How can I change the color of the circles on a scatter plot based on one of the fields that I'm not using on neither of the axes?
Example, this code:
var myChart3 = new dimple.chart(svg3, data);
myChart3.addMeasureAxis("x", "salary");
myChart3.addMeasureAxis("y", "bonus");
var mySeries = myChart3.addSeries(["Index","a"], dimple.plot.scatter);
myChart3.draw();
produces this graph:
but I also would like to color the bubbles based on a third field called "department"
thanks
The first parameter of addSeries determines colours. In the case of an array the last element is used, so you just need to do:
var mySeries = myChart3.addSeries(["Index","a","department"], dimple.plot.scatter);
Related
I'm using dc.js to draw my charts, and trying to give different color to the bars.
Some bars are black instead of the colors I requested. How do I get the chart to use the color array?
This is the code
var keyColorCodes;
keyColorCodes = dc.config.defaultColors();
bar.colors(d3.scaleOrdinal().domain(d3.keys(keyColorCodes)).range(d3.values(keyColorCodes)));
bar.colorAccessor(function(d) {
return d.key;
});
The domain of your scaleOrdinal should be an array containing the set of values which your colorAccessor will return. Right now you are pulling the set of indices of the dc.config.defaultColors().
One easy way to get the set of values is to map your group.all() through your colorAccessor:
.domain(speedSumGroup.all().map(d => d.key))
Also, d3.values is intended to be used with associative arrays, i.e. objects. It has no effect when applied to an ordinary array.
Here is a general way to do it, which should work in most cases:
chart
.colorAccessor(d => d.key)
.colors(d3.scaleOrdinal()
.domain(speedSumGroup.all().map(d => d.key))
.range(dc.config.defaultColors()));
Example fiddle.
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();
});
In a D3 or NVD3.js line graph, how can I select a particular line once the graph is rendered? For example, suppose I want to animate the stroke width on a line, like this:
d3.selectAll('path').transition().duration(2000).style("stroke-width", "20");
The above will select all paths, obviously, but I would like to select a particular series—for example, the Oranges series in a data set defined like this:
var data = [{key: "Apples", values: array1},{key: "Oranges", values: array2}]
I thought something this might work, but it did not:
d3.select('#chart svg').datum(data[1]).transition... // or alternatively,
d3.select('#chart svg').datum(data[1].values).transition...
I've been trying to figure it out using the Cumulative Line Chart example in the code editor here, with no success: http://nvd3.org/livecode/#codemirrorNav
This is a very basic question, but I'm new to D3 and have been unable to figure it out.
There are couple of simple ways that I can think of:
You can store each path in its own variable (or inside an array):
var path1 = graph.append("g").append("path").data([data1]).attr("class", "line1");
Now you can apply your transitions to just this path variable and it should work.
Another option is to give each path a unique class and then use d3.selectAll(".uniqueclassname") and apply your transitions.
In this fiddle, look at the tick function (specially for the following piece of code).
// redraw the lines
graph.select(".line1").attr("d", line).attr("transform", null);
path2.attr("d", line).attr("transform", null);
path3.attr("d", line).attr("transform", null);
graph.select(".line4").attr("d", line).attr("transform", null);
Is there a way in d3 to not draw overlapping tick labels? For example, if I have a bar chart, but the bars are only 5 pixels wide and the labels are 10 pixels wide, I end up with a cluttered mess. I'm currently working on an implementation to only draw the labels when they do not overlap. I can't find any existing way to do that, but wasn't sure if anyone else had dealt with this problem.
There is no way of doing this automatically in D3. You can set the number of ticks or the tick values explicitly (see the documentation), but you'll have to figure out the respective numbers/values yourself. Another option would be to rotate the labels such that there is less chance of them overlapping.
Alternatively, like suggested in the other answer, you could try using a force layout to place the labels. To clarify, you would use the force layout on the labels only -- this is completely independent of the type of chart. I have done this in this example, which is slightly more relevant than the one linked in the other answer.
Note that if you go with the force layout solution, you don't have to animate the position of the labels. You could simply compute the force layout until it converges and then plot the labels.
I've had a similar problem with multiple (sub-)axis, where the last tick overlaps my vertical axis in some situations (depending on the screen width), so I've just wrote a little function that compares the position of the end of the text label with the position of the next axis. This code is very specific to my use case, but could adapted easily to your needs:
var $svg = $('#svg');
// get the last tick of each of my sub-axis
$('.tick-axis').find('.tick:last-of-type').each(function() {
// get position of the end of this text field
var endOfTextField = $(this).offset().left + $(this).find('text').width();
// get the next vertical axis
var $nextAxis = $('line[data-axis="' + $(this).closest('.tick-axis').attr('data-axis') + '"]');
// there is no axis on the very right, so just use the svg width
var positionOfAxis = ($nextAxis.length > 0) ? $nextAxis.offset().left : $svg.offset().left + $svg.width();
// hide the ugly ones!
if (endOfTextField > positionOfAxis) {
$(this).attr('class', 'tick hide');
}
});
The ticks with color: aqua are the hidden ones:
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.