ideogram
Version:
Chromosome visualization for the web
315 lines (275 loc) • 10.5 kB
HTML
<html>
<head>
<title>Paralogs | Ideogram</title>
<style>
body {font: 14px Arial; line-height: 19.6px; padding: 0 15px;}
a, a:visited {text-decoration: none;}
a:hover {text-decoration: underline;}
a, a:hover, a:visited, a:active {color: #0366d6;}
select, optgroup, option {
float: left;
font-size: 14px;
}
#ideogram-container {z-index: -1}
#search-container {
height: 26px;
float: left;
position: relative;
top: -4px;
margin-left: 10px;
}
#search-genes {
padding-left: 3px;
width: 200px;
height: 20px;
font-size: 14px;
border-radius: 3px;
border: 1px solid #888;
}
#search-button {
height: 21px;
width: 23px;
font-size: 24px;
background: #58F;
color: #FFF;
display: inline-block;
position: relative;
top: 3px;
left: -25px;
border-radius: 3px;
text-align: center;
padding-top: 3px;
cursor: pointer;
}
#ideogram .annot path {
cursor: pointer;
}
#ideogram .chromosome {
cursor: default;
}
</style>
<script type="text/javascript" src="../../dist/js/ideogram.min.js"></script>
<link rel="icon" type="image/x-icon" href="img/ideogram_favicon.ico">
</head>
<body>
<h1>Paralogs | Ideogram</h1>
<a href="../">Overview</a> |
<a href="multiple-primates">Previous</a> |
<a href="mouse">Next</a> |
<a href="https://github.com/eweitz/ideogram/blob/gh-pages/paralogs.html" target="_blank">Source</a>
<p>
Find evolutionarily similar genes across the genome. See also <a href="orthologs">Orthologs</a>.
</p>
<div>
<select>
<optgroup label="Model organisms">
<option value="homo-sapiens" selected>Human (Homo sapiens)</option>
<option value="mus-musculus">Mouse (Mus musculus)</option>
<option value="rattus-norvegicus">Rat (Rattus norvegicus)</option>
<!-- <option value="drosophila-melanogaster">Fly (Drosophila melanogaster)</option> -->
<!-- <option value="caenorhabditis-elegans">Worm (Caenorhabditis elegans)</option> -->
<option value="danio-rerio">Zebrafish (Danio rerio)</option>
<!-- <option value="arabidopsis-thaliana">Thale cress (Arabidopsis thaliana)</option> -->
<!-- <option value="saccharomyces-cerevisiae">Yeast (Saccharomyces cerevisiae)</option> -->
</optgroup>
<optgroup label="Vertebrates">
<option value="pan-troglodytes">Chimpanzee (Pan troglodytes)</option>
<option value="macaca-mulatta">Macaque (Macaca mulatta)</option>
<option value="macaca-fascicularis">Crab-eating macaque (Macaca fascicularis)</option>
<option value="felis-catus">Cat (Felis catus)</option>
<option value="canis-lupus-familiaris">Dog (Canis lupus familiaris)</option>
<option value="equus-caballus">Horse (Horse)</option>
<option value="bos-taurus">Cow (Bos taurus)</option>
<option value="sus-scrofa">Pig (Sus scrofa)</option>
<!-- <option value="petromyzon-marinus">Lamprey (Petromyzon marinus)</option> -->
</optgroup>
<!-- <optgroup label="Plants">
<option value="zea-mays">Maize (Zea mays)</option>
<option value="oryza-sativa">Rice (Oryza sativa)</option>
<option value="solanum-lycopersicum">Tomato (Solanum lycopersicum)</option>
<option value="musa-acuminata">Banana (Musa acuminata)</option>
<option value="vitis-vinifera">Grape (Vitis vinifera)</option>
<option value="micromonas-commoda">Green algae (Micromonas commoda)</option>
</optgroup>
<optgroup label="Insects">
<option value="anopheles-gambiae">Mosquito (Anopheles gambiae)</option>
</optgroup>
<optgroup label="Protozoa">
<option value="plasmodium falciparum">Malaria parasite (Plasmodium falciparum)</option>
<option value="leishmania donovani">Leishmania parasite (Leishmania donovani)</option>
</optgroup> -->
</select>
</div>
<div style="float: left; width: 350px;">
<label for="search-genes" id="search-container">
<input id="search-genes" autocomplete="off" placeholder="Search genes (e.g. RAD51)"/>
<span id="search-button">⌕</span>
</label>
</div>
<br/><br/><br/>
<div id="ideogram-container"></div>
<script type="text/javascript">
function parseUrlParams() {
var rawParams = document.location.search;
var urlParams = {};
var param, key, value;
if (rawParams !== '') {
rawParams = rawParams.split('?')[1].split('&');
rawParams.forEach(rawParam => {
param = rawParam.split('=');
key = param[0];
value = param[1];
urlParams[key] = value;
});
}
return urlParams;
}
function handleOrganism() {
document.querySelector('#search-genes').value = '';
var selectedOrg = document.querySelector('option:checked').text;
selectedOrg = selectedOrg.split('(')[1].split(')')[0].toLowerCase();
config.organism = selectedOrg;
var banded = !['homo sapiens', 'mus musculus'].includes(selectedOrg);
config.showFullyBanded = banded;
ideogram = new Ideogram(config);
}
async function fetchEnsembl(path, body=null, method='GET') {
let init = {
method: method,
headers: {'Content-Type': 'application/json'}
}
if (body !== null) init.body = JSON.stringify(body);
const response = await fetch(`https://rest.ensembl.org${path}`, init);
const json = await response.json();
return json;
}
/**
* Fetch paralogs of searched gene
*/
async function fetchParalogPositions(annot, annots) {
const taxid = ideogram.config.taxid;
const orgUnderscored = ideogram.config.organism.replace(/[ -]/g, '_');
const params = `&format=condensed&type=paralogues&target_taxon=${taxid}`;
let path = `/homology/id/${annot.id}?${params}`
const ensemblHomologs = await fetchEnsembl(path);
const homologs = ensemblHomologs.data[0].homologies;
// Fetch positions of paralogs
homologIds = homologs.map(homolog => homolog.id)
path = '/lookup/id/' + orgUnderscored;
let body = {
'ids': homologIds,
'species': orgUnderscored,
'object_type': 'gene'
}
const ensemblHomologGenes = await fetchEnsembl(path, body, 'POST');
Object.entries(ensemblHomologGenes).map((idGene, i) => {
let gene = idGene[1]
annot = {
name: gene.display_name,
chr: gene.seq_region_name,
start: gene.start,
stop: gene.end,
id: gene.id,
shape: 'triangle',
color: 'pink',
height: 3
};
// Add to start of array, so searched gene gets top z-index
annots.unshift(annot);
annotDescriptions[annot.name] = gene.description;
})
return annots;
}
annotDescriptions = {}
async function searchGenes(geneSymbols) {
// Refine style
document.querySelectorAll('.chromosome').forEach(chromosome => {
chromosome.style.cursor = '';
})
const lastChr = [...document.querySelectorAll('.chromosome-set')].slice(-1)[0]
const left = lastChr.getBoundingClientRect().x;
const topPx = ideogram.config.chrHeight + 40;
const style =
`float: left; position: relative; top: -${topPx}px; left: ${left}px;`;
// Fetch positon of searched gene
const orgUnderscored = ideogram.config.organism.replace(/[ -]/g, '_');
let path = '/lookup/symbol/' + orgUnderscored;
let body = {'symbols': geneSymbols}
const ensemblGenes = await fetchEnsembl(path, body, 'POST');
let annots = []
geneSymbols.forEach(async geneSymbol => {
let gene = ensemblGenes[geneSymbol]
let annot = {
name: gene.display_name,
id: gene.id,
chr: gene.seq_region_name,
start: gene.start,
stop: gene.end,
shape: 'triangle',
color: 'red'
};
annots.push(annot);
annotDescriptions[annot.name] = gene.description;
annots = await fetchParalogPositions(annot, annots)
// More notable genes tend to have shorter names.
// This helps ensure such genes appear atop overlapping annotations.
annots.sort((a, b) => { return b.name.length - a.name.length })
ideogram.drawAnnots(annots);
document.querySelector('#_ideogramLegend').style = style;
});
ideogram.drawAnnots(annots);
document.querySelector('#_ideogramLegend').style = 'display: none;';
}
// Process text input for the "Search" field.
function handleSearch(event) {
// Ignore non-"Enter" keyups
if (event.type === 'keyup' && event.keyCode !== 13) return;
var searchInput = event.target.value.trim();
// Handles "BRCA1,BRCA2", "BRCA1 BRCA2", and "BRCA1, BRCA2"
let geneSymbols = searchInput.split(/[, ]/).filter(d => d !== '')
searchGenes(geneSymbols);
}
function onClickAnnot(annot) {
searchGenes([annot.name]);
}
var urlParams = parseUrlParams();
var organism = 'org' in urlParams ? urlParams.org : 'homo-sapiens';
document.querySelector('#search-button').addEventListener('click', handleSearch);
document.querySelector('#search-genes').addEventListener('keyup', handleSearch);
document.querySelector('select').addEventListener('change', handleOrganism);
const shape = 'triangle';
var legend = [{
name: 'Click paralog to search',
rows: [
{name: 'Paralog', color: 'pink', shape: shape},
{name: 'Searched gene', color: 'red', shape: shape}
]
}];
function decorateGene(annot) {
var org = ideogram.getScientificName(ideogram.config.taxid);
var term = `(${annot.name}[gene])+AND+(${org}[orgn])`;
var url = `https://ncbi.nlm.nih.gov/gene/?term=${term}`;
var description = annotDescriptions[annot.name].split(' [')[0];
annot.displayName =
`<a target="_blank" href="${url}">${annot.name}</a>
<br/>
${description}`;
return annot
}
config = {
organism: organism,
chrWidth: 8,
chrHeight: 90,
chrLabelSize: 10,
annotationHeight: 5,
showFullyBanded: false,
rotatable: false,
legend: legend,
onClickAnnot: onClickAnnot,
onWillShowAnnotTooltip: decorateGene
}
var ideogram = new Ideogram(config);
</script>
</body>
</html>