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.
I have quite a long period of observations (tornadoes) 800-2016 (about 2000 inputs). To visualize them on one bar chart I use mouseZoomable (true) function for DC.js but it starts to mess filtering: User can't properly select interval on the chart, it slips all the time and seems as asynchronized.
Sorry I am very new to D3 and DC.js and couldn't find an answer.
Here is my code:
var ndx = crossfilter(records);
var YearDim = ndx.dimension(function(d) { return d["Year"]; });
var numRecordsByYear = YearDim.group();
var minYear = YearDim.bottom(1)[0]["Year"];
var maxYear = YearDim.top(1)[0]["Year"];
var timeChart = dc.barChart("#time-chart");
timeChart
.width(600)
.height(140)
.margins({top: 10, right: 50, bottom: 40, left: 40})
.dimension(YearDim)
.group(numRecordsByYear)
.transitionDuration(500)
.mouseZoomable(true)
.x(d3.time.scale().domain([minYear, maxYear]))
.zoomOutRestrict([true])
.elasticY(true)
Will be very gratefull for helping or suggesting another way to visualize long and irregular time interval.
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?
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
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)
;