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
251 lines (210 loc) • 7.48 kB
JavaScript
var calc_cat_cluster_breakdown = require('./calc_cat_cluster_breakdown');
module.exports = function make_cat_breakdown_graph(params, inst_rc, inst_data, dendro_info, selector, tooltip=false){
// in case sim_mat
if (inst_rc === 'both'){
inst_rc = 'row';
}
var cat_breakdown = calc_cat_cluster_breakdown(params, inst_data, inst_rc);
if (cat_breakdown.length > 0){
// put cluster information in dendro_tip
///////////////////////////////////////////
var cluster_info_container = d3.select(selector + ' .cluster_info_container');
// loop through cat_breakdown data
var super_string = ': ';
var paragraph_string = '<p>';
var width = 225;
var bar_offset = 23;
var bar_height = 20;
var max_string_length = 15;
var bar_width = 135;
var title_height = 27;
// limit on the number of category types shown
var max_cats = 3;
// limit the number of bars shown
var max_bars = 5;
// calculate height needed for svg based don cat_breakdown data
var svg_height = 20;
_.each(cat_breakdown.slice(0,max_cats), function(tmp_break){
var num_bars = tmp_break.bar_data.length;
if (num_bars > max_bars){
num_bars = max_bars;
}
svg_height = svg_height + title_height * (num_bars + 1);
});
// Cluster Information Title (for tooltip only not modal)
if (tooltip){
cluster_info_container
.append('text')
.text('Cluster Information');
}
var main_dendro_svg = cluster_info_container
.append('div')
.style('margin-top','5px')
.classed('cat_graph', true)
.append('svg')
.style('height', svg_height+'px')
.style('width', width+'px');
// make background
main_dendro_svg
.append('rect')
.classed('cat_background', true)
.style('height', svg_height+'px')
.style('width', width+'px')
.style('fill', 'white')
.style('opacity', 1);
// the total amout to shift down the next category
var shift_down = title_height;
// limit the category-types
cat_breakdown = cat_breakdown.slice(0, max_cats);
_.each(cat_breakdown, function(cat_data){
// only keep the top 5 categories
cat_data.bar_data = cat_data.bar_data.slice(0, max_bars);
cluster_info_container
.style('margin-bottom', '5px');
var cat_graph_group = main_dendro_svg
.append('g')
.classed('cat_graph_group', true)
.attr('transform', 'translate(10, '+ shift_down + ')');
// shift down based on number of bars
shift_down = shift_down + title_height * (cat_data.bar_data.length + 1);
var inst_title = cat_data.type_name;
// ensure that title is not too long
if (inst_title.length >= max_string_length){
inst_title = inst_title.slice(0,max_string_length) + '..';
}
// make title
cat_graph_group
.append('text')
.classed('cat_graph_title', true)
.text(inst_title)
.style('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
.style('font-weight', 800);
var count_offset = 15;
// make P-value title
cat_graph_group
.append('text')
.text('Count')
.attr('transform', function(){
var inst_x = bar_width + count_offset;
var inst_translate = 'translate('+ inst_x +', 0)';
return inst_translate;
});
var line_y = 4;
cat_graph_group
.append('line')
.attr('x1', 0)
.attr('x2', bar_width)
.attr('y1', line_y)
.attr('y2', line_y)
.style('stroke', 'blue')
.style('stroke-width', 1)
.style('opacity', 1.0);
var cat_bar_container = cat_graph_group
.append('g')
.classed('cat_bar_container', true)
.attr('transform', 'translate(0, 10)');
// make bar groups (hold bar and text)
var cat_bar_groups = cat_bar_container
.selectAll('g')
.data(cat_data.bar_data)
.enter()
.append('g')
.attr('transform', function(d, i){
var inst_y = i * bar_offset;
return 'translate(0,'+ inst_y +')';
});
var bar_scale = d3.scale.linear()
.domain([0, cat_data.num_in_clust])
.range([0, bar_width]);
// make bars
cat_bar_groups
.append('rect')
.style('height', bar_height+'px')
.style('width', function(d){
var inst_width = bar_scale(d[2]);
return inst_width +'px';
})
.style('fill', function(d){
// cat color is stored in the third element
return d[3];
})
.style('opacity', params.viz.cat_colors.opacity)
.style('stroke', 'grey')
.style('stroke-width', '0.5px');
// make bar labels
cat_bar_groups
.append('text')
.classed('bar_labels', true)
.text(function(d){
var inst_text = d[1];
if (inst_text.indexOf(super_string) > 0){
inst_text = inst_text.split(super_string)[1];
}
if (inst_text.indexOf(paragraph_string) > 0){
// required for Enrichr category names (needs improvements)
inst_text = inst_text.split(paragraph_string)[0];
}
// ensure that bar name is not too long
if (inst_text.length >= max_string_length){
inst_text = inst_text.slice(0,max_string_length) + '..';
}
return inst_text;
})
.attr('transform', function(){
return 'translate(5, ' + 0.75 * bar_height + ')' ;
})
.style('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
.style('font-weight', 400);
// make bar labels
var shift_count_num = 25;
cat_bar_groups
.append('text')
.classed('count_labels', true)
.text(function(d){
return String(d[4]);
})
.attr('transform', function(){
var inst_x = bar_width + count_offset + shift_count_num;
var inst_y = 0.75 * bar_height;
return 'translate('+ inst_x +', ' + inst_y + ')' ;
})
.style('font-family', '"Helvetica Neue", Helvetica, Arial, sans-serif')
.style('font-weight', 400)
.style('text-anchor', 'end');
});
// reposition tooltip
/////////////////////////////////////////////////
if (tooltip){
var dendro_tip = d3.select(selector);
var old_top = dendro_tip.style('top').split('.px')[0];
var old_left = dendro_tip.style('left').split('.px')[0];
var shift_top = 0;
var shift_left = 0;
// shifting
if (inst_rc === 'row'){
// rows
//////////////
shift_top = svg_height + 30;
shift_left = 32;
// prevent graph from being too high
if (dendro_info.pos_top < svg_height){
shift_top = -(svg_height + (dendro_info.pos_mid - dendro_info.pos_top)/2) ;
}
} else {
// columns
//////////////
shift_top = svg_height + 32;
shift_left = 30;
}
dendro_tip
.style('top', function(){
var new_top = String(parseInt( old_top,10) - shift_top) + 'px';
return new_top;
})
.style('left', function(){
var new_left = String(parseInt( old_left,10) - shift_left) + 'px';
return new_left;
});
}
}
};