I'm building a data dashboard using DC.js and was wondering if it was possible to change the color of the slices in a pie chart dynamically based on the value in the field it is referring to.
Basically I've built a pie chart aggregating the costume colors of different superheroes and I'd love to be able to color each slice with the color it is referring to - so the slice for 'Black' is colored black, the slice for 'Green' is colored green and so forth.
I'm fairly new to DC.js so accept that it may not be possible, but wanted to throw it out there and see if it could be done!
I tried including an array within .ordinalColors but couldn't figure out if there was a way to pull in the data from the field dynamically. I'm assuming that I'd have to change the data in the .csv file to a string that could be recognised as a color reference, but not sure how to go about doing that.
function show_costume_color(ndx) {
var costume_color_dim = ndx.dimension(dc.pluck('Costume Colour'));
var costume_color = costume_color_dim.group();
dc.pieChart('#costume-color')
.width(500)
.height(500)
.radius(500)
.innerRadius(100)
.slicesCap([7])
.transitionDuration(1500)
.dimension(costume_color_dim)
.group(costume_color);
}
CSV data comes in the below format
ID,name,Gender,Eye color,Race,Hair color,Publisher,Alignment,Superpower,Superpower Strength Level,Costume
Colour
0,A-Bomb,Male,Yellow,Human,No Hair,Marvel Comics,Good,Superhuman
Strength,10,None
1,Abin Sur,Male,Blue,Ungaran,No Hair,DC Comics,Good,Cosmic Power,40,Green
Yes, of course. Everything is specified dynamically in dc.js.
Assuming you are using dc.js v3 (and d3 v4+) the way I would suggest doing this is by creating another CSV file with the color assignments you want, something like
Name, RGB
Red, #ff1122
Blue, #1133ff
...
Then you can load the second file in parallel with your data using Promise.all(),
Promise.all([d3.csv('data.csv'), d3.csv('colors.csv')])
.then(function(data, colors) {
// rest of code will go here
});
ordinalColors is a nice convenience method, but if you want complete control, and to understand exactly what's going on, it's better to supply your own color scale. In this case, we want an ordinal scale, which maps specific discrete values to specific colors.
Under the covers, dc.js always deals with colors by using the colorAccessor to fetch a value for the the item, and then mapping this value using a color scale. You can think of the value that the accessor returns as a "color name", which is pretty convenient because it's exactly what you want here.
So you can populate a d3.scaleOrdinal with the domain of color names and the range of RGB colors:
var colorScale = d3.scaleOrdinal()
.domain(colors.map(row => row.Name))
.range(colors.map(row => row.RGB));
Now supply it to your chart using .colors():
chart.colors(colorScale);
What's really handy about this approach is that you can supply the same color scale for multiple charts, in order to make sure they are consistent. This is something that you don't get automatically in dc.js, because charts don't know very much about each other.
So, I managed to figure it out through an extensive period of trial and error and now I'm off and away with my dashboard. Thanks for your help, Gordon - it really made the difference! It needs a bit of tidying up but my working test code is below.
// Bring in data from both csv files
Promise.all([d3.csv("../data/heroes_information.csv"),
d3.csv("../data/costume_colors.csv")])
.then(function(data) {
// Tidy up data before use
data.forEach(function(d) {
d.Height = +d.Height;
d.Weight = +d.Weight;
d.Strength = +d.Strength;
});
// Bring in colorScale to dynamically color pie chart slices
var ndxcol = crossfilter(data[1]);
var colorScale = d3.scaleOrdinal()
.domain(data[1].map(row => row.Name))
.range(data[1].map(row => row.RGB));
// Bring in superhero data
var ndx = crossfilter(data[0]);
// Define chart types
var publisherSelector = dc.selectMenu('#publisher-selector')
var genderChart = dc.rowChart('#gender-balance');
// Define chart dimensions
var publisherChoice = ndx.dimension(dc.pluck('Publisher'));
var genderBalance = ndx.dimension(dc.pluck('Gender'));
// Define chart groups
var genderNumber = genderBalance.group();
var publisherNumber = publisherChoice.group();
// Draw charts
publisherSelector
.dimension(publisherChoice)
.group(publisherNumber);
genderChart
.width(500)
.height(200)
.margins({ top: 30, right: 30, bottom: 30, left: 30 })
.dimension(genderBalance)
.group(genderNumber)
.gap(6)
.colors(colorScale)
.transitionDuration(500)
.x(d3.scaleOrdinal())
.elasticX(true);
dc.renderAll();
});
Can't figure out how I change the text colour of tooltips. For my column chart I tried:
series.tooltip.label.fill = am4core.color("#FFFFFF");
But it doesnt work. Curious also how I do it for the pie charts? Is there one place that I can update to affect all chart types, or do each need to be handled independently?
The tooltip label gets a calculated color that contrasts with the tooltip background. You need to set autoTextColor to false in order to the fill color to take effect.
series.tooltip.autoTextColor = false;
series.tooltip.label.fill = am4core.color("#FFFFFF");
The same is valid for pie charts.
You can create your own theme but that could be more than what you need.
You can use more than one theme, which allows you to use one default theme and then override just what you need:
am4core.useTheme(am4themes_animated);
am4core.useTheme(function customTheme (object) {
// Identify the instances
if (object instanceof am4core.Tooltip && object.label) {
object.autoTextColor = false;
object.label.fill = am4core.color("#FFFFFF");
}
});
After a lengthy search, I got the Below Line of code as successful line
pieSeries.labels.template.fill = am4core.color("white");
I have added above line of code if you are using axis range you can use that however as I can see your problem please take a look below line of code will solve your problem
series.tooltip.getFillFromObject = false;
series.tooltip.label.propertyFields.fill = "color";
series.tooltip.background.propertyFields.stroke = "color";
https://www.amcharts.com/docs/v4/concepts/tooltips/
I'd like to use images (icon or svg) instead of the default rectangles for the legend of the pie chart.
Would it be possible to do this in dc.js?
For example:
Many thanks.
This feature isn't built-in, but it's usually easy to "escape to d3" and customize your charts as you see fit.
In this case, we want to wait until the chart is rendered and then replace the rectangles with images:
chart.on('pretransition', function(chart) { // 1
var items = chart.selectAll('.dc-legend .dc-legend-item'); // 2
items.selectAll('rect').remove(); // 3
var images = items.selectAll('image').data(function(x) { // 4
return [x];
});
images.enter().append('image').attr({ // 5
width: 25,
height: 25,
href: function(leg) { return _icons[leg.name]; }
});
console.log('items', items.data());
});
Wait for chart render/redraw
Select the legend items
Remove any rect under each item (if it's a line chart you'll have to look for line instead
Select any existing images (the "trick" of returning a single-item array is so that we can cleanly replace anything which was there, and not keep adding more images)
And set up the image - in this example I'm using some the first SVG icons I could find on a CDN; we map stack names to SVG URLs using an object.
Finally, we also need to set the legend's item height to match the image height:
chart.legend(dc.legend().itemHeight(25));
Example output:
Example fiddle: https://jsfiddle.net/gordonwoodhull/Lss5wsz6/9/
I have a an AmChart, JavaScript chart, column chart with scroll.
I'd like to be able to pull the category axis data for the min and the max values that are currently being displayed in the chart.
Example:
If I have 0-10 on the x-axis and I zoom to 4-6, I want to be able to reference the data on point 4 and point 6.
I am new to AmCharts so hopefully I am just missing something simple but I can't seem to figure this out.
Here is a link to a chart I made:
https://live.amcharts.com/U4YmV/
You can use the zoomed event to capture the startIndex and endIndex from its event object.
In the example below, zoomedData is the zoom selection.
chart.addListener("zoomed", zoomed);
function zoomed (e) {
var chart = e.chart,
data = chart.dataProvider,
zoomedData = data.slice(e.startIndex, e.endIndex + 1);
}
Please check the example here: https://codepen.io/team/amcharts/pen/246e8f826610e848b7389fb85657348a
I am using jqplot to draw multiple lines of different line colors.
Also, I have legends whose colors should be in accordance with the corresponding line colors.
I seem to find no way to cope with the legend color.
So any hint?
Taken from the question title I understand you want to change the color of legend labels to correspond to the color of series, right?
For this reason, since the swatches which are just in front of the labels, we can use them to grab the color which we then set for the labels.
This is the bit of the code you need. You need to remember to put it before you draw your plot.
$.jqplot.postDrawHooks.push(function() {
var swatches = $('table.jqplot-table-legend tr td.jqplot-table-legend-swatch');
var labels = $('table.jqplot-table-legend tr td.jqplot-table-legend-label');
labels.each(function(index) {
//turn the label's text color to the swatch's color
var color = $(swatches[index]).find("div div").css('background-color');
$(this).css('color',color );
});
});
You could see the code running live here.