CINXE.COM
Synteny between chromosome
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Synteny between chromosome</title> <meta name="description" content="Select a chromosome pair for a synteny dot plot."> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="keywords" content="orthology,evolutionary gene relations,evolution,paralogy,inference"> <!-- Matomo --> <script> var _paq = window._paq = window._paq || []; /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setCookieDomain", "*.omabrowser.org"]); _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="https://matomo.sib.swiss/"; _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '6']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script> <noscript><p><img src="https://matomo.sib.swiss/matomo.php?idsite=6&rec=1" style="border:0;" alt="" /></p></noscript> <!-- End Matomo Code --> <link rel="shortcut icon" href="/static/image/favicon.ico" type="image/x-icon"> <!-- css includes --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Dosis:400,800%7CNoto+Sans:400,700%7CRopa+Sans%7CMaterial+Icons"> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE=" crossorigin="anonymous"> <link rel="stylesheet" href="/static/css/oma_styles.css"> <link type="text/css" rel="stylesheet" href="/static/css/typeaheadjs.css"/> <!-- js includes --> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js" integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=" crossorigin="anonymous"></script> <script>const static_root = "/static/";</script> <!-- AA: not sure which of those libs will still be needed. I suspect autocomplete.min.js for sure, rest probably not --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.11.2/css/all.css"> <script src="/static/js/jquery.autocomplete.min.js"></script> <script id="release_char-data" type="application/json">"E"</script> <script src="/static/js/typeahead.bundle.js"></script> <style> .x-axis, .y-axis { font-size: 8px; text-align: left; } .axis-title { font-size: 18px; text-align: left; } div.tooltip { margin: 10px; min-width: 80px; background-color: #80CBC4; position: absolute; padding: 4px 8px; font: 12px sans-serif; background: lightsteelblue; border: 1px darkgrey solid; border-radius: 2px; pointer-events: none; color: white; } </style> </head> <body class=""> <nav class="navbar fixed-top navbar-expand-xl bg-light navbar-light topnav"> <div class="logos-navbar mr-auto"> <a href="https://www.sib.swiss/"><img src="/static/image/logo-SIB.png" alt="Logo SIB"/></a> <a href="/oma/home/"><img src="/static/image/logo-oma-mobile.svg" alt="Logo OMA small"/></a> </div> <span class="oma-main-search-header"> <script src="/static/js/vue.js"></script> <style> .button_search { cursor:pointer; align-self: center; height: 100%; background-color: transparent; border: none; margin-right: 4px; margin-left: auto; order: 2; } .button_search:disabled { cursor:not-allowed; } .help_icon { align-self: center; font-size: 1.5em; margin: 4px; cursor: pointer; } .prefix-dropdown { border: none; background-color: transparent; } .vl { border-left: 2px solid grey; margin-left: 4px; margin-right: 4px; } #search_nav_input_part { display: flex; border: 1px solid #eee; font-size: 0.9em; box-sizing: border-box; padding: 0 0 0 4px; border-radius: 500px; } .ml-input{} .sl-input{height: 50px;} .token-input__tag { height: 30px; display: inline-block; margin-right: 10px; background-color: #eee; margin-top: 10px; line-height: 30px; padding: 0 5px; border-radius: 5px; } .token-input__tag > span { cursor: pointer; opacity: 0.75; } .token-input__text { border: none; outline: none; font-size: 0.9em; line-height: 50px; flex-grow: 1; background: transparent; } .token-delete { margin-left: 4px; color: red; } #token-container_search_nav{ overflow: scroll; display: inline; } .ml-token-con{margin-bottom: 8px;} .sl-token-con{white-space: nowrap;} </style> <script type="module"> const {createApp} = Vue window.search_token_vue_search_nav = createApp({ data() { return { tokens: [], //{query: 'HUMAN', single_term: true, prefix: "Species", type: "Taxon"} prefixes: { 'Protein': ['proteinid','xref','go','ec','description','domain','sequence'], 'Taxon': ['species','taxid', 'taxon'], 'HOG': ['hog','sequence'], 'OMA_Group': ['og', 'fingerprint','sequence'], }, default_prefix : 'description', show_error: false, error_message : " Error.", post_query_search_nav: '', multiline: false, wild_card: 'sequence', placeholder: ' "Blue-light photoreceptor" | proteinid:P53_RAT | species:"Drosophila melanogaster" ', //'P53_RAT | Insulin | species:HUMAN | "auxin response factor"', placeholder_default: 'proteinid:P53_RAT | "Blue-light photoreceptor" | species:"Drosophila melanogaster" ' //'P53_RAT | Insulin | species:HUMAN | "auxin response factor"', } }, compilerOptions: { delimiters: ["$[", "]$"] }, methods: { get_list_prefixes(lowercase=false){ let lp = [].concat(...Object.values(this.prefixes)); if (lowercase){ lp = lp.map(element => {return element.toLowerCase();}); } return lp }, get_prefix_used(){ return this.tokens.map(x => this.get_type_prefix(x.prefix)); }, get_type_prefix(prefix){ for (var key in this.prefixes) { if (this.prefixes.hasOwnProperty(key)) { if (this.prefixes[key].includes(prefix.toLowerCase())){ return key } } } return null }, addToken(event) { event.preventDefault() let val = event.target.value.trim(); if (val.length === 0 && this.tokens.length > 0){ this.collect_token() // wanted to auto search if press and empty + token but post request miss post_query data } else { var sinle_term = val[0] !== '"'; var multi_term_closed = (val.length > 1 && val[val.length - 1] === '"') var has_prefix = val.includes(':') var prefix_end = val[val.length - 1] === ':' var p = has_prefix ? val.split(':')[0].toLowerCase() : this.default_prefix; // If prefix but not valid if (has_prefix && !this.get_list_prefixes(true).includes(p.toLowerCase())) { this.show_error = true; this.error_message = "Error: Incorrect prefix." return; } else { this.show_error = false; } // If something typed if (val.length > 0) { // Multiple word query if (!sinle_term) { // STOP if multiple not closed if (!multi_term_closed) { if (event.code === "Space") { event.target.value = val + ' ' } return } } // STOP if the prefix is fine and we are at : if (prefix_end) { return } // has a prefix if (has_prefix) { var tmp = val.split(':')[1].trim() sinle_term = tmp[0] !== '"'; multi_term_closed = (val.length > 1 && tmp[tmp.length - 1] === '"') // multiple term if (!sinle_term) { // STOP if not closed if (!multi_term_closed) { if (event.code === "Space") { event.target.value = val + ' ' } return } } val = tmp } if (this.validate_token(val.replaceAll('"', ''), sinle_term, p)) { val = val.replaceAll('"', '') this.tokens.push({ query: val, single_term: sinle_term, prefix: p, type: this.get_type_prefix(p) }); event.target.value = ''; } } } document.getElementById("token-container_search_nav").scrollLeft += 200000; }, addToken_and_search(event){ this.addToken(event); if (this.tokens.length > 0){ this.collect_token() this.$refs.submit_button.click(); } }, removeToken(index) { this.tokens.splice(index, 1) }, removeLastToken(event) { if (event.target.value.length === 0) { this.removeToken(this.tokens.length - 1) } }, enter_from_input(event) { if (event.target.value.trim().length > 0) {this.addToken(event)} else{ event.target.nextElementSibling.focus().click() } }, collect_token(){ this.post_query_search_nav = JSON.stringify(this.tokens) }, detokenize(index){ var token = this.tokens.splice(index, 1)[0]; var input_token_search = document.getElementById('input_token_search_search_nav'); var token_str = token.prefix + ': ' token_str += token.single_term ? '' : '"' token_str += token.query token_str += token.single_term ? '' : '"' input_token_search.value = token_str }, on_change_prefix(target, t){ var prefix = target.value if (this.validate_token(t.query, t.single_term,prefix, true)){ t.prefix = prefix.toLowerCase() } else { target.value = t.prefix; } }, validate_token(val, sinle_term, p , OnChange=false){ if (this.wild_card.includes(p)){ return true } // todo Validate type val is valid for p // validate prefix not in conflict with other prefix var pu = this.get_prefix_used(); var current_prefix_type = this.get_type_prefix(p) if (current_prefix_type !== 'Taxon'){ var no_taxon = pu.filter(x => x !== 'Taxon'); if (no_taxon.length == 0){return true} else if (OnChange && no_taxon.length == 1){return true} else if (no_taxon.length > 0 && no_taxon.includes(current_prefix_type) ){return true} else if (no_taxon.length > 0 && !no_taxon.includes(current_prefix_type)) { this.show_error = true; this.error_message = "Warning: You are searching for " + no_taxon[0] + "; you can't add a token for " + current_prefix_type return false } } return true }, preload_token(tokens){ this.tokens = [] for (var i in tokens) { var token = tokens[i] if (this.validate_token(token.query, token.sinle_term, token.prefix )){ this.tokens.push({query: token.query, single_term: token.sinle_term, prefix: token.prefix, type:token.type}); } } this.placeholder = ''; this.$refs.input_handle.focus(); }, is_empty(){return this.tokens.length === 0}, modal_clicked(){ $('#exampleModal_search_nav').modal('show') }, format_token_string(str){ if (str.length < 20){return str} return str.slice(0, 20) + '...' } }, }).mount('#search_nav') var autocomplete_opts = { paramName: 'search', serviceUrl: '/api/xref/', minChars: 3, triggerSelectOnValidInput: false, deferRequestBy: 200, transformResult: function (response) { var json = JSON.parse(response); var xref_source_order = ['UniProtKB/SwissProt', 'UniProtKB/TrEMBL', 'Ensembl Protein', 'Ensembl Gene', 'Ensembl Transcript', 'RefSeq', 'EntrezGene', 'FlyBase', 'WormBase', 'EnsemblGenomes', 'NCBI', 'EMBL', 'SourceID', 'SourceAC', 'HGNC', 'Gene Name', 'Synonym', 'Protein Name', 'ORF Name', 'Ordered Locus Name', 'PDB', 'Swiss Model', 'STRING', 'neXtProt', 'Bgee', 'EPD', 'ChEMBL', 'GlyConnect', 'SwissPalm', 'DisGeNET', 'WikiGene', 'IPI', 'GI', 'n/a']; json.sort(function (a, b){ const idx_a = xref_source_order.indexOf(a.source), idx_b = xref_source_order.indexOf(b.source); if (idx_a === idx_b){ return a.xref > b.xref ? 1 : -1; } return idx_a - idx_b; }); return { suggestions: $.map(json, function (dataItem) { return {value: dataItem.xref, data: dataItem}; }) }; }, groupBy: 'source', formatResult: function(suggestion, currentValue) { // Do not replace anything if there current value is empty if (!currentValue) { return suggestion.value; } // escape any special char var pattern = '(' + currentValue.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&") + ')'; var highlight_and_escape = function(val){ return val.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>') .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/<(\/?strong)>/g, '<$1>'); }; return '<span class="auto-xref">' + highlight_and_escape(suggestion.data.xref) + '</span> ' + '<span class="auto-omaid">' + suggestion.data.omaid + '</span>' + '<span class="auto-species">' + highlight_and_escape(suggestion.data.genome.species) + '</span>'; }, onSelect: function(item){ window.location.href = "/oma/vps/" + item.data.entry_nr; return false; }, response: function( event, ui ) {console.log('HOG')} }; $('#input_token_search_search_nav').autocomplete(autocomplete_opts); </script> <!-- Modal --> <div class="modal fade" data-backdrop="false" id="exampleModal_search_nav" tabindex="-1" aria-labelledby="exampleModalLabelsearch_nav" aria-hidden="true"> <div class="modal-dialog modal-lg modal-dialog-centered" > <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title" id="exampleModalLabelsearch_nav">How to use the search in OMA Browser ?</h4> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body" style="text-align: justify"> <strong>How does the search work?</strong> <p>Input a query in the search field. Everytime you press Space or Enter after a word, a <b>token</b> will be created. The token is composed of a <b>prefix</b> describing how the query should be treated and the actual <b>query</b> itself.</p> <strong>What are the different types of tokens?</strong> <p>Each token represents either a Gene, HOG, OMA group, or Taxon. Prefixes are used to specify which category to associate with the query term. </p> <table class="table table-bordered"> <thead> <tr> <th scope="col">Category</th> <th scope="col">Prefixes</th> </tr> </thead> <tbody> <tr> <th scope="row">Genes</th> <td>id, go, ec, description, domain, sequence</td> </tr> <tr> <th scope="row">HOGs</th> <td>hog, sequence</td> </tr> <tr> <th scope="row">OMA Groups</th> <td>omagroup, fingerprint, sequence</td> </tr> <tr> <th scope="row">Taxon</th> <td>species, taxid, taxon</td> </tr> </tbody> </table> <small>For example, the token [go:4225] will search for genes in the OMA database annotated with the GO:0004225 gene ontology term. </small> <br> <strong>How to search for a multi-word query?</strong> <p>If your query term is composed of multiple words (e.g homo sapiens), use " " to encapsulate it. </p> <strong>How many tokens can I have?</strong> <p>There is no limit on the number of tokens. It is not possible to enter multiple tokens of different categories, except taxon, which can be combined with other categories. For example, you can search for 'hog:60627 species:HUMAN' to return human genes found in HOG:606207. </p> <strong>How to edit/delete a token?</strong> <p>To edit a query, click on it to modify the input field. To edit a prefix, click on the dropdown icon to select another one. To remove a token, click on the x to delete it.</p> <strong>Autosuggest</strong> <p>Typing a query without hitting enter or space will prompt an autosuggestion for the identifier after a few seconds.</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> </div> </div> </div> </div> <form method="POST" id='form_' action="/oma/search-token/" > <input type="hidden" name="csrfmiddlewaretoken" value="09ZqpkCZssAp4vgNO3eDQbxh587iTKgvDGw9k0Vfd1xb9UgVGCqxZoQ5IYvh6iSj"> <div id="search_nav"> <div id="search_nav_input_part" :class="multiline ? 'ml-input' : 'sl-input'"> <span class="material-symbols-outlined help_icon" @click="modal_clicked"> help </span> <div id="token-container_search_nav" :class="multiline ? 'ml-token-con' : 'sl-token-con'" > <span v-for="token, index in tokens" :key="token" class="token-input__tag"> <select class="prefix-dropdown" @change="on_change_prefix($event.target, token)"> <template v-for="(prefixes_list, prefix_type) in prefixes"> <optgroup :label="prefix_type" > <option v-for="prefix in prefixes_list" :key="prefix" :selected="prefix == token.prefix"> $[ prefix ]$ </option> </optgroup> </template> </select> <span class="vl"></span> <p style="display: inline" @click='detokenize(index)'> $[ format_token_string(token.query) ]$ </p> <span @click='removeToken(index)' class="token-delete">X</span> </select> </span> </div> <input type="hidden" name="hidden_query" :value="post_query_search_nav"> <input type='text' :placeholder='placeholder' ref="input_handle" class='token-input__text' id="input_token_search_search_nav" @keydown.enter='enter_from_input' @keydown.space='addToken' @keydown.delete='removeLastToken' /> <button class=" button_search float-right" id="button_submit" ref="submit_button" :disabled="is_empty()" @click='collect_token()' type="submit"> <img style='width: 24px;' src="/static/image/logo-oma-o.svg" alt="Logo OMA icon"/> </button> </div> <div style="display: flex" v-show="show_error"> <small style="color: red; margin-right: auto;" > $[this.error_message]$ </small> </div> </div> </form> </span> <button type="button" class="navbar-toggler ml-auto collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span></span> <span></span> <span></span> </button> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <div class="navbar-nav ml-auto"> <div class="search"> <h3>Search</h3> <script src="/static/js/vue.js"></script> <style> .button_search { cursor:pointer; align-self: center; height: 100%; background-color: transparent; border: none; margin-right: 4px; margin-left: auto; order: 2; } .button_search:disabled { cursor:not-allowed; } .help_icon { align-self: center; font-size: 1.5em; margin: 4px; cursor: pointer; } .prefix-dropdown { border: none; background-color: transparent; } .vl { border-left: 2px solid grey; margin-left: 4px; margin-right: 4px; } #search_min_input_part { display: flex; border: 1px solid #eee; font-size: 0.9em; box-sizing: border-box; padding: 0 0 0 4px; border-radius: 500px; } .ml-input{} .sl-input{height: 50px;} .token-input__tag { height: 30px; display: inline-block; margin-right: 10px; background-color: #eee; margin-top: 10px; line-height: 30px; padding: 0 5px; border-radius: 5px; } .token-input__tag > span { cursor: pointer; opacity: 0.75; } .token-input__text { border: none; outline: none; font-size: 0.9em; line-height: 50px; flex-grow: 1; background: transparent; } .token-delete { margin-left: 4px; color: red; } #token-container_search_min{ overflow: scroll; display: inline; } .ml-token-con{margin-bottom: 8px;} .sl-token-con{white-space: nowrap;} </style> <script type="module"> const {createApp} = Vue window.search_token_vue_search_min = createApp({ data() { return { tokens: [], //{query: 'HUMAN', single_term: true, prefix: "Species", type: "Taxon"} prefixes: { 'Protein': ['proteinid','xref','go','ec','description','domain','sequence'], 'Taxon': ['species','taxid', 'taxon'], 'HOG': ['hog','sequence'], 'OMA_Group': ['og', 'fingerprint','sequence'], }, default_prefix : 'description', show_error: false, error_message : " Error.", post_query_search_min: '', multiline: false, wild_card: 'sequence', placeholder: ' "Blue-light photoreceptor" | proteinid:P53_RAT | species:"Drosophila melanogaster" ', //'P53_RAT | Insulin | species:HUMAN | "auxin response factor"', placeholder_default: 'proteinid:P53_RAT | "Blue-light photoreceptor" | species:"Drosophila melanogaster" ' //'P53_RAT | Insulin | species:HUMAN | "auxin response factor"', } }, compilerOptions: { delimiters: ["$[", "]$"] }, methods: { get_list_prefixes(lowercase=false){ let lp = [].concat(...Object.values(this.prefixes)); if (lowercase){ lp = lp.map(element => {return element.toLowerCase();}); } return lp }, get_prefix_used(){ return this.tokens.map(x => this.get_type_prefix(x.prefix)); }, get_type_prefix(prefix){ for (var key in this.prefixes) { if (this.prefixes.hasOwnProperty(key)) { if (this.prefixes[key].includes(prefix.toLowerCase())){ return key } } } return null }, addToken(event) { event.preventDefault() let val = event.target.value.trim(); if (val.length === 0 && this.tokens.length > 0){ this.collect_token() // wanted to auto search if press and empty + token but post request miss post_query data } else { var sinle_term = val[0] !== '"'; var multi_term_closed = (val.length > 1 && val[val.length - 1] === '"') var has_prefix = val.includes(':') var prefix_end = val[val.length - 1] === ':' var p = has_prefix ? val.split(':')[0].toLowerCase() : this.default_prefix; // If prefix but not valid if (has_prefix && !this.get_list_prefixes(true).includes(p.toLowerCase())) { this.show_error = true; this.error_message = "Error: Incorrect prefix." return; } else { this.show_error = false; } // If something typed if (val.length > 0) { // Multiple word query if (!sinle_term) { // STOP if multiple not closed if (!multi_term_closed) { if (event.code === "Space") { event.target.value = val + ' ' } return } } // STOP if the prefix is fine and we are at : if (prefix_end) { return } // has a prefix if (has_prefix) { var tmp = val.split(':')[1].trim() sinle_term = tmp[0] !== '"'; multi_term_closed = (val.length > 1 && tmp[tmp.length - 1] === '"') // multiple term if (!sinle_term) { // STOP if not closed if (!multi_term_closed) { if (event.code === "Space") { event.target.value = val + ' ' } return } } val = tmp } if (this.validate_token(val.replaceAll('"', ''), sinle_term, p)) { val = val.replaceAll('"', '') this.tokens.push({ query: val, single_term: sinle_term, prefix: p, type: this.get_type_prefix(p) }); event.target.value = ''; } } } document.getElementById("token-container_search_nav").scrollLeft += 200000; }, addToken_and_search(event){ this.addToken(event); if (this.tokens.length > 0){ this.collect_token() this.$refs.submit_button.click(); } }, removeToken(index) { this.tokens.splice(index, 1) }, removeLastToken(event) { if (event.target.value.length === 0) { this.removeToken(this.tokens.length - 1) } }, enter_from_input(event) { if (event.target.value.trim().length > 0) {this.addToken(event)} else{ event.target.nextElementSibling.focus().click() } }, collect_token(){ this.post_query_search_min = JSON.stringify(this.tokens) }, detokenize(index){ var token = this.tokens.splice(index, 1)[0]; var input_token_search = document.getElementById('input_token_search_search_min'); var token_str = token.prefix + ': ' token_str += token.single_term ? '' : '"' token_str += token.query token_str += token.single_term ? '' : '"' input_token_search.value = token_str }, on_change_prefix(target, t){ var prefix = target.value if (this.validate_token(t.query, t.single_term,prefix, true)){ t.prefix = prefix.toLowerCase() } else { target.value = t.prefix; } }, validate_token(val, sinle_term, p , OnChange=false){ if (this.wild_card.includes(p)){ return true } // todo Validate type val is valid for p // validate prefix not in conflict with other prefix var pu = this.get_prefix_used(); var current_prefix_type = this.get_type_prefix(p) if (current_prefix_type !== 'Taxon'){ var no_taxon = pu.filter(x => x !== 'Taxon'); if (no_taxon.length == 0){return true} else if (OnChange && no_taxon.length == 1){return true} else if (no_taxon.length > 0 && no_taxon.includes(current_prefix_type) ){return true} else if (no_taxon.length > 0 && !no_taxon.includes(current_prefix_type)) { this.show_error = true; this.error_message = "Warning: You are searching for " + no_taxon[0] + "; you can't add a token for " + current_prefix_type return false } } return true }, preload_token(tokens){ this.tokens = [] for (var i in tokens) { var token = tokens[i] if (this.validate_token(token.query, token.sinle_term, token.prefix )){ this.tokens.push({query: token.query, single_term: token.sinle_term, prefix: token.prefix, type:token.type}); } } this.placeholder = ''; this.$refs.input_handle.focus(); }, is_empty(){return this.tokens.length === 0}, modal_clicked(){ $('#exampleModal_search_min').modal('show') }, format_token_string(str){ if (str.length < 20){return str} return str.slice(0, 20) + '...' } }, }).mount('#search_min') var autocomplete_opts = { paramName: 'search', serviceUrl: '/api/xref/', minChars: 3, triggerSelectOnValidInput: false, deferRequestBy: 200, transformResult: function (response) { var json = JSON.parse(response); var xref_source_order = ['UniProtKB/SwissProt', 'UniProtKB/TrEMBL', 'Ensembl Protein', 'Ensembl Gene', 'Ensembl Transcript', 'RefSeq', 'EntrezGene', 'FlyBase', 'WormBase', 'EnsemblGenomes', 'NCBI', 'EMBL', 'SourceID', 'SourceAC', 'HGNC', 'Gene Name', 'Synonym', 'Protein Name', 'ORF Name', 'Ordered Locus Name', 'PDB', 'Swiss Model', 'STRING', 'neXtProt', 'Bgee', 'EPD', 'ChEMBL', 'GlyConnect', 'SwissPalm', 'DisGeNET', 'WikiGene', 'IPI', 'GI', 'n/a']; json.sort(function (a, b){ const idx_a = xref_source_order.indexOf(a.source), idx_b = xref_source_order.indexOf(b.source); if (idx_a === idx_b){ return a.xref > b.xref ? 1 : -1; } return idx_a - idx_b; }); return { suggestions: $.map(json, function (dataItem) { return {value: dataItem.xref, data: dataItem}; }) }; }, groupBy: 'source', formatResult: function(suggestion, currentValue) { // Do not replace anything if there current value is empty if (!currentValue) { return suggestion.value; } // escape any special char var pattern = '(' + currentValue.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&") + ')'; var highlight_and_escape = function(val){ return val.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>') .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/<(\/?strong)>/g, '<$1>'); }; return '<span class="auto-xref">' + highlight_and_escape(suggestion.data.xref) + '</span> ' + '<span class="auto-omaid">' + suggestion.data.omaid + '</span>' + '<span class="auto-species">' + highlight_and_escape(suggestion.data.genome.species) + '</span>'; }, onSelect: function(item){ window.location.href = "/oma/vps/" + item.data.entry_nr; return false; }, response: function( event, ui ) {console.log('HOG')} }; $('#input_token_search_search_min').autocomplete(autocomplete_opts); </script> <!-- Modal --> <div class="modal fade" data-backdrop="false" id="exampleModal_search_min" tabindex="-1" aria-labelledby="exampleModalLabelsearch_min" aria-hidden="true"> <div class="modal-dialog modal-lg modal-dialog-centered" > <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title" id="exampleModalLabelsearch_min">How to use the search in OMA Browser ?</h4> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body" style="text-align: justify"> <strong>How does the search work?</strong> <p>Input a query in the search field. Everytime you press Space or Enter after a word, a <b>token</b> will be created. The token is composed of a <b>prefix</b> describing how the query should be treated and the actual <b>query</b> itself.</p> <strong>What are the different types of tokens?</strong> <p>Each token represents either a Gene, HOG, OMA group, or Taxon. Prefixes are used to specify which category to associate with the query term. </p> <table class="table table-bordered"> <thead> <tr> <th scope="col">Category</th> <th scope="col">Prefixes</th> </tr> </thead> <tbody> <tr> <th scope="row">Genes</th> <td>id, go, ec, description, domain, sequence</td> </tr> <tr> <th scope="row">HOGs</th> <td>hog, sequence</td> </tr> <tr> <th scope="row">OMA Groups</th> <td>omagroup, fingerprint, sequence</td> </tr> <tr> <th scope="row">Taxon</th> <td>species, taxid, taxon</td> </tr> </tbody> </table> <small>For example, the token [go:4225] will search for genes in the OMA database annotated with the GO:0004225 gene ontology term. </small> <br> <strong>How to search for a multi-word query?</strong> <p>If your query term is composed of multiple words (e.g homo sapiens), use " " to encapsulate it. </p> <strong>How many tokens can I have?</strong> <p>There is no limit on the number of tokens. It is not possible to enter multiple tokens of different categories, except taxon, which can be combined with other categories. For example, you can search for 'hog:60627 species:HUMAN' to return human genes found in HOG:606207. </p> <strong>How to edit/delete a token?</strong> <p>To edit a query, click on it to modify the input field. To edit a prefix, click on the dropdown icon to select another one. To remove a token, click on the x to delete it.</p> <strong>Autosuggest</strong> <p>Typing a query without hitting enter or space will prompt an autosuggestion for the identifier after a few seconds.</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> </div> </div> </div> </div> <form method="POST" id='form_' action="/oma/search-token/" > <input type="hidden" name="csrfmiddlewaretoken" value="09ZqpkCZssAp4vgNO3eDQbxh587iTKgvDGw9k0Vfd1xb9UgVGCqxZoQ5IYvh6iSj"> <div id="search_min"> <div id="search_min_input_part" :class="multiline ? 'ml-input' : 'sl-input'"> <span class="material-symbols-outlined help_icon" @click="modal_clicked"> help </span> <div id="token-container_search_min" :class="multiline ? 'ml-token-con' : 'sl-token-con'" > <span v-for="token, index in tokens" :key="token" class="token-input__tag"> <select class="prefix-dropdown" @change="on_change_prefix($event.target, token)"> <template v-for="(prefixes_list, prefix_type) in prefixes"> <optgroup :label="prefix_type" > <option v-for="prefix in prefixes_list" :key="prefix" :selected="prefix == token.prefix"> $[ prefix ]$ </option> </optgroup> </template> </select> <span class="vl"></span> <p style="display: inline" @click='detokenize(index)'> $[ format_token_string(token.query) ]$ </p> <span @click='removeToken(index)' class="token-delete">X</span> </select> </span> </div> <input type="hidden" name="hidden_query" :value="post_query_search_min"> <input type='text' :placeholder='placeholder' ref="input_handle" class='token-input__text' id="input_token_search_search_min" @keydown.enter='enter_from_input' @keydown.space='addToken' @keydown.delete='removeLastToken' /> <button class=" button_search float-right" id="button_submit" ref="submit_button" :disabled="is_empty()" @click='collect_token()' type="submit"> <img style='width: 24px;' src="/static/image/logo-oma-o.svg" alt="Logo OMA icon"/> </button> </div> <div style="display: flex" v-show="show_error"> <small style="color: red; margin-right: auto;" > $[this.error_message]$ </small> </div> </div> </form> </div> <ul class="navbar-nav"> <!-- explore dropdown --> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle text-nowrap" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Explore <span class="caret"></span></a> <div class="dropdown-menu" role="menu"> <a class="dropdown-item" href="/oma/release/">Species/release information</a> <a class="dropdown-item" href="/oma/phylostratigraphy/">Phylostratigraphy</a> <div class="dropdown-divider"></div> <div role="presentation" class="dropdown-header">Quick access to</div> <a class="dropdown-item" href="/oma/genome/">Extant and Ancestral genomes</a> <a class="dropdown-item" href="/oma/landOMA/">OMA groups</a> <a class="dropdown-item" href="/oma/hogs/">Hierarchical orthologous groups (HOGs)</a> <a class="dropdown-item" href="/oma/landAnnotation/">Functional annotations</a> <a class="dropdown-item" href="/oma/synteny/">Local synteny</a> </div> </li> <!-- compute dropdown --> <li class="nav-item dropdown"> <a href="#" class="nav-link dropdown-toggle text-nowrap" data-toggle="dropdown">Tools <span class="caret"></span></a> <div class="dropdown-menu" role="menu"> <div role="presentation" class="dropdown-header">Online tools</div> <a class="dropdown-item" href="/oma/fastmapping/">Fast mapping</a> <a class="dropdown-item" href="/oma/functions/">Functional prediction</a> <a class="dropdown-item" href="/oma/dotplot/">Synteny dotplot</a> <a class="dropdown-item" href="/oma/genomePW/">Genome pair orthology</a> <a class="dropdown-item" href="/oma/go_enrichment/">GO enrichment analysis</a> <a class="dropdown-item" href="/oma/omamo/search/">OMA-MO: Find model organism</a> <a class="dropdown-item" href="https://omark.omabrowser.org">OMArk: Assess proteome quality</a> <div class="dropdown-divider"></div> <div role="presentation" class="dropdown-header">Software</div> <a class="dropdown-item" href="https://omabrowser.org/standalone/">OMA StandAlone</a> <a class="dropdown-item" href="https://github.com/dessimozlab/read2tree">read2tree</a> <a class="dropdown-item" href="https://github.com/dessimozlab/FastOMA">FastOMA</a> <a class="dropdown-item" href="https://github.com/dessimozlab/pyham">pyHam</a> <div class="dropdown-divider"></div> <div role="presentation" class="dropdown-header">Visualisation tools</div> <a class="dropdown-item" href="https://phylo.io/">Phylo.io</a> <a class="dropdown-item" href="https://github.com/dessimozlab/iham">IHam</a> <div class="dropdown-divider"></div> <a class="dropdown-item text-center" href="/oma/tools/"><b> <i class="fas fa-toolbox"></i> See all OMA tools</b></a> </div> </li> <!-- Download dropdown --> <li class="nav-item dropdown"> <a href="#" class="nav-link dropdown-toggle text-nowrap" data-toggle="dropdown">Download <span class="caret"></span></a> <ul class="dropdown-menu" role="menu"> <div role="presentation" class="dropdown-header">OMA database files</div> <a class="dropdown-item" href="/oma/current/">Current release</a> <a class="dropdown-item" href="/oma/export/">Export All/All</a> <a class="dropdown-item" href="/oma/export_markers">Export marker genes</a> <a class="dropdown-item" href="/oma/archives/">Archives</a> <div class="dropdown-divider"></div> <div role="presentation" class="dropdown-header">API</div> <a class="dropdown-item" href="/api/docs">OMA API</a> <a class="dropdown-item" href="/oma/APISOAP/">SOAP</a> <a class="dropdown-item" href="https://bioconductor.org/packages/release/bioc/html/OmaDB.html">R API binding</a> <a class="dropdown-item" href="https://github.com/DessimozLab/pyomadb">Python API binding</a> <div class="dropdown-divider"></div> <div role="presentation" class="dropdown-header">Semantic web</div> <a class="dropdown-item" href="https://sparql.omabrowser.org/">SPARQL endpoint</a> <div class="dropdown-divider"></div> <a class="dropdown-item text-center" href="/oma/uses/"><b> <i class="fas fa-keyboard"></i> Access the OMA data</b></a> </ul> </li> <!-- Help dropdown --> <li class="nav-item dropdown"> <a href="#" class="nav-link dropdown-toggle text-nowrap" data-toggle="dropdown">Help <span class="caret"></span></a> <ul class="dropdown-menu dropdown-menu-right" role="menu"> <a class="dropdown-item" href="/oma/about/">Introduction</a> <a class="dropdown-item" href="/oma/type/">Orthology Basics</a> <a class="dropdown-item" href="/oma/homologs/">Type of homologs</a> <a class="dropdown-item" href="/oma/uses/">Access the OMA data</a> <a class="dropdown-item" href="/oma/tools/">Catalog of tools</a> <a class="dropdown-item" href="/oma/suggestion/genome/">Suggesting a genome</a> <a class="dropdown-item" href="/oma/FAQ/">FAQ</a> <a class="dropdown-item" href="https://www.biostars.org/tag/oma/">Q&A on BioStars</a> <a class="dropdown-item " href="/oma/glossary/"> Glossary</a> <div class="dropdown-divider"></div> <a class="dropdown-item text-center" href="/oma/academy/"><b> <i class="fas fa-book"></i> OMA Academy</b></a> </ul> </li> <!-- about dropdown --> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle text-nowrap" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">About <span class="caret"></span></a> <div class="dropdown-menu dropdown-menu-right" role="menu"> <a class="dropdown-item" href="/oma/about/">OMA</a> <a class="dropdown-item" href="/oma/team/">Team</a> <a class="dropdown-item" href="/oma/sab/">SAB</a> <a class="dropdown-item" href="/oma/funding/">Funding</a> <a class="dropdown-item" href="/oma/terms_of_use/">Terms of use</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="mailto:contact@omabrowser.org"><span class="glyphicon glyphicon-envelope"></span> Contact</a> </div> </li> </ul> </div> </div> </nav> <div id="oma-generic-container"> <div class="container"> <div class="jumbotron"> <h1>Synteny Dot Plot <span> <small class="text-center text-muted h3 d-block">Visualise synteny between chromosomes </small></span></h1> <div class="oma-seperator"> <span class="colour1"></span> <span class="colour2"></span> <span class="colour3"></span> </div> <div class="card card-header-oma"> <div class="card-header"> <strong>Step 1: Select a pair of genomes </strong> </div> <div class="card-body "> <p class="text-justify">Use the following form to choose two genomes using their scientific name or 5 letter OMA species name. </p> <form id="form_GP"> <div class="form-group row"> <label for="g1_name" class="col-md-2 offset-md-1 control-label">Genome 1</label> <div class="col-sm-7"> <input id="g1_name" type="text" class="form-control typeahead" name="g1_name"> </div> </div> <div class="form-group row"> <label for="g2_name" class="col-md-2 offset-md-1 control-label">Genome 2</label> <div class="col-sm-7"> <input id="g2_name" type="text" class="form-control typeahead" name="g2_name"> </div> </div> </form> </div> </div> <br> <div class="card card-header-oma" id="step2"> <div class="card-header"> <strong>Step 2: Select a chromosome in each genome</strong> </div> <div class="card-body "> <div id="loader" class="alert alert-info text-center "> <img id="spinner" src="/static/image/loading.gif"> <span id="msg"></span> </div> <div id="message" class="row" style="padding: 0; display:none;"> <p class="text-justify">You have two ways to select the chromosome pair of interest: use the left matrix by clicking on the square of interest (double click directly open the synteny viewer) or use the select widget on the right to browse for each genome the chromosome to display. Once the chromosome pair is chosen, use the 'launch DotPlot' to start the visualisation.</p> <div class="col-xs-12 col-lg-6"> <div id="hm" style="width: 100%;"> </div> </div> <div class="col-xs-12 col-md-6"> <form id="form_DP"> <div class="form-row"> <div class="form-group col-md-12" id="fg_first_chr"> <label class="col-sm-12" for="selectchr1"></label> <select style="margin-left: 15px;" id="selectchr1"></select> </div> <div class="form-group col-md-12" id="fg_second_chr"> <label class="col-sm-12" for="selectchr2"></label> <select style="margin-left: 15px;" id="selectchr2"></select> </div> </div> <div id="dotPlotSubmit" class=""> <div > <button class="btn btn-lg btn-block btn-primary" type="submit" id="launch_PP">Launch DotPlot </button> </div> </div> </form> </div> </div> </div> </div> </div> </div> </div> </div> <script src="//d3js.org/d3.v4.js" type="text/javascript"></script> <script type="text/javascript"> (function ($) { var genome_1, genome_2, genomeFullName_1, genomeFullName_2 = ""; $("#loader, #message, #spinner, #dotPlotSubmit").hide(); $("#msg").html('Please choose both genomes first'); var oKeyDeferredMap = {}; function fnReadData(sKey) { var sValue = window.localStorage.getItem(sKey); return sValue ? JSON.parse(sValue) : sValue; } function fnWriteData(sKey, oData) { var sValue = JSON.stringify(oData); while(true) { try { window.localStorage.setItem(sKey, sValue); break; } catch (e) { localStorage.removeItem(localStorage.key(0)); continue; } } } $.cachedAjaxPromise = function (sUrl, oAjaxOptions) { var oDeferred = oKeyDeferredMap[sUrl]; var sValue; if (!oDeferred) { oDeferred = new jQuery.Deferred(); oKeyDeferredMap[sUrl] = oDeferred; sValue = fnReadData(sUrl); if (sValue) { oDeferred.resolve(sValue); } if (!oAjaxOptions) { oAjaxOptions = {}; } $.extend(oAjaxOptions, { error: function (oXHR, sTextStatus, sErrorThrown) { console.log('ajax request failed: ' + sErrorThrown); oDeferred.resolve(null); }, success: function (oData) { // making assumption that data is JSON fnWriteData(sUrl, oData); oDeferred.resolve(oData); } }); $.ajax(sUrl, oAjaxOptions); } return oDeferred.promise(); }; }(jQuery)); var genomeNames = []; var genomeIDs = {}; var genomeSpecies = {}; $.ajax({ url: "/All/flatgenomes.json", method: "GET", dataType: 'json', success: function (jsonData) { $.each(jsonData, function (id, genome) { var tmp = genome.name + ' (' + genome.id + ')'; genomeNames.push(tmp); genomeIDs[tmp] = genome.id; genomeSpecies[tmp] = genome.name; }) }, statusCode: { 404: function () { } }, error: function () { $.getJSON("/api/genome/?per_page=5000", function (jsonData) { jsonData.forEach(function (genome) { var tmp = genome.species + " (" + genome.code + ")"; genomeNames.push(tmp); genomeIDs[tmp] = genome.code; genomeSpecies[tmp] = genome.name; }) }) } }); function changeMessage(msg, showSpinner) { if (msg == "") { $("#loader, #message, #spinner").hide(); $("#msg").html(''); } else { if (showSpinner) { $("#spinner").show(); } else { $("#spinner").hide(); } $("#msg").html(msg); $("#loader, #message").show(); } } changeMessage('Please choose both genomes first', false); $("#message").hide(); function remove_chromosome_select(id_select) { var select = document.getElementById(id_select); var i; for (i = select.options.length - 1; i >= 0; i--) { select.remove(i); } var el = document.createElement("option"); el.textContent = 'Choose a chromosome'; el.value = 'Choose a chromosome'; select.appendChild(el); } function set_chromosome_select(id_select, data) { var select = document.getElementById(id_select); select.innerHTML = ""; $.each(data, function (index) { var el = document.createElement("option"); el.textContent = this.id; el.value = this.id; select.appendChild(el); }); } function isInt(value) { if (isNaN(value)) { return false; } var x = parseFloat(value); return (x | 0) === x; } function filterChromosomesByCount(data, filterCount) { var MIN_NR_PROTEINS_PER_CHR; if (isInt(filterCount)) { MIN_NR_PROTEINS_PER_CHR = filterCount; } else { MIN_NR_PROTEINS_PER_CHR = 10; } var tmpData = []; $.each(data, function (index, arr) { var nr_prot_on_chr = arr.entry_ranges.reduce(function (acc, cur) { return acc + cur[1] - cur[0] + 1 }, 0); if (nr_prot_on_chr >= MIN_NR_PROTEINS_PER_CHR) { // skip scaffolds with only very few proteins //console.log('adding ' +arr.id + " at index "+ index); //data.splice(index, 1); arr.count = nr_prot_on_chr; tmpData.push(arr); } }); if (tmpData.length > 5) { tmpData = tmpData.sort(comparatorNrProteins); function comparatorNrProteins(a, b) { return b.count - a.count; } } return tmpData; } var substringMatcher = function (strs) { return function findMatches(q, cb) { var matches, substrRegex; // an array that will be populated with substring matches matches = []; if (q.length < 2) { return (cb(matches)); } // regex used to determine if a string contains the substring `q` substrRegex = new RegExp(q, 'i'); // iterate through the pool of strings and for any string that // contains the substring `q`, add it to the `matches` array $.each(strs, function (i, str) { if (substrRegex.test(str)) { // the typeahead jQuery plugin expects suggestions to a // JavaScript object, refer to typeahead docs for more info matches.push({value: str}); } }); cb(matches); }; }; function update_chromosome_select(input) { if (genomeIDs[input.val()] === null || genomeIDs[input.val()] === undefined) { input.val(''); return false; } input.trigger("input"); }; $('#g1_name').typeahead({ hint: true }, { name: 'genomes', minLength: 4, source: substringMatcher(genomeNames) }) //.on('typeahead:selected', change()); //.on('blur', function(){update_chromosome_select($(this))}) .on('typeahead:selected', function (ev, suggestion) { update_chromosome_select($(this)); }); $('#g2_name').typeahead({ hint: true }, { name: 'genomes', minLength: 4, source: substringMatcher(genomeNames) }) //.on('blur', function(){update_chromosome_select($(this))}) .on('typeahead:selected', function () { update_chromosome_select($(this)); }); function getLongestId(data) { return data.reduce(function (maxLen, val) { return val.id.length > maxLen ? val.id.length : maxLen }, 0); } $(window).keydown(function (event) { if (event.keyCode == 13) { event.preventDefault(); return false; } }); $('#g1_name, #g2_name').bind("input propertychange", function (event) { // If it's the propertychange event, make sure it's the value that changed. if (window.event && event.type == "propertychange" && event.propertyName != "value") { return false; } if ($('#g1_name').val() == "" || $('#g2_name').val() == "" || $('#g2_name').val().length < 5 || $('#g2_name').val().length < 5) { return false; } genome_1 = genomeIDs[$('#g1_name').val()]; genome_2 = genomeIDs[$('#g2_name').val()]; genomeFullName_1 = genomeSpecies[$('#g1_name').val()]; genomeFullName_2 = genomeSpecies[$('#g2_name').val()]; if (genome_1 === undefined || genome_2 === undefined) { return false; } // Clear any previously set timer before setting a fresh one window.clearTimeout($(this).data("timeout")); $(this).data("timeout", setTimeout(function () { var clickTimeout = null; //stop form submission event.preventDefault(); changeMessage("Loading genome data...", true); var server = ""; //"http://omabrowser.org"; $.ajaxSetup({timeout: 7000}); var get1 = $.getJSON(server + '/api/genome/' + genome_1 + '/?format=json'); var get2 = $.getJSON(server + '/api/genome/' + genome_2 + '/?format=json'); $.when(get1, get2).done(function (res1, res2) { var chrom1 = filterChromosomesByCount(res1[0].chromosomes, 10); var chrom2 = filterChromosomesByCount(res2[0].chromosomes, 10); if (chrom1.length > chrom2.length) { chromosomes1 = chrom2.slice(0, 50); chromosomes2 = chrom1.slice(0, 50); // change naming so genome with more chromosomes is shown in rows instead of columns var genome_1tmp = genome_1; genome_1 = genome_2; genome_2 = genome_1tmp; var genomeFullName_tmp = genomeFullName_1; genomeFullName_1 = genomeFullName_2; genomeFullName_2 = genomeFullName_tmp; } else { chromosomes1 = chrom1.slice(0, 50); chromosomes2 = chrom2.slice(0, 50); } $("#fg_first_chr > label").html("Chromosome for " + genome_1); $("#fg_second_chr > label").html("Chromosome for " + genome_2); changeMessage("Sorting genome data...", true); chromosomes1 = chromosomes1.sort(comparatorGenomeName); chromosomes2 = chromosomes2.sort(comparatorGenomeName); function comparatorGenomeName(a, b) { return a.id.localeCompare(b.id, undefined, { numeric: true, sensitivity: 'base' }); } set_chromosome_select('selectchr1', chromosomes1) set_chromosome_select('selectchr2', chromosomes2) function matrix(rows, cols, defaultValue) { var arr = []; for (var i = 0; i < rows; i++) { arr.push([]); // Adds cols to the empty row arr[i].push(new Array(cols)); for (var j = 0; j < cols; j++) { // Initializes: arr[i][j] = defaultValue; } } return arr; } function inRange(val, entries) { this.value = val; this.found = false; entries.forEach(function (entry) { if (this.value >= entry[0] && this.value <= entry[1]) { this.found = true; } }, this); return this.found; } changeMessage("Loading pairs...", true); d3.json(server + "/api/pairs/" + genome_1 + "/" + genome_2 + "/minimal/?format=json", function (pairdata) { var pairs = pairdata.pairs.slice(0); var count = pairs.length; var cols = chromosomes1.length; var rows = chromosomes2.length; var colLblLen = getLongestId(chromosomes1) * 8 + 12; var rowLblLen = getLongestId(chromosomes2) * 6 + 16; var data = matrix(rows, cols, 0) changeMessage("Matching pairs...", true); for (var i = 0; i < count; i++) { var pair0 = pairs[i][0]; var pair1 = pairs[i][1]; for (var col = 0; col < cols; col++) { if (inRange(pair0, chromosomes1[col].entry_ranges)) { for (var row = 0; row < rows; row++) { if (inRange(pair1, chromosomes2[row].entry_ranges)) { data[row][col] += 1; break; } } } } } changeMessage("Use the matrix or select boxes to choose the pair of chromosome to visualise", false); $("#fg_first_chr").removeClass('hidden'); $("#fg_second_chr").removeClass('hidden'); $("#dotPlotSubmit").show(); // TODO: cleanup var fullWidth = $('#hm').width(); var margin = {top: 25 + colLblLen, right: 30, bottom: 0, left: 15 + rowLblLen}, width = (fullWidth / cols) > 30 ? (cols * 30) : fullWidth; matrixWidth = (width - rowLblLen) < 30 ? width : (width - rowLblLen); height = matrixWidth / cols * rows; matrixHeight = height - colLblLen; var x = d3.scaleLinear() .domain([0, data[0].length]) .range([0, matrixWidth]); var y = d3.scaleLinear() .domain([0, data.length]) .range([0, matrixHeight]); values = [].concat.apply([], data); var colorDomain = d3.extent(values, function (d) { return d; }); var colorScale = d3.scaleLinear() .domain(colorDomain) .range(["white", "green"]); d3.select("#heatmap").remove(); var svg = d3.select("#hm").append("svg") .attr("id", "heatmap") //.attr("width", width + margin.left + margin.right) .attr("width", fullWidth) .attr("height", height + margin.top + margin.bottom) .style("margin-top", "10px") .append("g") .attr("transform", "translate(" + (margin.left + 20) + "," + (margin.top + 20) + ")"); var div = d3.select("body") .append("div") .attr("class", "tooltip") .style("opacity", 0); var row = svg.selectAll(".row") .data(data, function (d, i) { return i; }) .enter().append("svg:g") .attr("class", "row"); var col = row.selectAll(".cell") .data(function (d, i) { return d.map(function (a) { return {value: a, row: i}; }) }) .enter() .append("svg:rect") .attr("class", "cell") .attr("x", function (d, i) { return x(i); }) .attr("y", function (d) { return y(d.row); }) .attr("width", x(1)) .attr("height", y(1)) .style("fill", function (d) { return colorScale(d.value); }) .on("click", function (d, i) { if (clickTimeout != null) { clearTimeout(clickTimeout); } clickTimeout = setTimeout(function () { $("#selectchr1").val(chromosomes1[i].id); $("#selectchr2").val(chromosomes2[d.row].id); }, 300) }) .on("dblclick", function (d, i) { if (clickTimeout != null) { clearTimeout(clickTimeout); } window.location = server + "/oma/dotplot/" + genome_1 + "/" + genome_2 + "/" + chromosomes1[i].id + "/" + chromosomes2[d.row].id; }) .on("mouseover", function (d, i) { // normalize to browser coordinates var my = d3.event.pageY - window.scrollY; var mx = d3.event.pageX - window.scrollX; // move tooltip into viewport if cell is too close to the viewport edge var xPos = (mx > ($(window).width() - 140)) ? d3.event.pageX - 150 : d3.event.pageX + 15; var yPos = (my > ($(window).height() - 60)) ? d3.event.pageY - 55 : d3.event.pageY + 15; var ttText = "Chromosome: " + chromosomes1[i].id + ":" + chromosomes2[d.row].id; ttText += "<br>Nb. orthologs: " + d.value; div.transition() .duration(50) .style("opacity", .9); div.html(ttText) .style("left", xPos + "px") .style("top", yPos + "px"); }) .on("mouseout", function (d) { div.transition() .duration(100) .style("opacity", 0); }) // Axes var xAxisCall = d3.axisTop(x).ticks(cols).tickFormat(function (d) { if (chromosomes1[d] && typeof chromosomes1[d].id !== 'undefined') { return chromosomes1[d].id; } }); var xAxis = svg.append("g") .attr("class", "x-axis") .attr("transform", "translate(" + 0 + "," + 0 + ")") .call(xAxisCall) .style("text-anchor", "start") .call(adjustTextLabelsX) .append("g") .attr("fill", "green") .attr("id", "x-axislbl"); xAxis .append("text") .attr("class", "axis-title") .attr("y", 10 - margin.top) .style("text-anchor", "start") .attr("dx", "0") .text(genome_1); xAxis .append("text") .attr("class", "axis-title") .attr("y", 10 - margin.top) .attr("dy", "1em") .style("font-size", "13px") .attr("dx", "0") .text(genomeFullName_1); var yAxisCall = d3.axisLeft(y).ticks(rows).tickFormat(function (d) { if (chromosomes2[d] && typeof chromosomes2[d].id !== 'undefined') { return chromosomes2[d].id; } }); var yAxis = svg .append("g") .attr("class", "y-axis") .call(yAxisCall) .call(adjustTextLabelsY) .append("g") .attr("transform", "rotate(-90)") .style("text-anchor", "end") .attr("fill", "green") .attr("id", "y-axislbl"); yAxis .append("text") .attr("class", "axis-title") .attr("y", function (d) { return 0 - (margin.left + 15); }) .attr("dy", "1em") .attr("dx", "0") .text(genome_2); yAxis .append("text") .attr("class", "axis-title") .attr("y", function (d) { return 0 - (margin.left + 20); }) .attr("dy", "2.5em") .attr("dx", "0") .style("font-size", "13px") .text(genomeFullName_2); function adjustTextLabelsX(selection) { selection.selectAll('.x-axis text') .attr('transform', function (d) { return 'translate(' + x(1) + ', -10) rotate(-90)' }); } function adjustTextLabelsY(selection) { selection.selectAll('.y-axis text') .attr('transform', function (d) { return 'translate(0, ' + y(1) / 2 + ')' }); } }); }).fail(function () { changeMessage("Sorry, could not load pair data.", false); ; }); }, 1000)); }); $("form").on('submit', function (e) { //stop form submission e.preventDefault(); var select1 = document.getElementById("selectchr1"); var chr1 = select1.options[select1.selectedIndex].value; if (chr1 === 'Choose a chromosome') { alert('Invalid chromosome 1.'); return false } var select2 = document.getElementById("selectchr2"); var chr2 = select2.options[select2.selectedIndex].value; if (chr2 === 'Choose a chromosome') { alert('Invalid chromosome 2.'); return false } if (genome_1 === genome_2 && chr1 === chr2) { alert("You cannot select twice the same chromosome and genome."); return false; } var newUrl = encodeURI("/oma/dotplot/" + genome_1 + "/" + genome_2 + "/" + chr1 + "/" + chr2); window.location = newUrl; return false; }); </script> </body> </html>