I've got a graph of small multiples with line charts. All is spiffy, except I cannot figure out how to get the tooltip to grab the data I need it to.
The sample and the code is at http://bl.ocks.org/emagee/8b2f557396d6f16ba65f. The tooltip code starts at line 198, with the toolTip variable declared just above that. The tooltip itself is working awesomely, but I cannot figure out how to get the tooltip to show the "date" and "count" variables. I did figure out how to get the "subject" in tool tip, but that is redundant, as you will see.
Specifically, my problem stems from not knowing how to skip a level as I dig deeper into the object -- "key" is the first level, then "values", then an unnamed construct, THEN the data I need ("date" and "count").
Any guidance on how to get from "key" to the "date" and "count" data would be most appreciated. I do understand that it may be more of a basic JS problem than a D3.js problem, but I'm a bit shaky with both!
Addendum (and, I'm afraid, a second question) -- I'm also wondering now if part of the problem is that I'm accessing the entire line/path -- as opposed to individual points. Should I perhaps overlay some appropriately sized, invisible circles/points on the lines and have the tooltip try to take readings from those...
First question you have to ask is do you want the date and count of where they moused over or do you want the date and count of the closest point to where they moused over? I'm assuming the later, so that's what I'll answer.
To do this, I'd use a combination of invert and a bisector:
.on("mouseover", function(s) {
var xDate = x.invert(d3.mouse(this)[0]), //<-- give me the date at the x mouse position
bisect = d3.bisector(function(d) { return d.date; }).left, //<-- set up a bisector to search the array for the closest point to the left
idx = bisect(s.values, xDate); //<-- find that point given our mouse position
You can now use:
s.values[idx].date
s.values[idx].count
Here's a working example.
Related
I am working with D3 to try and create a simple bar chart. My x-axis uses ScaleTime and my y-axis uses ScaleLinear. In the pictures below, you can see that the values I've put for the domain (date values) go past the the range. Shouldn't the ticks be confined to the line? Been struggling with this for a while and haven't been able to find anything on the internet.
Graph
Inspect Element
EDIT
After applying .clamp, this is the result
New Graph
And here is the main part of my code I'm looking at (some of the values are arbitrary)
Code
I think this is because clamping is disabled by default on time scales:
Constructs a new time scale with the specified domain and range, the default interpolator and clamping disabled.
It's hard to suggest a fix without seeing your code, but try something like this:
d3.scaleTime()
.domain([domain)
.range([range])
.clamp(true)(Date.now())
I'm trying to build a sunburst diagram with an interactive slider. More specifically, I would like the slider, which is based on date, to appear and disappear slices in the sunburst according to the date associated with those slices.
I have created both the slider and the sunburst, but cannot get them to work together.
http://plnkr.co/edit/YIHd7o3fQ9RLFuN5PWVa?p=preview
I believe the problem lies in the 'updateData' function, which compares the date selected by the slider to the date associated with each datapoint. More specifically, the syntax obtaining the date of the slices appears to be incorrect, as it console.log() a "null" value.
Things I've tried:
To check syntax, I replaced d.data.Cattime with d.data.id. The latter logs the dataset information to the console - suggesting the syntax is correct. Strangely, this doesn't work with d.data.parentId.
I thought the problem might be that items under the Cattime heading is not represented as a date. But this code, console.log(parseDate(data[1].Cattime)); suggests that this is recognized as a date.
Any suggestions appreciated.
You should compare two date objects in your return statement.
svg.selectAll(".node").style("fill", function(d) {
return new Date(((d.data.data.Cattime))) > new Date(h) ? "red" : "black";
}
Also, initially you are setting fill color of path as a style property, but in your update function you are setting it as an attribute.
Apparently, its value doesn't change when you set it as an attribute later on. So, either change update function to style or change your initialization to attribute.
working example
I've just draw a stacked-area-chart with D3JS.
This is my referral implementation
I also need to dynamically swap the ordering of the layers.
I think that there isn't a way to do it dynamically without redrawing (or is there any? :D )
Actually i'm trying to map the data to a new header column, but this implies the redrawing.
Let me show you an example:
Here is the TSV header ['date', 'columnA', 'columnB', 'columnC']
Every column, except of 'date', represent the % of area for that sample.
I would like to dynamically rearrange the area layers, but I'm pretty sure that I also need to parse again the data with a new header
eg: ,
['date', 'columnA', 'columnB', 'columnC']
-map to-
['date','columnB', 'columnC', 'columnA']
and then draw the result.
I'm doing it right? Thanks for your support, cheers.
This is the line that defines the array that will be passed to the stack() function:
var keys = data.columns.slice(1);
Right now, this is the array:
["Google Chrome","Internet Explorer","Firefox","Safari","Microsoft Edge","Opera","Mozilla","Other/Unknown"]
But you can sort it anyway you want. For instance, sorting by alphabetic order:
keys.sort();
Which gives us:
["Firefox","Google Chrome","Internet Explorer","Microsoft Edge","Mozilla","Opera","Other/Unknown","Safari"]
Here is the result: https://bl.ocks.org/anonymous/6a339ed0731a70bb234af150ee6b4a99
Here is another one, with a random permutation (refresh the page to see diferent orders): https://bl.ocks.org/anonymous/662f99901219b8907030ec3c84363f3a
Pay attention to this: the order in the stacked area chart is now different, but the colours don't keep the same for each browser (that is, each stacked area). That's because d3.scaleOrdinal(d3.schemeCategory10) assigns the colours in a first-come, first served basis.
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/
I am comfortable with d3 but only starting to understand transitions/animations.
I am trying to take M Bostock's Marey chart for trains as a base and produce an interactive chart for Mumbai Western Railway system. The bl.ocks page is here. I have made slight changes so far as to adding tip text for lines, colour coding the station name as per zone etc.
Mumbai Western train system has fast and slow trains. The requirement is that, based on User input, the chart either displays all trains or Fast only. Fast trains are in black.
The column 'type' in csv either dictates a train is fast (F) or slow(S).
I am not able to think of best way to accomodate the transition framework. I have thought of the following as options so far.
Having two seperate csv files(one for all and other for fast only). Having a 'on click' listener outside d3.csv function and calling the appropriate d3.csv loader when selected. This is probably crude and not so elegant
There is already a filter here selecting only SF trains. but how do i incorporate only S or both SF depending on on click listener.
var train = svg.append("g")
.attr("class", "train")
.attr("clip-path", "url(#clip)")
.selectAll("g")
.data(trains.filter(function(d) { return /[SF]/.test(d.type); }))
//.data(trains)
.enter().append("g")
.attr("class", function(d) { return d.type; });
Appreciate if some one can help with an appropriate and elegant way to incorporate this transition
Edit: I know that for now, I have included form radio buttons outside SVG container which is puching the bottom X axis out of SVG container. Once the transitions part is covered I will attend to it
What you already have looks like a good start to me. The basic pattern is this.
Render a default selection when the CSV is loaded.
When the selection changes, filter the data to display like you already do. You might want to keep a reference to the currently selected data somewhere. Remember that your filter function can be something arbitrarily complex, i.e. you can check all the conditions you like.
Select all the train paths and pass in the new data. You will need to provide a key function (second argument to .data(), see here) to make sure that data and lines are matched correctly.
Handle the enter/update/exit selections. Start without transitions first and then add them.
How exactly you want to do the transitions depends on you, but you could have for example enter and exit selection fading in and out like so.
selection.enter().append("path").attr("opacity", 0).transition().attr("opacity", 1);
selection.exit().transition().attr("opacity", 0).remove();