I'm trying to implement bar totals at with bar charts in a very similar manner as you would with row charts. For row charts, the code would be
Chart
.width(500)
.height(500)
.dimension(chartDim)
.group(chartGroup)
.title(function(d) {
return d3.format(",f")(d.value); // or your custom value accessor
})
.renderTitleLabel(true)
.titleLabelOffsetX(50)
.xAxis().tickFormat(function(v) {
return "";
});
This will return a chart with the values of it at the end of the row charts with the elasticX functionality. However, when it comes to bar chart, you would have to implement a renderlet solution like this and this where you have to manually draw the bar totals.
The issue I have with this approach is that 1) the y domain isn't elastic, so if there are wide variations in your selections, the bar totals may not show, and 2) you have to manually determine the range for the y axis.
Is there a more elegant way to create bar totals in a more elegant way without relying on the renderlet solution, something preferably similar to the row chart solution?
No, there is no more elegant way, until this feature makes it into dc.js proper.
However, there is a solution to the problem you're describing: the coordinate grid mixin does support internal padding, yAxisPadding, to reserve extra space when elasticY is enabled.
This should keep the labels inside the bounds.
https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#yaxispaddingpadding
yAxisPadding works, but you'll end up with padding both above and below the bars, which is rarely what you want.
If you overwrite the yAxisMin function with something that always returns 0 you should be set, however, e.g.:
timeChart
.height(200)
.brushOn(false)
.elasticY(true)
.x(d3.scaleBand())
.xUnits(dc.units.ordinal)
.yAxisLabel('Entries')
.yAxisPadding('10%')
.renderLabel(true)
.dimension(timeDimension);
timeChart.yAxisMin = () => 0;
Related
function chart (data, selector) {
// generate chart with zoom feature. it scales the X domain and update the chart accordingly.
}
chart(dataset1, "#chart1")
chart(dataset2, "#chart2")
chart(datasetn, "#chartn")
the code above is a chart generator function which I give it different datasets to make me charts. in all charts, the dataset has the same X values but different Y values.
problem:
lets say we have 3 charts, all the X axis ranges are between 0-100. In the first chart, I drag mouse and create a zoombox between 30-60 and the first chart updates, now it is scaled between 30-60. But the second and third chart are intact. I need them to be updated as well between 30-60.
similarly if I do the same for second chart, I need the first and third one get updated.
here is jsfiddle to illustration
I made not so big modification to make this works.
First of all we remember globally the information about single chart in var charts array. This is done during creation of charts
charts.push(lineChart(data1,"#chart1"));
charts.push(lineChart(data2,"#chart2"));
charts.push(lineChart(data3,"#chart3"));
Next we can use this array in function zoomdrag and update.
This work maybe not perfect (reset of chart is missing) but show how to handle it and get the same zoom in all charts.
Here is jsfiddle
I have created a stacked bar chart using dc.js and crossfilter. I am using a time dimnesion along the x-axis and has also made it elastic. But it seems like the chart is not rendering properly when there is just one column (either because of data or bceause of cross filtering by other charts) in the stacked bar chart.
Before:
After filtering graph shows no column or may be it is hidden:
As a workaround, I added an extra month to the min and max date to the data as dummy data but even that doesn't help. So I decided to do away with the elastic x-axis. But without an elastic x-axis the chart looks very sparse & poor when the data is filtered.
I have searched across many posts but I don't seem to find any helpful solution. I will be glad if someone could point me in the right direction. This is how I have setup my chart currently
chart
.width(768)
.height(480)
.margins({
left: 80,
top: 20,
right: 10,
bottom: 80
})
.x(d3.time.scale()).elasticX(true)
.round(d3.time.month.round)
.alwaysUseRounding(true)
.xUnits(d3.time.months)
.brushOn(false)
.xAxisLabel('Months')
.yAxisLabel("Expected Sales (in thousands)")
.dimension(dimMonthYear)
.renderHorizontalGridLines(true)
.renderVerticalGridLines(true)
.legend(dc.legend().x(130).y(30).itemHeight(13).gap(5))
.group(combinedGroup, "Understand", sel_stack(0))
.stack(combinedGroup, "Propose", sel_stack(1))
.stack(combinedGroup, "Negotiate", sel_stack(2))
.stack(combinedGroup, "Decide", sel_stack(3))
.stack(combinedGroup, "Deliver", sel_stack(4))
.centerBar(true)
.elasticY(true)
.elasticX(true)
.renderlet(function(chart) {
chart.selectAll("g.x text").attr('dx', '-30').attr(
'dy', '-7').attr('transform', "rotate(-60)");
});
Working jsfiddle
I think you are running into this issue: elasticX for linear domain doesn't include the rightmost bar
(Or a similar issue.)
dc.js takes its boundaries very literally, and it also computes them literally, so much that it doesn't take the width of its own bars into consideration.
One simple way to work around this is to add some padding:
.xAxisPadding(1).xAxisPaddingUnit('month')
Since you are aggregating by month, this will make sure there is always a month to the left and right of the calculated domain (which will be of width 0 when there is only one bar).
Of course, you will end up with that single bar filling the chart:
So you might want to calculate the domain manually, in preRedraw, until dc.js gets better at this.
Fork of your fiddle: https://jsfiddle.net/gordonwoodhull/97h8kd5g/2/
I am using chart.js to try to create a timeline of events relative to current date.
The horizontal bar chart is close but would like to show only the tips of the bars eg as points which would pretty much be a horizontal line chart.
I have shown my horizontal bar chart along with a mock-up of what it would look like as horizontal line chart.
Is this possible with chart.js ?
You first need to know that every information that you can edit about the chart is stored in the variable containing your chart (called myChart usually, but my2Bar in your fiddle).
If you want to globally change the graph, you will need to edit attributes in myChart.config.options.
If you want to change a specific chart, you will need to edit attributes in myChart.config.data.
In this case, you need to change a specific chart (which is the horizontal bar).
If you happen to check the logs of your graph, and go very deep in the config, you will finally see that bars in your chart are drawn using attributes stored in myChart.config.data.datasets[0]._meta[0].data[n]._model (n being the nth rectangle drawn, top to bottom).
Some attributes you can find there :
base : The X position where the rectangle is starting to be drawn (0 in your xAxe for instance).
x : The rectangle is being drawn until this X position.
height : The height of the drawn rectangle.
and so on ...
To edit these values, you just need to loop in your different rectangles (the n in the above path).
But you just can't do it manually on the config of your variable. If you do this, it won't work since your chart is responsive (on resize, it will redraw the chart using the former options).
What you must use are Chart.js plugins.
Plugins let you handle all the events that are triggered while creating, updating, rendering your graph.
Then, in your beforeRender event (triggered after the initialisation, but before the drawing), you need to loop in your different rectangles to edit the values to affect how they will be drawn :
beforeRender: function(chart) {
for (var i = 0; i < chart.config.data.datasets[0]._meta[0].data.length; i++) {
// Change both `3` values to change the height & width of the point
chart.config.data.datasets[0]._meta[0].data[i]._model["base"] = chart.config.data.datasets[0]._meta[0].data[i]._model["x"] + 3;
chart.config.data.datasets[0]._meta[0].data[i]._model["height"] = 3;
}
}
Here is a jsFiddle with the final result.
Unfortunately, I wasn't able to make round dots, instead of squared ones.
Update :
I have also made another jsFiddle where all the dots are linked together which makes it look like it is a horizontal line chart (can be improved of course, but it is a good start).
When using Chart.js i cant find a way to evenly scale the Y axis. Overiding and using manual scaling( scaleOverride: true ) for every chart is not really an option since there are alot of them and they have different data. Some one have an idea how to fix the scaling of the data?
This is the scaling i want:
Sometimes the scaling gets uneven depending on the data.
You can set the options globally - this will apply to every chart instance. For instance
Chart.defaults.global.scaleOverride = true;
...
I've created a series of plots using the flot library, which are all displayed on a single page. Is there a way to update the X axis min and max options (options.xaxis.min, options.axis.max) values WITHOUT re-plotting the plots ($.plot('placeholder',data,options))?
I found this solution: http://osdir.com/ml/flot-graphs/2012-02/msg00064.html
Which suggests that the following line would do it, but it does not work for me - the plots visible min and max are not modified based on this call.
monitorGraph.getOptions().xaxis[0].max = xaxis.max;
Any tips on updating the graphs xaxis max and min values would be greatly appreciated!
EDIT: Solution Below
The following code will take an existing plot, update the range that is visible, and redraw it in a very light and efficient way.
plot.getOptions().xaxis[0].min = time.start;
plot.getOptions().xaxis[0].max = time.end;
plot.setupGrid();
plot.draw();
After you set the value of the yaxis max height, try
yourPlot.setupGrid();
Not sure if it'll be as smooth as you want but I think it does the trick.
You can also dynamically modify MIN/MAX parameters in axis options:
plot.getAxes().xaxis.options.min = 0;
plot.getAxes().xaxis.options.max = 999;
plot.setupGrid();
plot.draw();