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 three charts rendering using dc.js and all of them render a black area below or above the line. I looked through the dc.css file for any fill options that were relevant, but I couldn't find any that had a positive effect.
I', using Angular 7 as the framework to develop my application.
Json Data is in this form and has a few different device types:
{
device_ID: "DHT11-3fe381"
device_type: "thermometer"
time: "2019-02-26T00:56:54.000Z"
value: 25.9
}
I use crossfilter to create a timeDim dimension and sort each value according to device_type:
const timeDim = ndx.dimension((d) => d.time);
var Thermo = timeDim.group().reduceSum((d) => {
if (d.device_type === 'thermometer' && d.value <= 40) {
return d.value;
} else {
return 0;
}
});
Then, I create my graphs:
const DTchart = dc.compositeChart('#graphT');
DTchart
.width(800)
.height(300)
.margins({top: 10, right: 50, bottom: 100, left: 60})
.dimension(timeDim)
.group(device, 'value')
.xUnits(d3.timeMinutes)
.x(d3.scaleTime().domain([bottomDate, topDate]))
.yAxisLabel('Thermometer reading')
.xAxisLabel('Time')
.brushOn(false)
.elasticX(true)
.elasticY(true)
.controlsUseVisibility(true)
.renderHorizontalGridLines(false)
.compose([
dc.lineChart(DTchart)
.dimension(timeDim)
.renderArea(false) // This didn't contribute anything
.colors('RED')
.group(Thermo)
.valueAccessor((d) => d.value)]
);
The default for an SVG path element, which is used for line charts, is to display filled in black,
If you include dc.css it will set fill: none. The axis font will fit better and the axis lines will be narrower too.
You didn't ask, but I think the vertical red lines are due to zeros in your data. If data is missing you could consider using lineChart.defined to put gaps in your lines instead of dropping to zero.
I've a bubble chart built using dc.js in which the texts are not shown on the bubbles. Also, is there is a way to rotate the text on the bubbles.
Here is my code.
wfAvgChartBubble
.width(658)
.height(400)
.margins({top: 10, right: 50, bottom: 30, left: 60})
.dimension(wfStatusNameAvgDimBubble)
.group(wfStatusNameAvgGroupBubble)
.colors(d3.scaleOrdinal(d3.schemeCategory10))
.keyAccessor(function (p) {
return p.value.total;
})
.valueAccessor(function (p) {
return p.value.avg;
})
.radiusValueAccessor(function (p) {
return p.value.avg;
})
.x(d3.scaleBand().domain(data.map( function(d) {
return d['workflow_status_name'];
}
)))
.xUnits(dc.units.ordinal)
//.x(d3.scaleLinear().domain([0, 5000]))
.r(d3.scaleLinear().domain([0, 9000]))
.minRadiusWithLabel(15)
.elasticY(true)
.yAxisPadding(150)
.elasticX(true)
.xAxisPadding(300)
.maxBubbleRelativeSize(0.07)
.title(function (p) {
return p.key
+ "\n"
+ "Total Records: " + p.value.total + "\n"
+ "Average Time Taken: " + p.value.avg;
})
.render();
I need to print the text on each bubble
showing all the labels
It would be easier to test this with a running example, but I think your problem is this line:
.minRadiusWithLabel(15)
From your screenshot (thanks!) it looks like the big bubble has its label (which defaults to the key) but the labels are missing on the smaller bubbles. Try
.minRadiusWithLabel(0)
to display labels no matter what size the bubble.
(minRadiusWithLabel docs)
rotating the text
Since the text transform isn't driven by the data, it's best just to use CSS to change it, unless you need to change them individually.
Here's a reference to some of the relevant dc.js selectors.
From there we can infer a CSS rule like
g.node text {
transform: rotate(-45deg);
}
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.!
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?