How to exit().transition rects under a col in d3 - d3.js

I have a stacked bar chart that shows values either for month or year.
It is composed of a series of columns (1 or 12), and rects within each column (9 individual values).
You can see it here: (Note - this is a valid web page, currently running on AWS.)
http://54.245.225.47/stackedbar_ex_good
When I go from months to year view, I want to move all the positions to the yearly value, then fade them out as the year values .enter().
The problem is that the rects (where I would normally do the .exit().transition().attr("y", new_val) never gets called since the column gets deleted (.exit()). And when I tried referencing the child .rects from the svg.selectAll(".col").exit().transition(), they seemed to disappear all at once. I'm guessing this is the wrong way.
Sorry this is so confusing! I'm sure this sort of thing is answered elsewhere, but I don't even know the language to describe it properly (and hence search for it). Any tips / pointers would be appreciated.
(There is a lot of code - I don't know how to simplify in order to even post it.)

Yeah, kinda hard to understand the problem... As I understand it, you want to animate the exiting rects to some position before they're removed from the SVG. But your problem is that the rects' parents –– col in your code –– are removed immediately, and so the nested rects never have a chance to animate. Right?
If so, one way around it is to delay the removal of the exiting col's in order to give the rects animation time to play. So, rather than doing:
col.exit().remove()
apply a the delay like so:
col.exit().transition().delay(2000).remove()
There's no actual, visible transition here; it's just a way to delay the call to remove().

Related

why is computeBoundingBox() working differently if switching to another browser tab during loading?

I’m working on a complex project in threejs.
Trying to cut the corner:
I have to load an obj, create some pivot point to use as parent of the mesh inside this obj, let the user move and rotate the pivots.
It takes somewhere about 10 to 15 seconds to load due to its complexity.
My problem is that it is working flawlessly if I load the page and don’t change the focus, but if I change the browser tab or collapse the browser window I got a very specific problem:
geometry.computeBoundingBox() gives different results.
Is there someone who can help me figure out what’s happening?
To help you better understand the situation: at loading time I have to rotate the obj to -90° on the X axis (inverting Y and Z as a consequence); I think it’s relevant because the boundingBox calculation somehow inverts Y and Z and changes its min and max also, but as I said only if I switch tab or collapse the browser.
p.s. No matter the OS nor the browser. It’s a super consistent bug
Ok, I somehow solved the issue, but take it with a grain of salt:
the problem can be tracked back to the execution stack of javascript:
the first function computes the bounding box, the second uses this computation, but if the first function is somehow slower to execute, the second could not have what it needs.
What I did is to force javascript to execute functions in a given order and only when the previous is finished.
The problem occurred only when changing the tab because browsers optimize resources of non visible tabs, but the code I wrote was anyway too much entropic to work properly.
I hope what I found will be understandable and useful to someone else in future.

Greensock library morphSVG animation

I am trying to make an animation that will fill a tube with liquid and then start moving the liquid inside. I am using an SVG with 3 main paths, the first one is liquid with short height, which then I morph to become the liquid with long height, then I want to "repeat" the morph between the other 2 paths to make it look like the liquid is moving, however when i move from one path to the other using morphSVG, I can't go back to the previous path, so my other morphSVG statement isn't executed.
Here's link to my code:
https://codepen.io/BrittanyR/pen/rJvOyX
As can be seen, I am able to move from one path to the other using:
TweenMax.to("#redSecondary", 2, {morphSVG: "#redPrimary", delay: 2})
But I can't then use this: TweenMax.to("#redPrimary", 2, {morphSVG: "#redSecondary"})
Any idea will be helpful.
Thanks.
It seems like it was just a logic issue in your code - your setTimeout() was alternating between animating #redPrimary and #redSecondary (targets), but you never changed what they were animating TO. So it worked the first time...and that's it. Every subsequent call was just duplicating the exact same movement (tweening to the current values...thus no motion).
I wonder if this is what you were looking for: https://codepen.io/GreenSock/pen/gvzMLG?editors=0010
Note: as a convenience, MorphSVGPlugin automatically records the original path data for the element so that if you ever want to animate back to it (like to("#redPrimary", 2, {morphSVG:"#redPrimary"}), it knows to grab that. It's all automatic :)
So if you want to repeatedly bounce between those morphs, a simple TimelineMax is probably the easiest way. Get rid of all that setTimeout() stuff and just do this:
var tl = new TimelineMax({repeat:-1, delay:2});
tl.to("#redPrimary", 2, {morphSVG:"#redSecondary", ease:Power1.easeInOut})
.to("#redPrimary", 2, {morphSVG:"#redPrimary", ease:Power1.easeInOut});
Does that help? I'm not entirely sure that I understood your goal properly with the animation, but hopefully this nudges you in the right direction.
Happy tweening!

DC.js Line Chart - no line being displayed

Need to display line in a line-chart , with the ability to move the tiles, to see a max bitrate value line, to see labels and axis pointers on hover, grouped with a table and time Slider.Y dimension needs to display "bitrate total" or "bitrate Avg" (as defined in code). X dimension needs to display 15 min interval in scope of weeks.
I can upload my data into a table but not into the line graph. I can see points on the graph using .renderDataPoints() but no lines.
I checked the data - could not find any null/NaN values being returned, not using any old version of colors.
The code can be found in https://jsfiddle.net/dani2011/bu2ag0f7/8/. Tried to replace my CSV with var data but nothing is being displayed at the moment in the fiddle. The code as whole is displayed in https://groups.google.com/forum/#!topic/dc-js-user-group/MEslyF2RWRI
Any help would be greatly appreciated.
Here's my go-to-answer for how to put data into a jsFiddle. Basically it's easiest to stick it in an unused tag in the HTML. bl.ocks.org / blockbuilder.org is easier for this.
Here's a fork of your fiddle with the data loaded that way:
http://jsfiddle.net/gordonwoodhull/bu2ag0f7/17/
I also had to remove the spaces from the column names, because those got d3.csv confused and caused the BITRATE calculations to fail.
There was also some stray code inside the renderlet which was failing with a complaint about dim not existing.
The main reason why data was not displaying was because the input groups were not producing usable aggregated data. Your data is very close together in time, so aggregating by week would aggregate everything.
The way to debug this is to put a breakpoint or a console.log before the chart initialization and look at the results of group.all()
In this case bitrateWeekMinIntervalGroupMove and minIntervalWeekBitrateGroup were returning an array with one key/value pair. No lines can be drawn with one point. :)
It looks like you originally wanted to aggregate by 15 minute intervals, so let's get that working.
For whatever reason, there are two levels of aggregation in crossfilter, the dimension level and the group level. The dimension will have first crack at generating a key, and then the group will further refine these keys.
Your min15 function will map each time-key to the 15-minute mark before it, but it needs data that is higher than 15 minutes in resolution. So let's put these groups on the dateDimension, which hasn't already been mapped to a lower resolution:
var minIntervalWeekBitrateGroup = dateDimension.group(min15).reduceSum(function (d) {
return +d.BITRATE
});
var bitrateWeekMinIntervalGroupMove = dateDimension.group(min15).reduce(
...
Great, now there are 30 data points. And it draws lines.
I made the dots a bit smaller :) because at 30 pixels it was hard to see the lines.
Zooming in using the range chart reveals more of lines:
There still seem to be glitches in the reduce function (or somewhere) because the lines drop to zero when you zoom in too far, but hopefully this is enough to get you moving again.
My fork of your fiddle: http://jsfiddle.net/gordonwoodhull/bu2ag0f7/25/

dc.js heatmap expanding data

I am trying to show machine states over time. Part of this is to reproduce/automate a report that used to be done by hand. It consists of coloring 2minute 'time slices' in Excel based on what the machine is doing.
(Sorry, not enough reputation to post a picture, but it is a classic heatmap where the state drives the color. Some non DC-JS fiddle: http://jsfiddle.net/ww6Lbnc5/4/)
I was able to generate most of what I want in the following jsfiddle:
http://jsfiddle.net/hwhfxz2t/14/
See fiddle for code.
The total state duration (for selected time frame) is shown in the pieChart, followed by the individual state lines and then the heatmap that people are used to. (the ZOOM and date selection buttons do not work in the fiddle but are there to select specific data ranges or zoom in if you like).
The line charts uses the original representation of the states, which consists of a time the state is entered and a duration.
In order to make the heat map work, I had to (I think) take the original data and convert it into individual minute chunks and mark them with a state. So for instance the original data specifying:
RUN state starting 14:30 for 300 seconds
becomes:
14:30=RUN, 14:31=RUN, 14:32=RUN, 14:33=RUN and 14:34=RUN
The code in lines 233-297 loops through the original data and generates a new one that does this. In cases where there is more than one state within a given minute, the last state survives.
This works okay but it seems that this code is exactly what is normally done in group().reduce(add,remove,init). But in this case I need to add multiple timeslots depending on the duration of a state.
Also, because it is now using a different crossfilter, maps do not update each other.
Here are my questions related to this:
Can I display a heatmap without supplying information for all individual
'cells'? (i.e. straddle cells based on a value, similar to rowspan in a table)
Can I add multiple values at once inside group().reduce()?
Is there an easy way to invert the yAxis so 0 is at the top?
When clicking a row in the heatmap, it selects a column and vice-versa?
I'm not sure if this should be in the crossfilter group. If so please ignore my rambling. If someone knows how to keep the charts linked by grouping better, please let me know.
--Nico
Concerning Question 3:
DC.js heatmaps currently do not support custom order functions on axis but there is a pull request that has been merged into the developing branch and should be accessible to the public soon.
You could manually edit the dc.js file to set the sorting in heatmaps to a custom function. In the latest (2.0.0-beta10) version it is the following line:
rowValues.sort(d3.ascending);
and accordingly
colValues.sort(d3.ascending);

Trouble with selection.datum()

I am following this example of a difference chart. I've added buttons on my page that make ajax calls to fetch new datasets, and then I redraw the difference charts. There are several difference charts on my page.
Upon redrawing, the rendering of the above/below areas becomes corrupted: x-values have both above and below areas rendered. I'm fairly certain it's not a back-end problem, because the initial load produces a correct chart; changing a parameter messes up the redrawn chart; and going back to the default parameters and redrawing the original chart also produces a corrupted chart. In fact, I can partially make out what's happening: the original time series is present on the new graph. It's almost as if there are three series being graphed.
I think it has to do with .datum. I don't fully understand how it works, since it differs from the standard enter/update/exit methods associated with .data. I've read the documentation, but am still confused. Some possibilities:
The original data is hanging around (even though I clean out the container with $('#chart').html(''))
The .append(g) is adding groups without removing the earlier ones.
The svg.append("clipPath").attr("id", "clip-below") is causing problems, since multiple nodes have the same id (even though again, I'm not sure how this could happen since I remove the nodes before the redraw).
I feel like I'm missing a lot of fundamentals here, even though I've spent a decent amount of time trying to understand the library. Can anyone see anything obvious, or point out some good resources for me to look at?
UPDATE: This has to do with there being two charts on the page. I noticed this when I opened the inspector and closed it. The areas of the bottom chart (the difference chart) had screwed up, and I noticed the new line that it was using to separate the above-area from the below-area looked a lot like one of the lines from the top chart.
Does anybody have experience with dependency issues/namespace collisions when drawing two charts on the same page?
The problem was, the id's for the clipping paths were the same.
I would still like some more resources concerning .datum.

Resources