I have few bar charts in my dashboard where i'm displaying labels on top of the bar. My users requesting to have thousand seperators for the labels.
The reason is the numbers are like over 7 digits and more for each bar.
Is there any workaround to achieve this functionality?
Here is my code:
Chart
.width(1700)
.height(200)
.margins({top: 5, left: 40, right: 20, bottom: 30})
.transitionDuration(1000)
.dimension(dateDim)
//.formatNumber(d3.format(","))
.group(dateGroup)
.renderLabel(true)
.brushOn(true)
.elasticY(true)
//.centerBar(true)
//.x(d3.time.scale().domain([minDate,maxDate]))
.yAxisLabel("Trades per day")
.xAxisLabel("Days")
.ordinalColors(['#215979'])
.x(d3.time.scale().domain([minDate, d3.time.day.offset(maxDate, 1)]))
.yAxis().tickFormat(d3.format('s'));
Chart.xUnits(function(){return 30;});
Chart
.on("postRedraw", function(chart, filter){
window.globalActiveFilters.SelectedTradeCount=chart.filters().join(",")
});
The labels on top of the bars are controlled by .label().
In the case of bar charts, the default behavior is overridden to use the total Y value of the stacked bar:
_chart.label(function (d) {
return dc.utils.printSingleValue(d.y0 + d.y);
}, false);
(source link)
You can specify your own label accessor which uses d3.format as suggested by #REEE, supplying it the total stacked value:
.label(d => d3.format(',')(d.y0 + d.y1))
Example fiddle.
Use d3-format, you can find the relevant docs here: https://github.com/d3/d3-format
Example use case (as shown in link above):
d3.format(",")(20000)
-> "20,000"
d3.format(",")(200000000)
-> "200,000,000"
Related
Using bar chart:
actionsChart /* dc.barChart('#volume-month-chart', 'chartGroup') */
.width(actionsWidth)
.height(240)
.margins({top: 10, right: 50, bottom: 30, left: 40})
.dimension(dateDimension)
//...
.elasticX(true)
.elasticY(true)
.gap(1)
.alwaysUseRounding(true)
.x(d3.time.scale().domain( [ minDate, maxDate ] ) )
.round(d3.time.day.round)
.xUnits(d3.time.days)
.renderHorizontalGridLines(true)
//.xAxisLabel( 'Dan')
//.xAxisPadding(2)
.xAxisLabel( "Datum")
//.yAxisLabel( "Akcije" ) // OK, but already in title
.xAxisPadding(1)
//nok in dc: //.tickFormat(d3.time.format("%Y-%m-%d"))
//.label( function(d){ return JSON.stringify(d); })
;
It gets Label on x-axis unreadable (too much characters next to each other.
How to put label each 5 or 7 days, and customize format (day in month number, no week day) ?
Thank you.
dc.js mostly uses d3v3's d3.svg.axis to draw its axes.
You may be looking for d3.svg.axis.ticks() and d3.svg.axis.tickFormat().
You can get at the d3 axis object that dc.js uses by calling chart.xAxis() but I advise doing it in a separate statement from your other chart initialization because it gets confusing when you you chain function calls but they return different objects.
So, something like (untested):
chart.xAxis()
.ticks(d3.time.days, 7)
.tickFormat(d3.time.format('%e'));
d3v3 time formatting specifiers
If you can't get the automatic tick generator to do what you want, you can always specify the exact list of ticks using .tickValues(). You'd want to do this before each render and redraw, so (again, untested):
function calc_ticks(chart) {
var ticks = d3.time.weeks(chart.xAxisMin(), chart.xAxisMax()); // or days(chart.xAxisMin(), chart.xAxisMax(), 5)
chart.xAxis().tickValues(ticks);
}
chart.on('preRender', calc_ticks)
.on('preRedraw', calc_ticks);
I have chart with next properties:
barChart
.width(width)
.height(height)
.dimension(dim)
.group(group)
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
My axis tick looks like "ZZxBob", "PxBob"
How to use split function by 'x' to each tick?
The axes are generated entirely by D3.
You can use chart.xAxis() to retrieve the x axis object, and then axis.tickFormat() to change the way it's displayed.
So, e.g. to display the part before x:
barChart.xAxis()
.tickFormat(function(l) { return l.split('x')[0]; })
I would like to create a bar chart based on dates in x-axis. Labels should be displayed as month (i.e. Jan, Jan'17 - preferred). Within my data I have always first date of following months, i.e. 01Jan, 01Feb, 01Mar. I have created a chart but I am not able to make it aligned.
var chart = dc.barChart("#" + el.id);
var chCategory = ndx.dimension(function(d) {return d[chCategoryName];});
chValues = chCategory.group().reduceSum(
return parseFloat(d[chValueName]);});
//set range for x-axis
var minDate = chCategory.bottom(1)[0][chCategoryName];
var maxDate = chCategory.top(1)[0][chCategoryName];
chart
.width(800)
.height(200)
.x(d3.time.scale().domain([minDate,maxDate]))
.xUnits(d3.time.months)
.dimension(chCategory)
.group(chValues)
.renderHorizontalGridLines(true)
// .centerBar(true) //does not look better
.controlsUseVisibility(true)
.ordinalColors(arrColors)
.transitionDuration(1000)
.margins({top: 10, left: 80, right: 5, bottom: 20})
I have already read post: dc.js x-axis will not display ticks as months, shows decimals instead
but I am not able to implement it in a way that will keep correct sorting for different years.
dc.js takes the domain pretty literally - the x axis stretches exactly from the beginning to the end, disregarding the width of the bars or their placement. It's a design bug.
Here are two workarounds.
keep bars centered and add padding
If you're using elasticX you can manually correct it like this:
chart.centerBar(true)
.xAxisPadding(15).xAxisPaddingUnit('day')
If you're just setting the domain manually, that's
minDate = d3.time.day.offset(minDate, -15);
maxDate = d3.time.day.offset(maxDate, 15);
align the ticks to the left of bars and correct the right side of the domain
You don't say what problem you run into when you don't center the bars. But I know the right bar can get clipped.
If you want the elasticX effect, you can implement it manually like this, offsetting the right side by a month (example):
function calc_domain(chart) {
var min = d3.min(chart.group().all(), function(kv) { return kv.key; }),
max = d3.max(chart.group().all(), function(kv) { return kv.key; });
max = d3.time.month.offset(max, 1);
chart.x().domain([min, max]);
}
chart.on('preRender', calc_domain);
chart.on('preRedraw', calc_domain);
Or without elasticX that's just:
maxDate = d3.time.month.offset(maxDate, 1);
I am working on dc.js, i have draw pieChart
pieChart.width(300)
.height(200)
.transitionDuration(1500)
.dimension(startValue)
.group(startValueGroup, "StartValue")
.radius(100)
.minAngleForLabel(0.5)
.legend(dc.legend().x(230).y(0))
.title(function(d) {
return d.key + ": " + d.value;
})
.renderTitle(true)
.on("filtered", function (chart) {
dc.events.trigger(function () {
//console.log(total_payment);
});
});
Now, I want to set specific x axis value. Currently, pieChart taking center position of define width and height. That mean it's taking position of (150,100). I want to change this position to (100, 100).
How can i change position of x axis as per above code?
You can't set this directly in the dc options, but you can modify these values after the chart has been rendered. Assuming that "pie" is the ID of the DOM element that you rendered the pie chart into, you can do
d3.select("#pie > svg > g").attr("transform", "translate(100,100)");
I know it is an old post and that the answer works perfectly but when the chart is part of a bigger system (several charts) I found easier to add the above command directly to the chart by doing this:
pieChart.on('renderlet', function (chart) {
chart.select("svg > g").attr("transform", "translate("100,100)");
});
Edit:
Actually I just found out you can do:
.cx(100)
.cy(100)
which will set the centre of the pie chart to 100, 100 before render.
Is it possible, using dc.js, to construct a bar chart where the stacks are not placed on top of each other? Currently, my code produces charts that look like this:
Instead I'd like each of the stack bars to start from y axis and not from the value where the previous stack value ends. This may/will lead to the bars overlapping, so perhaps adding transparency will help here. A simple css rule will probably work here:
.dc-chart rect.bar { opacity: 0.75; }
You likely want to build a composite chart that includes a bar chart for each category.
You can build a group for each color in your chart like this:
usaGroup = categoryDimension.group().reduceSum(dc.pluck('usa')),
russiaGroup = categoryDimension.group().reduceSum(dc.pluck('russia'));
Here is a jsFiddle to demsonstrate this: http://jsfiddle.net/djmartin_umich/nK6K7/
composite
.width(400)
.height(300)
.x(d3.scale.ordinal().domain([1,2,3]))
.xUnits(dc.units.ordinal)
.yAxisLabel("User Count")
.renderHorizontalGridLines(true)
.compose([
dc.barChart(composite)
.centerBar(true)
.gap(100)
.colors('red')
.dimension(categoryDimension)
.group(russiaGroup),
dc.barChart(composite)
.centerBar(true)
.gap(100)
.colors('blue')
.dimension(categoryDimension)
.group(usaGroup)])
.brushOn(false)
.render();
You'll need to play around with the styling... the blue and red combine into a purple color when the opacity is lowered.