DC.js - Custom ordering of ordinal scale line chart - d3.js

Please forgive my english.
I am trying to create a line chart with ordinal scale and brushon function. I successfully set brushing on ordinal thanks to this method :
https://dc-js.github.io/dc.js/examples/brush-ordinal.html
And now I need to set the x-axis values order.
My data is like this :
[{"id_commune":4,"datation":"-30/-20","effectif":0.09,"commune":"Frejus","lieu_dit":"Les Aiguieres","departement":"83","pays":"FR","longitude":6.73703399,"latitude":43.433152,"quantite":1,"id_datation":1},
{"id_commune":4,"datation":"-20/-10","effectif":0.09,"commune":"Frejus","lieu_dit":"Les Aiguieres","departement":"83","pays":"FR","longitude":6.73703399,"latitude":43.433152,"quantite":1,"id_datation":2},
{"id_commune":4,"datation":"-10/1","effectif":0.09,"commune":"Frejus","lieu_dit":"Les Aiguieres","departement":"83","pays":"FR","longitude":6.73703399,"latitude":43.433152,"quantite":1,"id_datation":3},
{"id_commune":7,"datation":"20/30","effectif":0.33,"commune":"Nimes","lieu_dit":"Solignac","departement":"30","pays":"FR","longitude":4.36005399,"latitude":43.836699,"quantite":1,"id_datation":6},{"id_commune":6,"datation":"20\/30","effectif":0.6,"commune":"Muralto","lieu_dit":"Liverpool b","departement":"TI","pays":"CH","longitude":8.80560809,"latitude":46.1729618,"quantite":1,"id_datation":6},
{"id_commune":4,"datation":"20/30","effectif":0.09,"commune":"Frejus","lieu_dit":"Les Aiguieres","departement":"83","pays":"FR","longitude":6.73703399,"latitude":43.433152,"quantite":1,"id_datation":6},{"id_commune":1,"datation":"20/30","effectif":0.14,"commune":"Aislingen","lieu_dit":"NP","departement":"Lkr. Dillingen an der Donau BY","pays":"DE","longitude":10.4559987,"latitude":48.5065603,"quantite":1,"id_datation":6},]
My crossfilter dimension and group look like this :
var ndx = crossfilter(records)
var graphDim = ndx.dimension(function(d) {return d.datation});
var graphGroup = graphDim.group().reduceSum(function(d) {return d.effectif;});
And the chart :
lineChart
.width(950)
.height(350)
.margins({top: 10, right: 50, bottom: 35, left: 30})
.dimension(graphDim)
.keyAccessor(function(kv) { return graphGroup.ord2int(kv.key); })
.group(graphGroup)
.x(d3.scaleLinear().domain(linear_domain))
.xAxisLabel("Chronologie")
.yAxisLabel("Effectif")
.brushOn(true)
.renderArea(true)
.renderHorizontalGridLines(true)
.renderVerticalGridLines(true)
.elasticY(true)
.yAxis().ticks(4);
Right now, I get this :
The result I am trying to accomplish is the same chart but with x-axis ticks values ordered like this :
"-30/-20
-20/-10
-10/1
..."
Any help appreciated. Thank you!

Welcome to Stack Overflow. For future reference, it helps if you can include a reproducible example, for example a jsFiddle.
I understood what you were doing because I wrote the ordinal brushing example, but you didn't include all the code, so it wouldn't be clear to others.
Here is a fiddle with complete code, and here is the relevant code:
var graphDim = ndx.dimension(function(d) {return d.datation});
var graphGroup = graphDim.group().reduceSum(function(d) {return d.effectif;});
graphGroup = ordinal_to_linear_group(sort_group(graphGroup, function(a, b) {
return d3.descending(a.value, b.value);
}));
line = dc.lineChart('#line');
var linear_domain = [-0.5, data.length - 0.5];
line
.width(950)
.height(350)
.margins({top: 10, right: 50, bottom: 35, left: 30})
.dimension(graphDim)
.keyAccessor(function(kv) { return graphGroup.ord2int(kv.key); })
.group(graphGroup)
.x(d3.scaleLinear().domain(linear_domain))
.xAxisLabel("Chronologie")
.yAxisLabel("Effectif")
.brushOn(true)
.renderArea(true)
.renderHorizontalGridLines(true)
.renderVerticalGridLines(true)
.elasticY(true)
line.yAxis().ticks(4);
line.xAxis()
.tickValues(d3.range(data.length))
.tickFormat(function(d) { return graphGroup.int2ord(d); });
Here is the (bad) result:
As its name implies, sort_group() creates a fake group sorted by the ordering function. Right now it's sorting by value, from highest to lowest:
sort_group(graphGroup, function(a, b) {
return d3.descending(a.value, b.value);
})
It looks like you want to sort by the numeric value of the first part of each key. You can change the sort accordingly:
sort_group(graphGroup, function(a, b) {
return d3.ascending(+a.key.split('/')[0], +b.key.split('/')[0]);
})
This splits each key by /, then takes the first item ([0]), then converts it to a number (+), before using d3.ascending to specify sorting from low to high.
The result:
And a working version of the fiddle.

Related

set row chart labels outside the bar like a barchart in Dc.js?

How can I have the labels outside the bar in a row chart with dc.js?
I'd like a graph like this:
however, the labels are inside the actual bars... is there any settings i need to change to have it like this?
I finally got this working and here is the trick,
As mentioned by the Gordon it can be done on renderlet.
First I have gave the margin for my row chart ,
.margins({ top: 20, right: 20, bottom: 40, left: 110 })
Then took the label outside by giving x value in negative.
.labelOffsetX(-10)
This will perfectly move our label but its still need some style changes to look fine and that need to be done on renderlet,
.on('renderlet', function (chart) {
chart.selectAll("g.row text")
.style("text-anchor", "end")
.call(function (t) {
t.each(function (d) {
var self = d3.select(this);
var text = self.text();
if (text.length > 14) {
self.text('');
text = text.substring(0, 14) + '..';
self.text(text);
}
})
});
})
You can ignore .call() function as I place this just to make sure my label length does not cross certain limit.
Hope that work for you.!

DC - Can geoChoroplethChart be combined with bubbleOverlay?

This example (http://dc-js.github.io/dc.js/crime/index.html) looks great but the path elements and SVG for the map of Canada have been defined manually. I'd like to draw a world map with geoChoroplethChart and then add a bubbleOverlay.
I've tried them separately and recently tried a compositeChart approach:
compositeChart.width(1440)
.height(500)
.margins({top: 10, right: 50, bottom: 30, left: 60})
.compose([
dc.geoChoroplethChart("#us-chart")
.dimension(countries)
.projection(projection)
.group(countryValue)
.colors(d3.scale.category10())
.colorDomain([0, 3])
.colorCalculator(function (d) { return d ? geoChart.colors()(d) : '#ccc'; })
.overlayGeoJson(statesJson.features, "state", function (d) {
return d.properties.name;
}),
dc.bubbleOverlay("#us-chart")
.svg(d3.select("#us-chart svg"))
.dimension(countries)
.group(countryValue)
.radiusValueAccessor(function(p) {
//console.log(p);
return p.val;
})
.r(d3.scale.linear().domain([0, 4]))
.point("Angola",200,200)
])
dc.renderAll();
I have a sneaky feeling compositeChart will only work with charts based on a grid system, like line and bar charts. Is this right? In which case, is there a way to add a bubbleOverlay to a choropleth in DC, without doing it manually?

dc.js - How set brush (with specific width) to barChart on load

On load i see this, all data set without filters:
Picture: what i have
I want to see this, brush(selector) picked last 21 day already on load:
Picture: what i want
Solved! click for answer
Here i saw similar question, but not works for me
dc.js - is it possible to show the user grab handles upon page load
var lineChart = dc.lineChart(".chart-line-graph");
var dateRangeChart = dc.barChart('.chart-date-range');
var hourDim = ndx.dimension(function(d) {return d.hour;});
var valueByHour = hourDim.group().reduceSum(function(d) {return d.value;});
var minDate = hourDim.bottom(1)[0].date;
var maxDate = hourDim.top(1)[0].date;
lineChart
.renderArea(true)
.width(1360)
.height(350)
.transitionDuration(200)
.margins({top: 30, right: 50, bottom: 45, left: 80})
.dimension(hourDim)
.mouseZoomable(true)
.rangeChart(dateRangeChart)
.brushOn(false)
.x(d3.time.scale().domain([minDate,maxDate]))
.elasticY(true)
.group(value)
.renderHorizontalGridLines(true);
var dayDim = ndx.dimension(function (d) {return d.day;});
var groupByDayDim = moveDays.group();
dateRangeChart
.width(1360)
.height(35)
.margins({top: 0, right: 50, bottom: 20, left: 80})
.dimension(moveDays)
.group(volumeByMonthGroup)
.centerBar(false)
.gap(1)
.x(d3.time.scale().domain([minDate,maxDate]))
.round(d3.time.week.round)
.alwaysUseRounding(true)
.xUnits(d3.time.days);
dateRangeChart
.yAxis().ticks(0);
If i add this:
lineChart
.filter(dc.filters.RangedFilter(d3.time.day.offset(xrange[1], -21), d3.time.day.offset(xrange[1], 1)))
Then barChart are filtered, but not selected
I solved my first problem!
Just added filter after all code (after renderAll()) and then call redrawAll()
Screenshot, how it looks like for now, on load charts

Problems with .x() in dc.js barCharts

I am doing my first interactive visualization using dc.js. I have come to a hard stop over a dc.barChart() attribute that I cannot seem with the answers I find here og on google. I will start the code from the crossfilter()function. I am able to create dc.rowCharts() so I highly doubt that it is a malformed .json problem
var ndx = crossfilter(salgsTransaksjonene);
//Define Dimensions
var kundeDim = ndx.dimension(function(d) { return d["CustomerName"]; });
//Calculate metrics
var OmsetningKunder = kundeDim.group().reduceSum(function(fact) { return fact.TotalAmount;});
//Charts
var toppChart = dc.barChart("#topp-20-bar-chart");
toppChart
.width(950)
.height(240)
.margins({top: 10, right: 50, bottom: 30, left: 50})
.dimension(kundeDim)
.group(topp20OmsetningKunder)
.transitionDuration(500)
.elasticY(true)
.yAxis().ticks(4)
When it comes to the .x() attribute I have tried the following
// .isOrdinal(true)
// .xUnitCount(20)
.xUnits(dc.units.ordinal.domain(salgsTransaksjonene.map(function (d) {return d.CustomerName; })))
.x(d3.scale.ordinal());
// .isOrdinal(true)
// .xUnitCount(20)
.xUnits(dc.units.ordinal)
.x(d3.scale.ordinal());
The errors I get is mostly the same; Uncaught TypeError: undefined is not a function
and various combinations of the above attributes, but to no avail. Any Ideas about what could be wrong is greatly appreciated!
Try to add a .domain with your ordinal values like this.
Also I've seen the order of the declarations to be of importance.
.x(d3.scale.ordinal().domain(['cat1','cat2','cat3']))
.xUnits(dc.units.ordinal)
here is a full working barchart for your inspiration.
chart11
.width(xxx)
.height(xxx)
.margins(xxx)
.dimension(xxx)
.group(xxx)
.x(d3.scale.ordinal().domain([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
.xUnits(dc.units.ordinal)
.centerBar(false)
.transitionDuration(transitionDuration)
.elasticY(true)
.gap(1)
.renderHorizontalGridLines(true)
.yAxis().ticks(2)
;

Multibar chart(nvd3) x axis label in not centered

Using nvd3 multibar chart. When having minimum bars x axis label does not display in center like y axis.
Sample code to generate x axis label.
chart = nv.models.multiBarChart().margin({
top: 30,
right: 28,
bottom: 50,
left: 60
})
.x(function(d) {
return d.x
})
.y(function(d) {
return d.y
})
.color(d3.scale.myColors().range());
chart.xAxis
.showMaxMin(true)
.axisLabel(xAxisLabel)
.tickFormat(xAxisTickFormat)
.tickValues(xaxisValues);
How to solve this problem ?
This might sound strange but try swapping the order of axisLabel and showMaxMin like the following :
chart.xAxis
.axisLabel(xAxisLabel) // axisLabel first
.showMaxMin(true)
.tickFormat(xAxisTickFormat)
.tickValues(xaxisValues);
Hope it helps.
I have used the next workaround. Hope it helps:
var transitions = 0;
d3.select(this.tag + ' svg').transition().each( "start", function() {
transitions++;
}).each( "end", function() {
if( --transitions === 0 ) {
alignaxisCallback();
}
});
function alignaxisCallback(){
var axisWidth = d3.select('.nv-x').node().getBoundingClientRect().width;
d3.select('.nv-x').select('.nv-axislabel').attr('x', axisWidth / 2);
}
Did you try
chart.xAxis.axisLabelDistance(LABEL_OFFSET);
The issue is resolved by updating nvd3 to version 1.8.4 or higher.

Resources