clustergrammer
Version:
This is a clustergram implemented in D3.js. I started from the example http://bost.ocks.org/mike/miserables/ and added the following features
689 lines (526 loc) • 18.9 kB
JavaScript
var genes_were_found = false;
function check_setup_enrichr(inst_cgm){
var all_rows = inst_cgm.params.network_data.row_nodes_names;
var max_num_genes = 20;
if (all_rows.length > 20){
all_rows = all_rows.slice(0,20);
}
var wait_unit = 500;
var wait_time = 0;
// check each gene using Harmonizome
_.each(all_rows, function(inst_name){
// check_gene_request(inst_cgm, inst_name, run_ini_enrichr);
setTimeout(check_gene_request, wait_time, inst_cgm, inst_name, run_ini_enrichr);
wait_time = wait_time + wait_unit;
});
}
function run_ini_enrichr(inst_cgm, inst_name){
if (genes_were_found){
if (d3.select('.enrichr_logo').empty()){
// set up Enrichr category import
enr_obj = Enrichr_request(inst_cgm);
enr_obj.enrichr_icon();
// set up Enrichr export in dendro modal
//////////////////////////////////////////
// only display for rows
var enrichr_section = d3.selectAll('.dendro_info')
.select('.modal-body')
.append('div')
.classed('enrichr_export_section', true)
.style('margin-top', '10px')
.style('display','none');
enrichr_section
.append('text')
.text('Send genes to ');
enrichr_section
.append('a')
.html('Enrichr')
.on('click', function(){
var group_string = d3.select('.dendro_text input').attr('value');
// replace all instances of commas with new line
var gene_list = group_string.replace(/, /g, '\n');
var enrichr_info = {list: gene_list, description: 'Clustergrammer gene-cluster list' , popup: true};
// defined globally - will improve
enrich(enrichr_info);
});
}
}
}
function check_gene_request(inst_cgm, gene_symbol, check_enrichr_callback){
var base_url = 'https://amp.pharm.mssm.edu/Harmonizome/api/1.0/gene/';
var url = base_url + gene_symbol;
if (genes_were_found === false){
$.get(url, function(data) {
data = JSON.parse(data);
if (data.name != undefined){
genes_were_found = true;
}
check_enrichr_callback(inst_cgm, gene_symbol);
});
}
}
function Enrichr_request(inst_cgm){
function enrichr_icon(){
var low_opacity = 0.7;
var high_opacity = 1.0;
var icon_size = 42;
var d3_tip_custom = inst_cgm.d3_tip_custom();
// var enrichr_description = 'Perform enrichment analysis on your gene-list <br>'+
// 'using Enrichr to find biological information that is unique to your list.'
var enrichr_description = 'Perform enrichment analysis, using Enrichr, to find biological <br>'+
'information specific to your set (or subset) of genes. <br><br>' +
'Select a subset of genes for analysis by cropping the matrix using: the brush-cropping tool in the sidebar, or the crop buttons on the dendrogram.'
// d3-tooltip
var enr_tip = d3_tip_custom()
.attr('class', function(){
var root_tip_selector = inst_cgm.params.viz.root_tips.replace('.','');
var class_string = root_tip_selector + '_enr_tip d3-tip';
return class_string;
})
.direction('se')
.offset([-10,-5])
.html(function(d){
return enrichr_description;
});
var enr_logo = d3.select('.viz_svg').append("svg:image")
.attr('x', 50)
.attr('y', 2)
.attr('width', icon_size)
.attr('height', icon_size)
.attr("xlink:href", "https://amp.pharm.mssm.edu/Enrichr/images/enrichr-icon.png")
.style('opacity', low_opacity)
.classed('enrichr_logo', true)
.attr('id', function(){
var inst_id = 'enrichr_menu_button_' + inst_cgm.params.root.replace('#','');
return inst_id;
})
.on('click', function(){
toggle_enrichr_menu();
})
.on('mouseover', function(){
var is_showing = d3.select(inst_cgm.params.root+' .enrichr_menu')
.classed('showing');
if (is_showing === false){
// show tooltip
d3.selectAll( inst_cgm.params.viz.root_tips + '_enr_tip')
.style('opacity', 1)
.style('display', 'block');
enr_tip.show();
}
})
.on('mouseout', function(){
// hide tooltip
d3.selectAll( inst_cgm.params.viz.root_tips + '_enr_tip')
.style('opacity', 0)
.style('display', 'block');
enr_tip.hide();
})
.call(enr_tip);
var enr_menu = d3.select(inst_cgm.params.root+' .viz_svg')
.append('g')
.classed('showing', false)
.classed('enrichr_menu', true)
.attr('transform', 'translate(85,40)')
.style('display', 'none');
enr_menu
.append('rect')
.classed('enr_menu_background', true)
.style('width', 500)
.style('height', 425)
.style('opacity', 0.95)
.style('fill', 'white')
.style('stroke', '#A3A3A3')
.style('stroke-width', '3px');
enr_menu
.append('text')
.attr('transform', 'translate(20,30)')
.attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
.style('font-size','18px')
.style('font-weight', 800)
.style('cursor', 'default')
.text('Choose Enrichr Library');
// clear results button
enr_menu
.append('text')
.classed('enr_menu_clear', true)
.attr('transform', 'translate(375, 30)')
.attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
.style('font-size','18px')
.style('font-weight', 800)
.style('cursor', 'default')
.text('Clear Results')
.style('fill', 'red')
.style('opacity', 0.75)
.style('display', 'none')
.on('click', function(){
// reset enrichr menu
toggle_enrichr_menu();
clear_enrichr_results();
})
var lib_section = enr_menu
.append('g')
.attr('transform', 'translate(20,60)')
.style('width', 460)
.style('height', 330)
.classed('enr_lib_section','true');
var possible_libraries = ['ChEA_2015','KEA_2015',
'ENCODE_TF_ChIP-seq_2015',
'ENCODE_Histone_Modifications_2015',
'Disease_Perturbations_from_GEO_up',
'Disease_Perturbations_from_GEO_down',
'GO_Molecular_Function_2015',
'GO_Biological_Process_2015',
'GO_Cellular_Component_2015',
'Reactome_2015',
'MGI_Mammalian_Phenotype_Level_4'
];
var vertical_space = 30;
enr_menu
.append('rect')
.classed('enr_menu_line', true)
.attr('height', '2px')
.attr('width', '460px')
.style('stroke-width', '3px')
.style('opacity', 0.3)
.style('fill','black')
.attr('transform', 'translate(20, 380)');
var enr_export_container = enr_menu
.append('g')
.classed('enr_export_container', true)
.attr('transform', 'translate(20, 410)');
enr_export_container
.append('text')
.style('font-size','16px')
.attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
.style('cursor', 'default')
.text('Export gene list to ');
enr_export_container
.append('text')
.style('font-size','16px')
.attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
.style('cursor', 'default')
.text('Enrichr')
.style('fill','#337ab7')
.attr('transform', 'translate(135, 0)')
.on('click', function(){
// get gene list and send to Enrichr
var gene_list = inst_cgm.params.network_data.row_nodes_names.join('\n');
var enrichr_info = {list: gene_list, description: 'Clustergrammer gene list' , popup: true};
// defined globally - will improve
enrich(enrichr_info);
})
var lib_groups = lib_section
.selectAll('g')
.data(possible_libraries)
.enter()
.append('g')
.attr('transform', function(d,i){
var vert = i*vertical_space
var transform_string = 'translate(0,'+ vert+')';
return transform_string;
})
lib_groups
.append('circle')
.attr('cx', 10)
.attr('cy', -6)
.attr('r', 7)
.style('stroke', '#A3A3A3')
.style('stroke-width', '2px')
.style('fill','white')
lib_groups
.append('text')
.attr('transform', 'translate(25,0)')
.style('font-size','16px')
.attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
.style('cursor', 'default')
.text(function(d){
return d.replace(/_/g, ' ');
});
lib_groups
.on('click', function(d){
d3.select(inst_cgm.params.root+' .enr_lib_section')
.selectAll('g')
.select('circle')
.style('fill','white');
// indicate that library was selected
d3.select(this)
.select('circle')
.style('fill','red')
// turn on clear sign
d3.select(inst_cgm.params.root+' .enr_menu_clear')
.transition()
.delay(1000)
.style('display', 'block');
// request enrichment results from Enrichr
enr_obj.enrichr_rows(d, update_viz_callback, 10);
make_enr_wait_circle();
animate_wait();
setTimeout(toggle_enrichr_menu, 500);
})
}
function clear_enrichr_results(){
d3.select(inst_cgm.params.root+ ' .enr_menu_clear')
.style('display', 'none');
// unselect library
d3.select(inst_cgm.params.root+' .enr_lib_section')
.selectAll('g')
.select('circle')
.style('fill','white');
// clear categories
inst_cgm.reset_cats();
// remove title and bars
d3.select(inst_cgm.params.root+' .enr_title').remove();
d3.selectAll(inst_cgm.params.root+' .enrichr_bars').remove();
}
function toggle_enrichr_menu(){
var enr_menu = d3.select(inst_cgm.params.root+' .enrichr_menu');
if (enr_menu.classed('showing') === false){
// show menu
///////////////////////
enr_menu
.classed('showing', true)
.style('display', 'block');
d3.select(inst_cgm.params.root+' .enrichr_menu')
.style('opacity',0)
.transition()
.style('opacity',1)
d3.selectAll('.row_cat_super').style('display','none');
// hide tooltip
d3.selectAll( inst_cgm.params.viz.root_tips + '_enr_tip')
.style('opacity', 0)
.style('display', 'block');
} else {
// hide menu
///////////////////////
setTimeout(function(){enr_menu.style('display', 'none');}, 1000)
d3.select(inst_cgm.params.root+' .enrichr_menu')
.classed('showing', false)
.style('opacity',1)
.transition()
.style('opacity',0)
d3.selectAll('.row_cat_super').style('display','block');
}
}
function get_enr_with_list(gene_list, library, callback_function){
enr_obj.library = library;
enr_obj.gene_list = gene_list;
enr_obj.post_list(gene_list, function(){
if (typeof callback_function != 'undefined'){
enr_obj.get_enr(library, callback_function);
} else {
enr_obj.get_enr(library);
}
});
}
function post_list(gene_list, callback_function){
var gene_list_string = gene_list.join('\n');
var form = new FormData();
var response;
form.append("list", gene_list_string);
form.append("description", "clustergrammer");
var settings = {
"async": true,
"crossDomain": true,
"url": "https://amp.pharm.mssm.edu/Enrichr/addList",
"method": "POST",
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": form
}
if (typeof callback_function === 'undefined'){
callback_function = confirm_save;
}
$.ajax(settings)
.done(function(response){
response = JSON.parse(response);
enr_obj.user_list_id = response.userListId;
// make get request
setTimeout(callback_function, 500, response);
// callback_function(response);
});
}
function confirm_save(response){
console.log('saved user_list_id '+String(enr_obj.user_list_id));
}
function get_enr(library, callback_function){
if (enr_obj.user_list_id !== null){
var form = new FormData();
var base_url = 'https://amp.pharm.mssm.edu/Enrichr/enrich?';
var library_string = 'backgroundType=' + String(library);
var list_id_string = 'userListId=' + String(enr_obj.user_list_id);
var full_url = base_url + library_string + '&' + list_id_string;
// get request
var settings = {
"async": true,
"crossDomain": true,
"url": full_url,
"method": "GET",
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": form
}
$.ajax(settings)
.done(function (response, textStatus, jqXHR) {
response = JSON.parse(response);
enr_obj.enr_data = response;
// parse enr_data to cat_data format
/////////////////////////////////////
// enr_obj.cat_data = enr_obj.enr_data
enr_obj.enr_data_to_cats();
if (typeof callback_function != 'undefined'){
callback_function(enr_obj);
}
d3.select(inst_cgm.params.root+' .enr_wait_circle').remove();
})
.fail(function( jqXHR, textStatus, errorThrown ){
enr_obj.get_tries = enr_obj.get_tries + 1;
if (enr_obj.get_tries < 2){
// enr_obj.get_enr(library, callback_function);
setTimeout( enr_obj.get_enr, 500, library_string, callback_function )
} else {
console.log('did not get response from Enrichr - need to remove wait circle')
d3.select(inst_cgm.params.root+' .enr_wait_circle').remove();
}
});
} else {
console.log('no user_list_id defined')
}
}
function enrichr_rows(library, callback_function, num_terms){
// set up a variable number of terms
enr_obj.library = library;
var gene_list = inst_cgm.params.network_data.row_nodes_names;
enr_obj.get_enr_with_list(gene_list, library, callback_function)
}
function enr_data_to_cats(){
var library_name = _.keys(this.enr_data)[0];
var enr_terms = this.enr_data[library_name];
// keep the top 10 enriched terms
enr_terms = enr_terms.slice(0,10);
cat_data = []
_.each(enr_terms, function(inst_term){
inst_data = {};
inst_data['cat_title'] = inst_term[1];
inst_data['cats'] = [];
inst_data['pval'] = inst_term[2];
// keep the combined score
inst_data['combined_score'] = inst_term[4]
cat_details = {};
cat_details.cat_name = 'true';
cat_details.members = inst_term[5]
// there are only two categories for Enrichr: true/false
inst_data['cats'].push(cat_details)
cat_data.push(inst_data);
});
this.cat_data = cat_data;
}
function animate_wait() {
var repeat_time = 700;
var max_opacity = 0.8;
var min_opacity = 0.2
d3.select(inst_cgm.params.root+' .enr_wait_circle')
.transition()
.ease('linear')
.style('opacity', min_opacity)
.transition()
.ease('linear')
.duration(repeat_time)
.style('opacity', max_opacity)
.transition()
.ease('linear')
.duration(repeat_time)
.style('opacity', min_opacity)
.each("end", animate_wait);
}
function update_viz_callback(enr_obj){
inst_cgm.update_cats(enr_obj.cat_data);
d3.select(inst_cgm.params.root+' .enr_title').remove();
var enr_title = d3.select(inst_cgm.params.root+' .viz_svg')
.append('g')
.classed('enr_title', true)
.attr('transform', function(){
var trans = d3.select('.row_cat_label_container')
.attr('transform').split('(')[1].split(')')[0];
x_offset = Number(trans.split(',')[0]) - 10;
return 'translate('+ String(x_offset)+', 0)';
});
enr_title
.append('rect')
.attr('width', inst_cgm.params.viz.cat_room.row)
.attr('height', 25)
.attr('fill', 'white');
var library_string = enr_obj.library.substring(0,40);
enr_title
.append('text')
.attr('transform', 'translate(0, 17)')
.text(library_string.replace(/_/g, ' '))
.style('font-size', '15px')
.attr('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif');
var extra_y_room = 1.25;
var unit_length = extra_y_room * inst_cgm.params.viz.cat_room.symbol_width;
var bar_width = unit_length * 0.9;
// Enrichr bars
///////////////////////////////
d3.selectAll(inst_cgm.params.root+' .enrichr_bars').remove();
var bar_height = inst_cgm.params.viz.clust.margin.top - 35;
var max_score = enr_obj.cat_data[0].combined_score;
var bar_scale = d3.scale.linear()
.domain([0, max_score])
.range([0, bar_height]);
d3.select(inst_cgm.params.root+' .row_cat_label_bar_container')
.selectAll()
.data(inst_cgm.params.viz.all_cats.row)
.enter()
.append('rect')
.classed('enrichr_bars', true)
.style('height', bar_width +'px')
.style('fill', 'red')
.style('width', function(d){
var enr_index = d.split('-')[1];
var inst_comb_score = enr_obj.cat_data[enr_index].combined_score;
var bar_lenth = bar_scale(inst_comb_score);
var bar_length_string = bar_lenth + 'px'
return bar_length_string;
})
.style('opacity', 0.4)
.attr('transform', function(d){
var inst_y = unit_length * (parseInt( d.split('-')[1], 10 ) -0.75 );
return 'translate(0,'+inst_y+')';
})
}
function make_enr_wait_circle(){
var pos_x = 72;
var pos_y = 25;
var click_circle = d3.select(inst_cgm.params.root+' .viz_svg')
.append('circle')
.classed('enr_wait_circle', true)
.attr('cx',pos_x)
.attr('cy',pos_y)
.attr('r',23)
.style('stroke','#666666')
.style('stroke-width','3px')
.style('fill','white')
.style('fill-opacity',0)
.style('opacity', 0);
}
// example of how to check gene list
// http://amp.pharm.mssm.edu/Enrichr/view?userListId=1284420
var enr_obj = {};
enr_obj.user_list_id = null;
enr_obj.enr_data = null;
enr_obj.cat_data = null;
enr_obj.get_tries = 0;
enr_obj.library = null;
enr_obj.gene_list = null;
enr_obj.enrichr_icon = enrichr_icon;
enr_obj.post_list = post_list;
enr_obj.get_enr = get_enr;
enr_obj.get_enr_with_list = get_enr_with_list;
enr_obj.enrichr_rows = enrichr_rows;
enr_obj.enr_data_to_cats = enr_data_to_cats;
enr_obj.update_viz_callback = update_viz_callback;
enr_obj.clear_enrichr_results = clear_enrichr_results;
return enr_obj;
}