How to dynamically change bin size in bar chart (dc.js)? - dc.js

So I am calling the below code multiple times but the issue is that the bar chart bin size is stuck to the first data that I am putting in rest everything is changing as it should but not the bin size.
barChart
.width(1080)
.height(138)
.margins({top: 10, right: 10, bottom: 20, left: 50})
.dimension(key_map[$(this).text()].Dim)
.group(key_map[$(this).text()].Group)
.colors(['#6baed6'])
.x(d3.scale.ordinal().domain(key_map[$(this).text()].Dim))
.xUnits(dc.units.ordinal)
.elasticY(true)
.yAxis().ticks(4);
barChart.elasticX(true).filterAll();dc.redrawAll();

Thanks to #Gordon, I finally figured it out.
The array of keys was getting ignored even though I was calling elasticX(true); So I ended up calling chart.focus([all_the_keys_from_the group]); And it works perfectly now.
barChart
.dimension(key_map[$(this).text()].Dim)
.group(key_map[$(this).text()].Group)
.x(d3.scale.ordinal().domain(key_map[$(this).text()].Dim))
.xUnits(dc.units.ordinal)
.elasticX(true);
var focus_keys = [];
key_map[$(this).text()].Group.all().forEach(element => {
focus_keys.push(element.key);
});
barChart.focus(focus_keys);
barChart.filterAll(); dc.redrawAll();

Related

Is it possible to have a scrolling div that adjusts to the number of bars in a dc.js rowchart

I have several rowcharts that are connected to each other with dc.js.
These rowcharts have the x axis at the top in a different div, as explained here. However these rowcharts also implement filtering and removing, therefore, whenever I filter in one rowchart, the number of bars in the others reduce, but it maintains the size of the scrollable div, even though there are no bars below what is shown. Also, I'm pretty sure it is easy, but I haven't figured out how to put the reset button below the chart, because it shows between the chart div and the axis div, as seen below.
Is there a way to correct these issues?
This is what I have in each rowchart div:
<div id='axis'></div>
<div id="chart" style="overflow-y:auto; height:200px;">
<div>
<span class="reset" style="display: none;">Phylum seleccionado(s):
<span class="filter"></span>
<a class="reset" href="javascript:Chart.filterAll();dc.redrawAll();" style="display">Reset</a>
</span>
</div>
</div>
And this is what a I have in each rowchart in the main.js:
Chart
.fixedBarHeight(20)
.height(nonEmpty.all().length * 20 + 1)
.margins({top: 0, right: 20, bottom: 0, left: 20})
.width(600)
.xAxis(d3.axisTop())
.elasticX(true)
.ordinalColors(['#e41a1c'])
.gap(1)
.dimension(Dim)
.group(nonEmpty) //this removes the ones that don't match the filter of the other rowchart
.on('pretransition', function () {
Chart.select('g.axis').attr('transform', 'translate(0,0)');
Chart.selectAll('line.grid-line').attr('y2', Chart.effectiveHeight());
});
Partial answer here. Well, it answers what you asked but doesn't answer the next question I expect. :(
You are currently sizing the chart based on the number of bars, and you will need to resize the chart when the number of bars change.
This should be done in a preRedraw handler, but unfortunately preRedraw is currently fired after resizing is done. So currently you have to override .redraw():
dc.override(chart, 'redraw', function() {
chart.height(chart.group().all().length * 21);
return chart._redraw();
})
As for putting the info & controls after the chart, there are two issues and I was only able to solve one of them.
dc.js will append an svg element to the chart div. It'd be nice to have more control over this but I'm not sure what to do. For the moment, the easiest workaround is to re-append the info div:
chart.on('postRender', function() {
chart.root().node().appendChild(chart.select('div.info').node())
})
However, what you really want is probably to pull the info div out of the scrolling div, and I can't figure that out at the moment. The problem is that the chart expects the controls/info to be inside the chart div, and that's the same one that needs to scroll.
I tried to mess around with adding another scrolling div inside the chart div, and then moving the svg under it. This works, but it creates some annoying flashing.
Here's what I got so far. I may return to this later if I think of a better solution.
Update: controls outside of the scroller
To solve this right, we need the controls outside of the chart div.
We can port baseMixin.turnOnControls to a filtered event handler, and do the same showing and populating that the chart would do:
function turnOnControls(_chart, controls) {
var attribute = _chart.controlsUseVisibility() ? 'visibility' : 'display';
controls.selectAll('.reset').style(attribute, null);
controls.selectAll('.filter').text(dc.printers.filters(_chart.filters())).style(attribute, null);
}
function turnOffControls(_chart, controls) {
var attribute = _chart.controlsUseVisibility() ? 'visibility' : 'display';
var value = _chart.controlsUseVisibility() ? 'hidden' : 'none';
controls.selectAll('.reset').style(attribute, value);
controls.selectAll('.filter').style(attribute, value).text(_chart.filter());
}
function filter_function(controls) {
return chart => {
chart.hasFilter() ?
turnOnControls(chart, controls) :
turnOffControls(chart, controls);
}
}
chart.on('filtered', filter_function(d3.select('#info')));
Also, controlsUseVisibility and visibility: hidden is better when the controls will affect layout when shown/hidden.
(fiddle)

animation with jquery, moving element

I have a problem with animation in jquery. I want to make an element smaller after time (1second) and then move this to the bottom (20px).
What am i doing wrong?
$(function(){
var box = $('box');
box.delay(1000).animate({
width: 100,
height: 100,
}, 3000, function(){
box.animate({
top: "+=20",
}, 3000);
});
})
Your code works: https://jsfiddle.net/b4qjagwt/
However, I think you meant to select #box not box, is that right? There is no <box> element.
For the element to move down, you have two options:
Make the box element have position: relative
Use a top margin: "margin-top": "+= 20"
Using relative positioning will mean the element may overflow onto something else. I don't know what your page looks like, but you can try both and see which works best.

dc.js charts not linked

I have two barCharts exactly equivalent except for the .brushOn option :
pnlPerDaybarChart
.height(300)
.width(700)
.dimension(dims.date)
.group(groups.date.pnlSum)
.valueAccessor(function(d) {
return Math.abs(d.value);
})
.renderTitle(false)
.x(d3.time.scale().domain([minDate,maxDate]))
.xUnits(d3.time.days)
.colors(colorChoice)
.colorAccessor(colorAccessorPosNeg)
.brushOn(false)
.elasticY(true)
.margins({left: 70 ,top: 10, bottom: 30, right: 50})
.centerBar(true);
pnlPerDaybarChartBrush
.height(100)
.width(700)
.dimension(dims.date)
.group(groups.date.pnlSum)
.valueAccessor(function(d) {
return Math.abs(d.value);
})
.renderTitle(false)
.x(d3.time.scale().domain([minDate,maxDate]))
.xUnits(d3.time.days)
.colors(colorChoice)
.colorAccessor(colorAccessorPosNeg)
.brushOn(true)
.elasticY(true)
.margins({left: 70 ,top: 10, bottom: 30, right: 50})
.centerBar(true);
They render the way I expect but when I use the brush on pnlPerDaybarChartBrush, dc.js doesn't update the other one.
Also, clicking on a bar in pnlPerDaybarChart doesn't modify pnlPerDaybarChartBrush rendering (or any of the other charts on the webpage).
Is this the expected behaviour ?
What I was expecting is :
when I click on a single day in the chart without brush it
automatically renders all charts with data for that specific day.
when I use the brush it also renders the filtered chart without brush
Here is the jsFiddle
It doesn't look like dc.js bar charts support click-to-filter by default. The brush function is expected to be the way you filter a bar or line chart (but as you've discovered, it has its own complications).
If your data is too dense to filter it precisely with the brush, one option would be to allow the user to zoom in on the range chart with mouse or touch events:
http://jsfiddle.net/r4YBS/4/
The only change is adding
.mouseZoomable(true);
at the end of the definition of the brushable bar chart.
Alternately you could implement a custom click listener, which then calls the .filter() method directly.
Fiddle for your requirement.
You are of course right.
.rangeChart is the property you'd need to use it.
Hope it helps.

How to remove NVD3 chart resize/update delay

I've created an NVD3 multiBarChart and placed it in a jQuery resizable container. When resizing the chart, each render incurs the same delay as when the chart is first drawn: staggered left-to-right delayed drawing of the bars. This looks cool when the chart is first drawn, but it's a nuisance when resizing the chart. I've experimented with nv.d3.css, reducing every delay to 0ms to no avail. Haven't yet inspected the NVD3 JS and am hoping not to need to.
Fiddle:
http://jsfiddle.net/a5Fnj/10/
var container = $("#mycontainer");
$(container[0]).resizable();
var svg = d3.select(container[0]).append("svg");
nv.addGraph(function () {
var chart = nv.models.multiBarChart();
chart.xAxis.tickFormat(d3.format(',f'));
chart.yAxis.tickFormat(d3.format(',.1f'));
d3.select(container[0]).select("svg")
.datum(exampleData())
.transition().duration(0).call(chart);
nv.utils.windowResize(chart.update);
this.stackedbar = chart;
});
function exampleData() {
return stream_layers(3, 10 + Math.random() * 100, .1).map(function (data, i) {
return {
key: 'Stream' + i,
values: data
};
});
}
As of NVD3 1.7.1 you can use the duration option:
chart.duration(0);
I used transitionDuration: -1 that worked for a stackedAreaChart.
Edit
This helped remove the transition when appending chart data, not the re-size issue, please check the comments below.
In the latest version (from github), you can set .transitionDuration():
chart.transitionDuration(0);
Edit: Even with this, some of the transitions/durations are hardcoded in the NVD3 source. The only way to get rid of those is to modify the source.

Rotate axis labels in jqplot

I'm trying to replicate the rotated labels example at http://www.jqplot.com/tests/rotated-tick-labels.php using:
axesDefaults: {
tickRenderer: $.jqplot.CanvasAxisTickRenderer ,
tickOptions: {
angle: -30,
fontSize: '11pt'
}
},
http://jsfiddle.net/XV5yz/2/
But I can't get the rotated labels... I think I've included all the relevant js files...
The "fontSize" option works as expected.
Your jqplot files aren't correct. Try to include those instead :
http://cdn.jsdelivr.net/jqplot/1.0.8/jquery.jqplot.js
http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.dateAxisRenderer.min.js
http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.categoryAxisRenderer.min.js
http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasTextRenderer.min.js
http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasAxisTickRenderer.min.js
You need to increase div height too in order to see ticks well fitted :
<div id="chart2" style="height:400px;width:300px"></div>
Please see working example here

Resources