scale.linear() is returning NaN - d3.js

Im running a simple bar chart using d3.scale.linear() and hardcoding he domain range for this example
I can see in firebug that when aplying attr of width to my div, w_bar appears to be NaN.
Why is that?
var w_bar = d3.scale.linear()
.domain([0, 107525233]) //harcoded
.range(["0px", "290px"]);
var theList = d3.select("#list").selectAll("div")
.data(myJSON);
theList.enter().append("div")
.text(function (d) { return d.v; })
.transition()
.duration(1000)
.attr("width", w_bar); // Why NaN?
theList.exit()
.remove();
Here's the jsfiddle:
http://jsfiddle.net/NAhD9/5/

Well, w_bar is Not a Number, and the width attribute needs to be a number. Hence, NaN.
If you want your width attribute to scale based on the v attribute in your myJSON object, you should say
.attr("width",function (d) {return w_bar(d.v)}).
This is how scales work in d3, they are a function which takes in an argument (some value within the domain of the scale) and returns that value transformed to fit into the range of your scale.
Updated jsFiddle here.

You need to use a function to tell d3 how you want your data to interact with to scale to create an array:
.attr("width", function(d){ return w_bar(d.v); })
This will take all the v attributes from objects making up the myJSON array, scale them with w_bar, and set the width of their corresponding rectangles equal to that value.

Related

d3js scatterplot custom icons and animation

I'm just starting with d3js and I wanted to know if it's possible to create a scatterplot with custom icons for the data points similar to this method for Forced Layout?
I don't want to use d3.svg.symbol() as I want to use a custom icon with my company logo to mark each data point.
My final goal is to translate a point (with a custom icon) along a horizontal axis depending on the x value. I've searched high and low on how to do this with d3js but have had no luck.
To use an icon instead of a symbol, just swap out the path element (that the symbol generator is called on) with an image element.
Given a data set, D, with elements like {src: http.myImageURL, x: 10, y : 20} it would look something like this:
var svg = d3.select('body').append('svg');
svg.append('g').selectAll('.myPoint')
.data(D)
.enter()
.append('image')
.attr("xlink:href", function(d){ return d.src })
.attr("x", function(d){ return d.x })
.attr("y", function(d){ return d.y })
.attr("width", 16)
.attr("height", 16);

domain / padding in d3.js linear scales

Folks-
I've been trying to set the d3.scale.linear.domain x axis value manually, using Mike Bostock's simple bar chart: http://bl.ocks.org/mbostock/raw/2368837/
var x = d3.scale.linear()
.domain([-100, 200]) //this line added
.range([0, width])
I would expect this to yield a an x axis with values -100 to 200. Instead it yields -30 to 10, as before, and the chart doesn't change. Any ideas?
Thanks,
RL
The domain is set again inside the d3.tsv callback:
x.domain(d3.extent(data, function(d) { return d.value; })).nice();
If you want to change it, you need to delete that line.

D3 - Vertical axis is not displaying correctly

I have a CSV file containing the French population by department. I can correctly display a map colored with population density but I encounter problems with the associated legend.
You can see the current result here: http://i.stack.imgur.com/Y26JT.jpg
After loading the CSV, here is my code to add the legend :
legend = svg.append('g')
.attr('transform', 'translate(525, 150)')
.attr('id', 'legend');
legend.selectAll('.colorbar')
.data(d3.range(9))
.enter().append('svg:rect')
.attr('y', function(d) { return d * 20 + 'px'; })
.attr('height', '20px')
.attr('width', '20px')
.attr('x', '0px')
.attr("class", function(d) { return "q" + d + "-9"; })
.attr('stroke', 'none');
legendScale = d3.scale.linear()
.domain([0, d3.max(csv, function(e) { return +e.POP; })])
.range([0, 9 * 20]);
legendAxis = d3.svg.axis()
.scale(legendScale)
.orient('right')
.tickSize(1);
legendLabels = svg.append('g')
.attr('transform', 'translate(550, 150)')
.attr('class', 'y axis')
.call(legendAxis);
Colors are obtain using ColorBrewer CSS (https://github.com/mbostock/d3/tree/master/lib/colorbrewer)
I have two problems:
The Hyphen '-' (a SVG line) is not displayed for each value of my axis
I cannot choose the number of values in my axis, I would like one at the beginning of each color block.
Thanks in advance for any help.
The reason your solution isn't showing the 'hyphen' (svg lines) is because you have the tickSize set very small. Try not setting it and it will default to 6 (according to the API docs - https://github.com/mbostock/d3/wiki/SVG-Axes).
To choose the number of values in your axis, you can add a call to ".ticks(N)", where N is the number of ticks you want. D3 will try to show that many ticks. You could also call ".tickValues([...])" and pass in the exact array of values to use for the ticks.
Here's a JSFiddle that corrects the issues in your example: http://jsfiddle.net/TRkGK/3/
And a sample of the part that fixes your issues:
var legendAxis = d3.svg.axis()
.scale(legendScale)
.orient('right')
.tickSize(6) // Tick size controls the width of the svg lines used as ticks
.ticks(9); // This tells it to 'try' to use 9 ticks
UPDATED:
You also want to make sure you're setting the CSS correctly. Here's what I use:
.y.axis line { stroke: #ccc; }
.y.axis path { display: none; }
In your example, when you add the larger tickSize, you are seeing the path in which the tick lines are defined. If you hide the path and give the lines a color, you'll see the ticks rather than the area in which the ticks are defined.
Hope this helps!
It looks like it could be a css issue, did you look at reblace's css in his fiddle?

D3: Create a continuous color scale with many strings/inputs for the range and dynamically changing values of the domain

I am trying to create a linear color scale for a heatmap. I want to color scale to go through a large set of specific colors, where the first color corresponds to the min of the data and the last color should be given to the max of the data.
I know that I can do this by also giving the domain 17 values in between the min and max, but I do not know how to do this dynamically if the user is able to change the dataset (and thus change the coloring of the heatmap)
In essence I would like to following, but I know it does not work
var colorScale = d3.scale.linear()
.range(["#6363FF", "#6373FF", "#63A3FF", "#63E3FF", "#63FFFB", "#63FFCB",
"#63FF9B", "#63FF6B", "#7BFF63", "#BBFF63", "#DBFF63", "#FBFF63",
"#FFD363", "#FFB363", "#FF8363", "#FF7363", "#FF6364"])
.domain([d3.min(dataset, function(d) {return d;}),
d3.max(dataset, function(d) {return d;})]);
Can anybody please tell me what I need to put into 'domain' to make it work?
EDIT:
I did find something that does what I want. Using R I calculated 256 colors in between the 17 from above with the designer.colors functions and put this into the range. This does give the feeling of a continous color scale
var colorScale = d3.scale.linear()
.range(["#6363FF", "#6364FF", "#6364FF", "#6365FF",
"... several other lines with color codes ..."
"#FF6764", "#FF6564", "#FF6464", "#FF6364"])
.domain(d3.range(1,257));
var quantize = d3.scale.quantile()
.range(d3.range(1,257))
.domain([d3.min(dataset, function(d) {return d;}),
d3.max(dataset, function(d) {return d;})]);
Now I can use the color in this fashion
colorScale(quantize(dataset))
But I'm wondering if this can also be done in less lines of code?
You want to split the problem up. First define a scale for your heatmap that maps 0-1 to your colours. Then define a second (dynamic) scale that maps your dataset to 0-1. You can then combine the scales to paint your shapes.
var colours = ["#6363FF", "#6373FF", "#63A3FF", "#63E3FF", "#63FFFB", "#63FFCB",
"#63FF9B", "#63FF6B", "#7BFF63", "#BBFF63", "#DBFF63", "#FBFF63",
"#FFD363", "#FFB363", "#FF8363", "#FF7363", "#FF6364"];
var heatmapColour = d3.scale.linear()
.domain(d3.range(0, 1, 1.0 / (colours.length - 1)))
.range(colours);
// dynamic bit...
var c = d3.scale.linear().domain(d3.extent(dataset)).range([0,1]);
// use the heatmap to fill in a canvas or whatever you want to do...
canvas.append("svg:rect")
.data(dataset)
.enter()
// snip...
.style("fill", function(d) {
return heatmapColour(c(d));
Plus you can use the d3.extent function to get the min and max of the dataset in one go.
Use a Quantitative Scale plus Color Brewer
// pick any number [3-9]
var numColors = 9;
var heatmapColour = d3.scale.quantize()
.domain(d3.extent(dataset))
.range(colorbrewer.Reds[numColors]);
// use the heatmap to fill in a canvas or whatever you want to do...
canvas.append("svg:rect")
.data(dataset)
.enter()
// snip...
.style("fill", function(d) {return heatmapColour(d);})
Use threshold scales. Here is a quick example:
coffee> d3 = require 'd3'
coffee> color = d3.scale.threshold().domain([5,30,100]).range(["red","orange","green"]);
coffee> color 6
'orange'
coffee> color 3
'red'
coffee> color 33
'green'

D3 log scale displaying wrong numbers

I'm trying to wrap my head around the log scales provided by D3.js. It should be noted that as of yesterday, I had no idea what a logarithmic scale was.
For practice, I made a column chart displaying a dataset with four values: [100, 200, 300, 500]. I used a log scale to determine their height.
var y = d3.scale.log()
.domain([1, 500])
.range([height, 1]);
This scale doesn't work (at least not when applied to the y-axis as well). The bar representing the value 500 does not reach the top of the svg container as it should. If I change the domain to [100, 500] that bar does reach the top but the axis ticks does not correspond to the proper values of the bars. Because 4e+2 is 4*10^2, right?
What am I not getting here? Here is a fiddle.
Your scale already reverses the range to account for the SVG y-coordinates starting at the top of the screen -- ie, you have domain([min, max]) and range([max, min]). This means your calcs for the y position and height should be reversed because your scale already calculated y directly:
bars.append("rect")
.attr("x", function (d, i) { return i * 20 + 20; })
.attr("y", function (d) { return y(d); })
.attr("width", 15)
.attr("height", function (d) { return height - y(d); });
Here's an updated Fiddle: http://jsfiddle.net/findango/VeNYj/2/

Resources