(apologies for my lack of knowledge upfront)
Horizon Charts seem to be handled differently than area charts in D3. I've seen previous answers on non-continuous data in area charts, using line.defined. However, I'm not seeing how to accomplish that same effect in a horizon chart.
End goal: Where data is missing, skip or otherwise mask later, that point. As in this line.defined example (http://bl.ocks.org/mbostock/3035090), it shouldn't affect the curve of the path.
Ideally, the data in the json would just be a missing value, but I can add a type signifier if needed.
Is there a better approach - like adding a filled rectangle after the path was created in those spots to mask it?
I've updated the d3.horizon plugin to support setting area.defined for the area instance used internally.
For example, you can say:
var horizon = d3.horizon()
.width(…)
.height(…)
.defined(function(d) { return !isNaN(d[1]); });
Related
I'd like to have dc.js chart which slides along a selection, e.g. in the Nasdaq example https://dc-js.github.io/dc.js/ you would select a sub-selection of time then click "animate" button and the selection filter would slide along the x-axis at a pre-determined step size.
I'm a bit lost as to where one would start...does anyone have any ideas?
Most of what you need to do is set the current filter on the relevant chart based on a timer, instead of based on user interaction.
I've copied the relevant parts of the Nasdaq example into a fiddle to illustrate this: https://jsfiddle.net/0zkbyyqu/9/
Once the charts are in place, the animation is just a matter of changing the filter based on a setInterval. For obscure reasons, we want to use the focus method of the moveChart, not the filter method, but it's essentially doing the same thing, with a little more code to reflect the changes in the range chart:
var beginYear = 1985;
window.setInterval(function() {
moveChart.focus([
new Date(beginYear, 0,0,0,0,0,0),
new Date(beginYear+3, 0,0,0,0,0,0)]);
if(++beginYear > 2009)
beginYear = 1985;
}, 1000);
(If you were using the filter method, you'd have to construct a dc.filters.RangedFilter, as detailed here: Initial Range selection in DC.js chart)
I have left off your idea about the initial selection of the range coming from the user, and just gone with a range of 3 years. This example just starts animating as soon as it is loaded. You can fetch the current filter using chart.filter(); the result will be a RangedFilter, which is an array of two dates. Hopefully it is clear how to add start/stop buttons to the animation.
A couple of things are tricky about this approach:
It's tricky using a chart with transitions when you also have a timer or streaming data. In this case, I had to reduce the transitionDuration to 500ms for it to make any sense, but the cause-and-effect is still a little confusing. Not sure what to do about this.
The area chart transitions are incorrect so you get some weird artifacts.
I have a number of graphs, for simplicity take this example on jsfiddle, where there is a brush-on graph, a bar chart keyed on time and a row chart keyed on some categories. In addition, I use the d3-tip library for the tooltips (in the link above a very simplified version of my tip).
In order to avoid the creation of a bar-row in a rowChart, I used the fake-group as outlined in the FAQ of dc-js (and here as well).
The fake group works well, not displaying the C category on the row chart.
However, if I brush on some months with 0 data, when I reset the filter (just click anywhere but the filtered region on the brushon chart), the d3-tip on the row chart disappears.
Notice the if the group is created without the fake-grouping-function, this problem does not arise.
Any explanation why this happens?
How to avoid this (without loosing the remove_empty_bins)?
Although you can use dc.js and d3.js interchangeably, and dc.js is intentionally a "leaky abstraction", some things will go better if you do them the idiomatic dc.js way.
I have two suggestions:
Apply your tooltips in response to dc.js events so that they will get reapplied when new graphical objects are created (or re-created).
Use chart.selectAll instead of d3.selectAll when modifying the charts.
Okay, #2 actually has no bearing on this question, but it does help scope the selects better so that it's harder for them to miss the chart or accidentally modify stuff elsewhere in the page.
Implementing #1 looks something like this:
month_chart.on('pretransition', function(chart) {
chart.selectAll('rect.bar').call(month_tip)
.on('mouseover', month_tip.show).on('mouseout', month_tip.hide);
});
loc_chart1.on('pretransition', function(chart) {
chart.selectAll('g.row').call(loc_tip)
.on('mouseover', loc_tip.show).on('mouseout', loc_tip.hide);
});
The pretransition event fires right after a render or redraw, so it's usually the best moment to manipulate dc's elements. Much better than just running the code globally. I like to set everything up, then call dc.renderAll(), then allow the renders and redraws to take care of themselves later on.
In particular, when those bars get added back in when remove_empty_bins stops removing them, these events will pick them up and re-tip them.
Fork of your fiddle: https://jsfiddle.net/gordonwoodhull/5feL3gko/4/
Could some one please suggest how to do column-drilldown with D3 JS library,
below example is from Hightchart,
http://www.highcharts.com/demo/column-drilldown
A complete code example for this problem is probably quite extensive, so I'll mostly keep to how you would approach it and assume you know enough of D3 to turn the concept into code.
Lets assume you have the functionality for drawing a general bar chart.
Part of that functionality would priobably be things like
Setting up your svg element and containers
Setting up your scales (one for x and one for y)
Adding axes based on the scales you have created
Adding your bars to the svg container
4.1 Make sure you have your data set available as an array
4.2 Create an enter selection for the available data and append rectelements
4.3 Update attributes like x, y for all your available bar nodes
4.4 Remove any nodes on your exit selection
Voila you have a simple bar chart. Nothing new in that and you can have a look at the code details here -> https://bl.ocks.org/mbostock/3885304
Now in order to do the drill down:
In order to avoid lots of code repetition it probably makes sense to separate the above steps into functions. So for example a setup function that just creates your svg and containers as well as your scales.
Important about the setup function is that you do not need to rerun it on drill through.
Second you will want an update function. This contains steps 3+, which you will need to rerun in order to update your charts on drill through.
One addition here would be adding functionality for updating your scale domain in the beginning (as your data changes on drill through and you want to reflect that in your scales).
Now that you have those two functions all you really need to do is:
Add a click handler to your axis labels or your bars (click on bars might be easier for now). You cans use d3's .on() function for that.
In that event you will want to subset your data by the value of the clicked bar (or get a new data set for the bar value depending on how your data is structured) and then run the update function we created above with the new data.
It could look something like this:
d3.selectAll('.bar-nodes')
.on('click', function(d) {
var updatedData = updateData(d);
updateChart(updatedData);
});
If anything is unclear some more specific questions would be good.
Hope that helps.
I created a grouped-stacked composite chart using dc.js.
I am wondering if I can add a filterHandler to a composite chart.
I want to filter on each stacks.
It seems that, there is no straight forward way to build a composite chart and hook the parent chart to the volumeChart that would filter all the individual child components at once via dc.js, as Gordon suggested. I came up with a solution for one of my dashboards which is not so modular but works fine & also keep in mind the downsides to this approach pointed out below.
For the above dashboard to work, I defined 3 barCharts and 3 lineCharts overlaid on top the barCharts and chaining them all together linearly to volumeChart.
Although this works fine with a fixed y-axis scale, lineChart fails to align with the barCharts when the I set elasticY(true) on all of them, since the lineChart components seem to pic its own yMax and when I pass the yMax value as window.value from barCharts to the lineChart via .on('renderlet'..., again I fail to read these values due the misalignment of individual chart render times. And of course when I overlay the lineCharts I intrinsically loose/block the interaction with the barCharts and use the line moving average tooltips to view bar data.
I have not tried this yet but found a better way to do the same from Scott Miller - https://stackoverflow.com/a/25188909/5743716
Hope it helps!
I am new user of DC.JS. I am using dc.piechart. I'm having issues change pie slice colors using a dc.pieChart.
Documentation and examples I've seen use the colors method and many combination seen from Google. I want to bind a particular color for a particular data.
which I used the code for change color but still not working mentioned bellow.
.colors(["#eeff00","#ff0022"]);
another approach-
var colorScale = d3.scale.ordinal().domain(["banana", "cherry", "blueberry"])
.range(["#eeff00", "#ff0022", "#2200ff"]);
pie.colors(function(d){ return colorScale(d.fruitType); });
Any idea about how to solve the problem?
you need to generate a ordinal scale first.
.colors(d3.scale.ordinal().range(
[ '#1f78b4', '#b2df8a', '#cab2d6'..., '#bc80bd']);
The first slice would take the first color, second the second and so on.
A gordon pointed out, there is a convenience method too:
// convenience method, the same as above
chart.ordinalColors(['#1f78b4', '#b2df8a', '#cab2d6'...]);
https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#colorscolorscale