Reputation: 1644
I'm having trouble seeing the big picture for some potentially massive refactoring. I'm looking for a solution (if one exists) that solves two problems simultaneously. I haven't coded in d3 for a long time and was never fluent to begin with.
I've created a simple demo of MCMC. It looks like this:
All the data exist in an array thetas
that has dimensions nChains
x nIters
, or 2 x ... (with the chain length increasing with each mouse click).
Now I want to show a burn-in, which will be the same length for each chain. For the left plot, the burn-in will show, in different colors (e.g., orange and red) for each chain, the first biLength
points. Effectively, the first biLength
points that are already there will just be colored differently. On the histogram on the right, I want those points to have their own corresponding bars.
Should I create a separate array to hold the burn-in, effectively plotting two containers of data on each plot? (Is there an example of how to do this?) Alternatively, is there some way to keep the data in thetas
but handle subcomponents differently? (Example?)
Here's some sample code to show how I'm currently plotting thetas
:
// Left plot update function movePoints () { var tmp = chart.selectAll(".vis1points").data(thetas[0], function (d, i) { return i; } ); tmp .enter().insert("svg:circle") .attr("class", "vis1points") .attr("cx", function (d, i) { return xx(i); }) .attr("cy", yy) .attr("r", 3) tmp.transition() .duration(10) .attr("cx", function (d, i) { return xx(i); }) .attr("cy", yy) tmp.exit() .transition().duration(10).attr("r",0).remove(); if ( nChains == 2 ) { var tmp2 = chart.selectAll(".vis1points2").data(thetas[1], function (d, i) { return i; } ); tmp2 .enter().insert("svg:circle") .attr("class", "vis1points2") .attr("cx", function (d, i) { return xx(i); }) .attr("cy", yy) .attr("r", 3) tmp2.transition() .duration(10) .attr("cx", function (d, i) { return xx(i); }) .attr("cy", yy) tmp2.exit() .transition().duration(10).attr("r",0).remove(); } };
The axes currently take thetas
as input to infer the range and domain limits.
For the histogram on the right:
// Creation involves... var dataLength = thetas[0].length; this.histBars = this.vis.selectAll("rect.vis2bars") .data(that.histVals.counts[0]) .enter().append("svg:rect") .attr("class", "vis2bars") .attr("x", function (d, i) { return that.xx2(i); }) .attr("y", function (d, i) { return that.yy2(that.maxDensity*(d/dataLength)/(d3.max(that.histVals.counts[0])/dataLength)); }) .attr("height",function (d, i) { return that.yy2(0)-that.yy2(that.maxDensity*(d/dataLength)/(d3.max(that.histVals.counts[0])/dataLength)); }) .attr("width", Math.floor(innerWidth2/numBins)); this.histBars.transition() .attr("y", function (d, i) { return that.yy2(that.maxDensity*(d/dataLength)/(d3.max(that.histVals.counts[0])/dataLength)); }) .attr("height",function (d, i) { return that.yy2(0)-that.yy2(that.maxDensity*(d/dataLength)/(d3.max(that.histVals.counts[0])/dataLength)); }) .duration(dur);
And the update:
this.update = function( dur2 ) { var dataLength = thetas[0].length; var tmp2 = this.histBars.data(this.histVals.counts[0]); var tmp3; if ( nChains > 1 ) { // fix tmp3 = this.histBars2.data(this.histVals.counts[1]); } var that = this; tmp2 .transition() .delay( 0 ) // could tweak... .duration(dur2 - 10) .attr("y", function (d, i) { return that.yy2(that.maxDensity*(d/dataLength)/(d3.max(that.histVals.counts[0])/dataLength)); }) .attr("height",function (d, i) { return that.yy2(0)-that.yy2(that.maxDensity*(d/dataLength)/(d3.max(that.histVals.counts[0])/dataLength)); }); // Add update for second data set if ( nChains > 1 ) { tmp3 .transition() .attr("y", function (d, i) { return that.yy2(that.maxDensity*(d/dataLength)/(d3.max(that.histVals.counts[1])/dataLength)); }) .attr("height",function (d, i) { return that.yy2(0)-that.yy2(that.maxDensity*(d/dataLength)/(d3.max(that.histVals.counts[1])/dataLength)); }); }
Upvotes: 3
Views: 536
Reputation: 1163
You can dynamically change the color of your circles when updating them, for example inside here :
tmp.transition()
.duration(10)
.attr("cx", function (d, i) { return xx(i); })
.attr("cy", yy)
.attr("fill", function(d) {
if (d.isBiLengthPoint) {
return "orange";
} else {
return "blue";
}
});
I assume that for the moment you are coloring your circles based on your CSS, but for the effect you want I really think that loading them dynamically is a better solution.
Or you could change the class of your circles dynamically and have two CSS classes declaration
tmp.transition()
.attr("class", function(d) {
if (d.isBiLengthPoint) {
return "vis1points-bilength";
} else {
return "vis1points";
}
})
.duration(10)
.attr("cx", function (d, i) { return xx(i); })
.attr("cy", yy)
and in your CSS
vis1points {
fill: blue;
}
vis1points-bilength {
fill: orange;
}
Upvotes: 0