Skip to content

Commit

Permalink
Merge af73c24 into e41c2c1
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasoniii committed May 2, 2018
2 parents e41c2c1 + af73c24 commit 9d2c67b
Showing 1 changed file with 103 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,32 @@ define (

this.$elem.append($heatElem);

// can I whistle and dance while I work? I sure want to!
//
// Okay, here's what we gotta do. The clusters come back in some sort of arbitrary order, and they should be sorted into
// ascending order. Meaning that Cluster_0 (which is really Cluster_1 after we re-name it down below) should always come first.
// and then increase after that.
//
// But...
// There isn't anything that directly connects cluster info to the rows. We have a label and a count. So the first thing we need to do
// is invert the input data, because of course it comes in inverted. Then we can iterate over the resulting data structure and
// peel them out in order and stuff 'em into a key based on their label. Then we'll sort by key and re-assemble the data.
//
// BUT WAIT THERE'S MORE!
//
// Some of the rows contain all null values. Which means they should be filtered out and not displayed.
// Which in turn means that the cluster row counts need to be updated.
//
// Oh! And the labels need to be pruned.
// And what's the relationship between label and row? That's right! The index alone! So the labels and rows need
// to be more tightly linked before the pruning. Fun! Plus, the labels need to be sorted by the same technique.
//
// Oh oh oh! Which also means that a cluster could, in theory, be filtered out to not exist, which would screw up the numbering since
// one in the middle would be skipped entirely and we'd go straight from Cluster_1 -> Cluster_3! I'm not going to deal with that edge
// case until I am made to, though!
//
// http://dilbert.com/strip/2012-12-05

var invertedData = [];
for (var i = 0; i < newDataset.column_labels.length; i++) {
invertedData[i] = [];
Expand All @@ -85,13 +111,66 @@ define (
}
}

var heatmap_dataset = {
row_ids : newDataset.column_labels,
column_ids : newDataset.row_labels,
row_labels : newDataset.column_labels,
column_labels : newDataset.row_labels,
data : invertedData,//newDataset.data,
};
var rows_by_cluster = {};
var groupStartIdx = 0;
for (var i = 0; i < groupInfo.ygroup.length; i++) {
var label = groupInfo.ygtick_labels[i];
var count = groupInfo.ygroup[i];
var groupEndIdx = groupStartIdx + count;
if (rows_by_cluster[label] === undefined) {
rows_by_cluster[label] = { };
}

// side effects are the best! We need to filter out rows if they have only null values, but we also need
// to filter out the label associated with that row, which is in a different array and associated solely by index.
// So here we keep track of all of the indexes we've filtered out while iterating over the data, so we can use that
// to filter the sliced array of labels later.
var filteredIndexes = {};

//okay, now we slice out the rows associated with this cluster.
rows_by_cluster[label].data = invertedData.slice(groupStartIdx, groupEndIdx)
.filter( function(r, i) {
//here's where we filter. We take a row and iterate through it, if all of the values are null it gets tossed.
var keep_this_row = r.reduce( function (keep_this_row, v) {
return keep_this_row || v !== null;
}, false);

if ( !keep_this_row ) {
filteredIndexes[i] = true;
}
return keep_this_row;
});

//peel out the appropriate subarray of labels, filtering out the indexes we removed up above.
rows_by_cluster[label].labels = newDataset.column_labels.slice(groupStartIdx, groupEndIdx)
.filter(function(l, i) { return ! filteredIndexes[i] });

//next group starts where ours left off
groupStartIdx = groupEndIdx;
}

// now we've built up lists of filtered rows, grouped by cluster. Next step is easy - we just sort
// the cluster keys and stitch their related arrays back onto a bigger sorted list.
//
// This is where I'd love to use the spread syntax on the push, but since I wasn't sure our environment supported it
// I went old school.
var sortedRows = [];
var sortedLabels = [];
Object.keys(rows_by_cluster).sort().forEach( function(label) {
var clusterRows = rows_by_cluster[label].data;
sortedRows.push.apply(sortedRows, clusterRows);

var clusterLabels = rows_by_cluster[label].labels;
sortedLabels.push.apply(sortedLabels, clusterLabels);
});

var heatmap_dataset = {
row_ids : sortedLabels,
column_ids : newDataset.row_labels,
row_labels : sortedLabels,
column_labels : newDataset.row_labels,
data : sortedRows,//invertedData,//newDataset.data,
};

this.data('heatmap').setDataset(
heatmap_dataset
Expand All @@ -105,20 +184,17 @@ var heatmap_dataset = {
//this one assumes that all genes will always be in the dataset. They will not be.
//var total_groups = groupInfo.ygroup.reduce(function(p,v) { return p + v} );

//so, instead, we assign the total_groups to the length of the first row. Somewhat arbitrarily.
var total_groups = newDataset.data[0].length;

// the ygtick_labels which are returned from the server are wrong. They are indexed starting at 1, but we want them indexed
// starting at 0. We're not going to update the server code because of reasons.

// First thing we're going to do is a little bit of bounds checking and see if we actually need to decrement at all.

var needs_decrement = groupInfo.ygtick_labels.reduce( function(needs_it, label) {
var needs_decrement = Object.keys(rows_by_cluster).reduce( function(needs_it, label) {
if (label === 'Cluster_0') { needs_it = false };
return needs_it;
}, true);

var ygtick_labels = groupInfo.ygtick_labels.map( function(label) {
var ygtick_labels = Object.keys(rows_by_cluster).sort().map( function(label) {
// yes, I know that I don't need to loop and map to nothing if needs_decrement is false.
// I'm mapping invalid data from the server anyway. I put in the bounds check at all.
// Let me have this little protest.
Expand All @@ -128,6 +204,17 @@ var heatmap_dataset = {
return label;
});

// it's a maxim in CS that side-effects are wonderful and should always be used as much as possible, right?
// in this case, we need to find out the total number of groups. While we're iterating over our list of groups
// to get each group's count, we just peel that off into a running total.
var total_groups = 0;

// Super. We've got our labels in sorted order. Now we peel out our new counts in sorted order.
var ygroup = Object.keys(rows_by_cluster).sort().map( function(label) {
total_groups += rows_by_cluster[label].labels.length;
return rows_by_cluster[label].labels.length;
});

// finally, also just note that the "Results" tab of View Multi-Cluster Heatmap will, of course, still display the ygtick_labels
// as they were originally generated on the server, and so will not be in sync with the data in the heatmap itself.

Expand All @@ -141,7 +228,7 @@ var heatmap_dataset = {
var prior = 0;

for (var j = 0; j < i; j++) {
prior += groupInfo.ygroup[j];
prior += ygroup[j];
}
return chartBounds.size.height * (prior / total_groups);
}
Expand All @@ -154,7 +241,7 @@ var heatmap_dataset = {
.attr('width', $heatmap.xPaddingBounds().size.width)
.attr('height',
function (d, i) {
return chartBounds.size.height * (groupInfo.ygroup[i] / total_groups);
return chartBounds.size.height * (ygroup[i] / total_groups);
}
)
.attr('stroke', 'black')
Expand Down Expand Up @@ -193,7 +280,7 @@ var heatmap_dataset = {
.attr('font-size', function(d, i) {
var width = d3.select(this).node().getComputedTextLength();

var groupHeight = chartBounds.size.height * (groupInfo.ygroup[this.idx] / total_groups);
var groupHeight = chartBounds.size.height * (ygroup[this.idx] / total_groups);

if (width > groupHeight && width > 60) { //magic numbers abound in KBase!
this.tinySize = true;
Expand All @@ -206,7 +293,7 @@ var heatmap_dataset = {

var width = d3.select(this).node().getComputedTextLength();

var groupHeight = chartBounds.size.height * (groupInfo.ygroup[this.idx] / total_groups);
var groupHeight = chartBounds.size.height * (ygroup[this.idx] / total_groups);

if (width < groupHeight) {

Expand Down

0 comments on commit 9d2c67b

Please sign in to comment.