Margins on composite Chart - dc.js

I've recently tried to add margins to composite charts and the charts are plotting to the left of the Y axis.
The charts are built dynamically. I tried more combinations of values for margins, but it didn't work. I want to add margin-left because some charts have big values on y axis.
Here is the esential code:
hist_margins = {top: 10, right: 50, bottom: 30, left: 40}
charts[i]
.compose([
dc.barChart(charts[i])
.dimension(dim)
.group(static_group)
.colors('#ccc')
.barPadding(0.1)
.controlsUseVisibility(true),
dc.barChart(charts[i])
.dimension(dim)
.colors('rgb(85, 160, 185)')
.group(group)
.barPadding(0.1)
.controlsUseVisibility(true)
.brushOn(false),
])
var min = dim.bottom(1)[0][it.variable],
max = dim.top(1)[0][it.variable];
charts[i]
.width(w_hist)
.height(h_hist)
.margins(hist_margins)
.dimension(dim)
.group(group)
.x(d3.scaleLinear().domain([min, max]))
.xAxisLabel(it.variable, 20)
.xUnits(dc.units.fp.precision(it.precision*1.5))
.brushOn(true)
.transitionDuration(0)
.renderTitle(true)
.title(function (d) {
return it.variable + ': ' + d.value
})
.controlsUseVisibility(true);
Any ideas?

As of dc.js 3.1.4, you would have to call .margins() before calling .compose() in order for the values to be reflected in the child charts.
However, thanks to a PR by Keith Dahlby, this limitation has been eliminated.
So, you can either upgrade to dc.js 3.1.5 (just released), or you can call .margins() first.

Related

d3.js - Dendrogram display adjusted to the tree diagram

With d3.js I have created d3 dendrograms to visualize hierachicals relations between objects. Dimensions and margins of the graph are defined with fixed height and width values.
var width = 1000,
height = 800,
boxWidth = 150,
boxHeight = 35,
gap = {
width: 50,
height: 12
},
margin = {
top: 16,
right: 16,
bottom: 16,
left: 16
},
svg;
With a few relations, display is ok but with many relations it's doesn't fit, graph is 'cut' and I can't see the entire graph. How to set this width and height properties dynamically and adjusted to the size of the graph ?
An example with a correct display : Codepen
An example with an incorrect display : Codepen
Let's work this out, you need to know the bounding box of your content first and then adjust the svg size. To do that, in this particular case, you only have to look at the boxes or nodes and can ignore the links.
With that in mind you can do the following after populating the Nodes in your renderRelationshipGraph function and return the calculated value:
function renderRelationshipGraph(data) {
// ...
var bbox = Nodes.reduce(function (max, d)
{
var w = d.x + boxWidth;
var h = d.y + boxHeight;
if (w > max[0]) {max[0] = w}
if (h > max[1]) {max[1] = h}
return max
}, [0,0])
return bbox
}
then on the main code change use it to update height and width of the svg:
svg = d3.select("#tree").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("g");
var bbox = renderRelationshipGraph(data);
svg.attr("width", bbox[0])
.attr("height", bbox[1]);
You can add a transition and limit the height but this does what you requested with a really large end result.

D3 v4 - make a horizontal bar chart with fixed width

I have made a horizontal bar chart using d3 v4, which works fine except for one thing. I am not able to make the bar height fixed. I am using bandwidth() currently and if i replace it with a fixed value say (15) the problem is that it does not align with the y axis label/tick http://jsbin.com/gigesi/3/edit?html,css,js,output
var w = 200;
var h = 400;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h)
.attr("transform", "translate(80,30)");
var data = [
{Item: "Item 1", count: "11"},
{Item: "Item 2", count: "14"},
{Item: "Item 3", count: "10"},
{Item: "Item 4", count: "14"}
];
var xScale = d3.scaleLinear()
.rangeRound([0,w])
.domain([0, d3.max(data, function(d) {
return d.count;
})]);
var yScale = d3.scaleBand()
.rangeRound([h,0]).padding(0.2)
.domain(data.map(function(d) {
return d.Item;
}));
var yAxis = d3.axisLeft(yScale);
svg.append('g')
.attr('class','axis')
.call(yAxis);
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('width', function(d,i) {
return xScale(d.count);
})
.attr('height', yScale.bandwidth())
.attr('y', function(d, i) {
return yScale(d.Item);
}).attr("fill","#000");
The y axis seemed to be off SVG in the link you provided. (Maybe you have overflow: visible; for the SVG.
Anyway, I've added a few margins to the chart so that the whole chart is visible. Here it is (ignore the link description):
DEMO: H BAR CHART WITH HEIGHT POSITIONING TO THE TICKS
Relevant code changes:
As you are using a scale band, the height is computed within. You just need to use .bandWidth().
.attr('height', yScale.bandwidth())
Added a margin and transformed the axis and the bars to make the whole chart visible :
: I'm assigning margins so that the y-axis is within the viewport of the SVG which makes it easier to adjust the left margin based on the tick value as well. And I think this should be a standard practice.
Also, if you notice, the rects i.e. bars are now a part of <g class="bars"></g>. Inspect the DOM if you'd like. This would be useful for complex charts with a LOT of elements but it's always a good practice.
var margin = {top: 10, left: 40, right: 30, bottom: 10};
var xScale = d3.scaleLinear()
.rangeRound([0,w-margin.left-margin.right])
var yScale = d3.scaleBand()
.rangeRound([h-margin.top-margin.bottom,0]).padding(0.2)
svg.append('g')
.attr('class','axis')
.attr('transform', 'translate(' + margin.left+', '+margin.top+')')
Try changing the data and the bar height will adjust and align according to the ticks. Hope this helps. Let me know if you have any questions.
EDIT:
Initially, I thought you were facing a problem placing the bars at the center of the y tick but as you said you needed fixed height bars, here's a quick addition to the above code that lets you do that. I'll add another approach using the padding (inner and outer) sometime soon.
Updated JS BIN
To position the bar exactly at the position of the axis tick, I'm moving the bar from top to the scale's bandwidth that is calculated by .bandWidth() which will the position it starting right from the tick and now subtracting half of the desired height half from it so that the center of the bar matches the tick y. Hope this explains.
.attr('height', 15)
.attr('transform', 'translate(0, '+(yScale.bandwidth()/2-7.5)+')')

Calculating the number of bars in a bar chart in dc.js

I want to adjust width of bar charts based on number of bars appearing on my bar chart. Here is my chart which is displaying enough records which are fit to the width and is displayed nicely.
Here is another scenario in which only two bars are displayed in same width, Which looks odd.
For this situation I need to adjust the width of charts according to the number of bars, so that my chart will look pretty.
Here is the part of my script
var width = ??; // Here how should I calculate width based on the number of bars?
redrawCustomerCodeBarChart
.width(width)
.height(400)
.margins({top: 10, right: 10, bottom: 70, left: 30})
.dimension(customerNamer)
.group(customerNameGroupr)
.x(d3.scale.ordinal().domain(newCoh.map(function (d) {return d.customerName; })))
.xUnits(dc.units.ordinal)
.elasticY(true)
.renderHorizontalGridLines(true)
.on('renderlet',function(chart){
chart.selectAll("g.x text")
.attr('dx', '-15')
.attr('transform', "rotate(-55)");
})
.on('filtered.monitor', function(d) {
// return d.key + ' (' + d.value + ')';
if(d.value !== undefined)
size= d.value;
})
.controlsUseVisibility(true);
In most dc.js charts, the data is read from group.all(). So the number of bars is simply
customerNameGroupr.all().length
and then multiply appropriately.
If the number of bars may change as stuff is filtered (using remove_empty_bins for example), then you'd want to set the width prior to each redraw:
chart.on('preRedraw', function(chart) {
chart.width(chart.group().all().length * BAR_WIDTH);
});
That might be messy though.

How can i change the range of the y Axis - dc.js composite Linechart

Some Informations:
I have a composite Linechart.
And my Question is:
Im using elasticY but my axis beginns at 0 but my smallest value can be 250.
Is there a chance to start the Y Axis from 250 and not from 0 ? But the dynamic Y axis should work (elasticY)
var compositeAvg = dc.compositeChart("#avgline-chart");
compositeAvg.width(1500).height(375)
.group(filtered_group)
.brushOn(true)
.yAxisLabel("Morbalwait AVG ")
.x(d3.scale.ordinal()) //x axis
.xUnits(dc.units.ordinal)
.margins({ top: 10, left: 50, right: 10, bottom: 50 })
.elasticY(true)
.elasticX(true)
._rangeBandPadding(1)
.compose(composeLines())
.legend(dc.legend().x(1425).y(0).itemHeight(13).gap(1));
have you tried .y(d3.scale.linear().domain([250, yourmaxvalue]))

How to fix the height of each bar on a rowChart?

I have a rowChart that can have more or less bars based on what you filter on other graphs.
The problem is that if I set the height of the graph to e.g. 500, if I have 50 bars they will be 10px height but if I have only one, it will be 500px
var graph = dc.rowChart (".graph")
.margins({top: 0, right: 10, bottom: 20, left: 10})
.height(300)
.width(200)
.gap(0)
.x(d3.scale.ordinal())
.elasticX(true)
.ordering(function(d){return -d.value})
.dimension(dim)
.group(filteredGroup);
The group will return the top 10, but if you filter (using other graphs, you might have as low as a single item. In that case, that bar is 300px height and it looks not good (and in general, having the height change that much is not pleasant IMO).
Is there a way to leave the height of the graph flexible but the height of each bar fixed?
So to say that each bar has a height of 30, but the height of the graph is going to adjust from 30 to 300.
According to the latest documentation for DC row charts:
.fixedBarHeight([height])
Get or set the fixed bar height. Default is [false] which will
auto-scale bars. For example, if you want to fix the height for a
specific number of bars (useful in TopN charts) you could fix height
as follows (where count = total number of bars in your TopN and gap is
your vertical gap space).
Example:
var chartheight = 500;
var gap = 5;
var count = 20;
var spaceForScales = 70;
c.fixedBarHeight((chartheight - (count + 1) * gap - spaceForScales) / count);

Resources