Setting pie chart colors using d3.js - javascript

I'm having issues setting pie slice colors using a d3.pieChart. Documentation and examples I've seen use the colors method in combination with an array of hex colors. However, setting this results in my pie chart being colored white (invisible) and every item in the legend becoming black.
I've tried using .colors with an array of five and an array of six colors but the issue persists. Could this be due to some issue with the slicesCap?
Code snippet below, but category10 burns my eyes so any advice on implementing a custom color set would be appreciated!
pie
.slicesCap(5)
.legend(dc.legend().gap(3))
.colors(d3.scale.category10())

Just passing an array of colour values doesn't work because the .colors() function is expecting a color scale like the one created by d3.scale.category10(). Scales are functions which take input data and return a value; in this case, the returned value is one of 10 colours.
For starters, you could try one of the other d3 built-in colour scales, which don't have as extreme contrast:
https://github.com/mbostock/d3/wiki/Ordinal-Scales#wiki-category20
If none of those suit, you can make your own scale function with
var colorScale = d3.scale.ordinal().range([/*array of hex values */]);
pie.colors(colorScale);
You can create the array yourself or use one of the colorBrewer functions.
If you want to specify particular colours for particular values (instead of just assigning the colours to values in the order they appear) you'll need to (a) specify the domain of the scale as an array of values that matches the order of the range array, and (b) create a helper function that passes in the correct property from your data:
var colorScale = d3.scale.ordinal().domain(["banana", "cherry", "blueberry"])
.range(["#eeff00", "#ff0022", "#2200ff"]);
pie.colors(function(d){ return colorScale(d.fruitType); });

You can assign colors to particular values like this.
var colorScale = d3.scale.ordinal()
.domain(["banana", "cherry", "blueberry"])
.range(["#eeff00", "#ff0022", "#2200ff"]);
pie.colors(colorScale.range())
.colorAccessor(function(d){ return colorScale.domain().indexOf(d.fruitType); });
This solution is a little bit hacky, but I couldn't get it to work using only chart.colorDomain, and calling a function in chart.colors seems to be throwing errors now.

Riffing off Tayden's answer, there is slightly different syntax for newer versions of d3 (i.e. "scaleOrdinal")
var colorScale = d3.scaleOrdinal()
.domain(["banana", "cherry", "blueberry"])
.range(["#eeff00", "#ff0022", "#2200ff"]);

Related

Dynamic colours in chartJS based on entries in the array

I have an issue trying to color my bar chart dynamically based on a JSON response.
I know this has been asked a number of times before but none of the answers I've found or tried to work thorugh have got me any closer to a solution.
I've created a quick JSfiddle to show the issue.
I have a number of other charts which are all generated from different JSON strings so have cut this down a lot to try and isolate the issue. I don't have the same problem with the other charts as the number of entries in the Label array in consistent with the number of colours. The offending piece of code is this;
DT_Labels.forEach(function(DT_LABELS, x) {
data.datasets.push({
label: DT_LABELS,
backgroundColor: backgroundColor[x],
data: JSON.parse(DT_Values[x]).map(Number)
});
});
DT_Labels only contains a single entry as the chart is a summarised list - In theory, this would work if I counted the number of DT_Values but if I do that, I can't get the correct data in the chart.
Any ideas how I can reformat this to generate the colours counter based on the number of Values instead of Labels?
Change:
backgroundColor: backgroundColor[x],
to:
backgroundColor: backgroundColor,
Result:
Why does this work?
The backgroundColor property can be specified in a number of ways. Typically it's set to a string, e.g. #abcdef but it can also be set to an array. In this case Chart.js itself will pick the colour from the array based on the index of the data point it is drawing.

Drawing linear chart without gaps in Chart.js

I want to draw a linear chart of currency rates. There are some days when there are no rates from the market (holidays). I would like to remove these days from the chart but without ugly gaps or straight lines between the days with rates.
You can see an example on this chart:
On 3rd of May there is no data, the chart is linked and the missing date is removed from the legend.
How do I get such effect using Chart.js?
I figured out a workaround. It requires some hacking but it works:
1) First, modify your dataset. Iterate over all your points and mutate x values so that they correspond to new position on your chart. Save the original x value in some property for future use (in tooltips)
2) Now you can draw the data on the chart and they look properly. The problem is with tooltips and ticks.
How to deal with the ticks:
The ticks are a list of mutated numbers (they don't correspond to their original values). You have utilize a hack. Temporarily overrite chartController.ticks in afterBuildTicks method with array of objects (instead of plain numbers) with original corresponding x values. You have to approximate original x value for every tick.
Having that you can use this information in ticks callback to return correct labels for ticks.
With such mutated data the chart won't plot. You have to revert it to the state before mutation. In the method afterTickToLabelConversion restore the ticks. Bear in mind that now they are stored in property ticksAsNumbers
The similar hack should be done with tooltips callbacks. You have access to the dataset and utated x value. Approximate original x value for mutated x and that's it.
You can use the spanGap attribute. From the documentation:
If [spanGaps is set to] true, lines will be drawn between points
with no or null data. If false, points with NaN data will create a
break in the line

Plot within a tooltip in d3.js

I would like to create a d3-based plot which graphs a plot within a tooltip. Unfortunately, I haven't found any examples on the web. Here is a sample JSON file.
[{"x":[0.4],
"y":[0.2],
"scatter.x":[0.54,0.9297,0.6024,-1.9224,2.2819],
"scatter.y":[0.4139,1.1298,-0.1119,2.3624,-1.1947]},
{"x":[0.1],
"y":[0.9],
"scatter.x":[-0.8566,-0.5806,-0.9326,0.8329,-0.5792],
"scatter.y":[-0.5462,-0.7054,1.0264,-3.4874,-1.0431]}]
The idea is to have a scatter plot for (x,y) coordinates first. However, when one mouses over a point, a different scatter plot within a tooltip appears based on [scatter.x, scatter.y] coordinates for that respective point.
I can do the scatter plots separately but have been struggling to put them together. Could anyone shed some light on this and/or provide a minimal example?
This was too long for a comment but I'm not certain if it's the answer you were looking for. One of the issues you might find is that your nested data is formatted differently-- one uses JSON objects with x and y, while the other uses two arrays of points.
My solution to this would be to create an extensible function:
function makeScatterPlot(elem, width, height, data, fill)
elem, width, height, and data are the core parameters: which element to attach the chart to, the size of the chart, and the data for the chart (in the JSON object format).
This function would generate all necessary items for the chart and add the chart to the provided element.
Then you want to bind to mouseover of your main chart, and in that function you'll have to do a bit of data modification to re-organize the two arrays into the JSON object structure.
function mainMouseover(d){
var newData = [];
for (var i = 0; i < d["scatter.x"].length; i++){
var t = {x: [0], y: [0]};
t.x[0] = d["scatter.x"][i];
t.y[0] = d["scatter.y"][i];
newData.push(t);
}
var newG = mainG.append("g").attr("transform", "translate(200,200)");
makeScatterPlot(newG, 100,100, newData, "red");
}
Of course, you would modify the translate to match wherever you want your tooltip to be.
Putting this all together you get the following (very crude) fiddle. Hover over either of the black dots to see the sub-chart. Obviously this needs quite a bit of work to be a solid example (i.e. remove the sub-chart on mouseout), but hopefully it will set you in the right direction.
If the tooltip chart is significantly different styling-wise compared to your main chart it may not be the best idea to use an extensible function, and you could just create another custom function instead.

How do I get data from a rectangle in D3?

I have this mock up of something I'm working on at the moment :
http://jsfiddle.net/Qh9X5/5760/
Basically I've created 3 rectangles with 3 circles on top, in my own work there's around 80. What I want to do is compare these rectangles to check which ones have the same number.
I've worked with the nodes in force layout so normally I would go through them like so :
rectangles.forEach(function(e){
console.log(e.Number) // to get that rectangles number
var compareRect = rectangles.filter(function(n){ return n.Number === e.Number});
if(e.Connect === compareRect.Connect){
//colour corresponding circles green
}
else{
//colour corresponding circles red
}
});
I can't even log to console as this gives me undefined.
I want to get at the rectangles data so I can first compare their Number, then once the numbers are the same, check if the 'Connect' value is the same. If it is, then colour the circles on both the same numbered rectangles Green, if the 'Connect' value is different, then colour the circles Red.
Hope this makes sense, basically I can't get hold of the data for any of the rectangles I have created. Thanks for your time :)
Please note, that your variable rectangles is a d3 selection which is a two-dimensional array containing grouped references to your rects. You are, however, using Array.prototype.forEach() to iterate over the the array.
rectangles.forEach(function(e){
console.log(e.Number) // to get that rectangles number
});
While being technically and syntactically correct, this won't give you the expected behaviour. To iterate over your rectangles you should use selection.each(function) instead:
rectangles.each(function(e){
console.log(e.Number) // to get that rectangles number
});
See this working JSFiddle.

D3 bar chart from objects with arrays

Good afternoon.
I am using this D3 bar chart example with my data (that is in the same format whereof in the
jsfiddle example).
The chart works well but i have some problems that i do not know i solve.
The xAxis have the number of index of the key parameter and not the key parameters values;
When I sort the data after pressing the "sort" button;
The numbers over the bars after the sort disappear or appear the the left side insted of over the correspondent bars
var dataset = {key: [0, 30], value:[60, 30]};
http://jsfiddle.net/3HL4a/75/
Here is the link where you can see the code and perform the changes.
Thanks
To reference the key values, you have to use those instead of the index:
var xScale = d3.scale.ordinal()
.domain(dataset.key)
.rangeRoundBands([0, w], 0.05);
// ...
.attr("x", function(d, i) {
return xScale(dataset.key[i]);
})
You can make this nicer by merging the key and value arrays such that both are part of the same data element.
As for the other problem, this is because you're selecting text elements, which include the axis labels. Even with the key function this doesn't work here, as one of the axis labels is the same as the label you want to display on the bar. Assigning a special class to these labels and selecting accordingly fixes this.
See here for the complete jsfiddle.

Categories