Use d3 log scale instead of linear scale - javascript

I'm trying to do a chart based on http://mbostock.github.com/d3/talk/20111116/bar-hierarchy.html, the only difference being that I'd like to use a log scale for the x-axis.
Here's my fiddle: http://jsfiddle.net/JhDVC/5/
As you can see, the x-axis is defined at line 4:
x = d3.scale.linear().range([0, w]),
If I change it for
x = d3.scale.log().range([0, w]),
Then it doesn't work (nothing is rendered), throwing these error messages:
Error: Invalid value for <rect> attribute width="NaN"
Changing the domain setting from
x.domain([0, root.value]).nice();
to
x.domain([1, root.value]).nice();
shows me the z axis (names) but still no bars or values.

There are a few other places where the domain for the scale is set. You need to update those as well.
Working jsfiddle here.
And here's some code so that it allows me to post this:
x.domain([1, root.value]).nice();

Your range includes zero - log(0) is undefined.

Related

how to update y axis for NVD3's multichart?

There is a stacked area chart built with NVD3's multichart. The values in the chart can change, and I want the y Axis to scale according to the selected values.
How can I update the yAxis for multiChart?
I have used forceY to change the yAxis in other NVD3 charts, but forceY doesn't work with multiChart.
Below are several strategies. The last strategy changes the value of the domain, but the new value is not reflected on the chart.
Thanks for any help offered.
//existing domain values -- to be changed
chart.stack1.yDomain()
=> [-.1, -1.92]
//new values that I want the y axis to use
let [padStart, padEnd] = [.12, 0.27];
//DOESNT WORK - this changes the yDomain of stack1, but does not change yAxis1.domain
// chart.stack1.yDomain([padStart, padEnd]);
//DOESNT WORK - error -chart.forceY is not a function
// chart.forceY(padStart, padEnd);
//DOESNT WORK - error - chart.yAxis1.forceY is not a function
// chart.yAxis1.forceY(padStart, padEnd);
//DOESNT WORK - this does not change domain value
// chart.yAxis1.scale().domain([padStart, padEnd]);
//WORKS -- this changes domain value, but the view doesn't update
chart.yAxis1.domain([padStart, padEnd]);
The correct approach for multichart is to access the yDomain directly:
chart.yDomain([padStart, padEnd])

Scaling Axis with D3 JavaScript

I have plotted the X and Y axes. I have couple of points to show on the axis. My points vary for X axis from 4.5 to 8 and for Y axis from 2 to 4.
You can find the DEMO of what I have done.
function kmeans(){
x_means[0] = 5.9;
plotMeans();
}
The problem is this chart shows the points such as 0.59. However, I can't see when I give the value of 5.9 since it falls out of the chart.
Any ideas on how to solve this?
Thank you!
If you inspect your javascript console, you'll see this error:
Error: Invalid value for <circle> attribute cy="NaN"
This is because the data you feed d3 is:
> numeric.transpose([[0.59],[]])
Array[2]
0: 0.59
1: undefined
So that:
.attr("cy", function(d, i){return Y(d[1]);});
is an operation on undefined.
EDITS
Do'h, just re-read your question. Your scales need a domain, this is the user space span of your coordinate space. The range then is is the pixel span of your coordinate space. The scale maps the two together:
var X = d3.scale.linear()
.range([0, width]) //<-- 0 to 960 pixels
.domain([0,10]); //<-- maps to coordinates 0 to 10
See update here.
I also modified it to use proper axis so it's easier to visualize.

dygraph set x axis max value and update the dygraph

Trying to set the maximum value of the x-axis of a dygraph after it has been drawn.
Tried
axes = g.axes_;
axes.maxxval = maxVal;
g.updateOptions({
axes
});
You want to be setting the valueRange property. See this demo.
The trailing _ in g.axes_ means it's a private internal property. Nothing good will come from messing with it.

Setting a minim value for the y axis in d3.js

I'm trying to make a d3 plot based on Focus+Context example.
It works fine, but I'm not able to set a minimal value for the y-axis.
I taught I understood the theory of input domain and output range (http://chimera.labs.oreilly.com/books/1230000000345/ch07.html), but it seems I'm missing something.
here is my code: http://jsfiddle.net/cecdsmnv/1/
I want the y axis to go from minAltitude to maxAltitude
any idea?
You have all the right ideas.
The settings you made for y.domain will be overwritten in line 72. Change around line to (switch min and max):
var z = 50;
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([minAltitude, maxAltitude + z]);
x2.domain(x.domain());
y2.domain(y.domain());
I added a z padding variable there in case you want some heading space at the top.

nvd3 scatter plot with ordinal scale

Im relatively new to d3 and nvd3 and wanted to create a simple scatterplot, just like the example but with an ordinal y-axis. So y axis values are categorical strings. This is what I thought I needed to do:
var xfun = function (d) { return d.Pos } //simple ints
, yfun = function (d) { return d.Title } //the ordinal values
var chart = nv.models.scatterChart()
.showDistX(true)
.showDistY(true)
.color(d3.scale.category10().range())
.margin({ top: 30, right: 20, bottom: 50, left: 130 })
.tooltips(false)
.x(xfun)
.y(yfun);
// create an ordinal scale with some test values
var ys = d3.scale.ordinal()
.domain(["this","is","an","ordinal","scale"])
.range(5);
// tell nvd3 to use it
chart.yAxis.scale(ys);
// add to the page
nv.addGraph(function () {
d3.select(selector).datum(data).transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
However, no luck:
Error: Invalid value for <circle> attribute cy="NaN" d3.js:690
Error: Invalid value for <line> attribute y1="NaN" d3.js:690
Error: Invalid value for <line> attribute y2="NaN" d3.js:690
Error: Invalid value for <circle> attribute cy="NaN" d3.js:7532
Uncaught TypeError: Cannot read property '0' of undefined
..
And the y-axis simply shows a linear axis from -1 to 1. Iterestingly there are some circles plotted at y=-1 and y=1 (the extremes).
To manually force correct values for cy I tried adding after call(chart):
d3.selectAll("#mychart circle").attr("cy", function(d){
return = ys(yfun(d));
});
But still the same error. How do I get the ordinal scale to work properly? Note I also need it to update correctly when I use the nvd3 legend to switch between dataseries (which will contain different x/y data).
There is a related question on github, but no solution.
Update: after some debugging I tried replacing chart.yAxis.scale(ys) with chart.scatter.y(ys) and this gets rid of the errors. I can also drop the manual selectAll.
However, the y-axis still shows a linear scale from 0.99-1.01 and all points are plotted at y=1. So a step closer but no ordinal scale yet.
In case somebody else stumbles upon this, here's what worked for me: instead of trying to force an ordinal scale on the axis (X, in my case), I used a linear scale, but provided a custom tickFormat function that returned the desired label.
chart.xAxis.tickFormat(function(d){
return labelValues[d];
});
Where labelValues maps between the numerical value and the desired label.
There is an easy solution by #robinfhu.
Don't use an ordinal scale!
Instead, set your x function to return the index of the element:
chart.x(function(d,i){ return i;})
And set your tickFormat function to read the proper label:
tickFormat(function(d) {return that.data[0].values[d].x;})
Working example: Plunker
Copy and paste:
nv.models.lineChart()
.x(function(d, i) {
return i;
}).xAxis
.tickFormat(function(d) {
return that.data[0].values[d].x;
});
I haven't used nvd3.js, but from my d3 experience, the error seems to be the range on your scale. For an ordinal scale, you need to define an array of corresponding values for the domain to map to. For example, I could set the following scale:
var myScale = d3.scale.ordinal()
.domain(['this','is','an','ordinal','scale'])
.range([1,2,3,4,5])
This scale would map my domain to numbers in the range 1:5, with 'this' -> 1, 'is' -> 2, etc. If I didn't want to set each point individually, I could also define my range with rangePoints, as follows:
var myScale = d3.scale.ordinal()
.domain(['this','is','an','ordinal','scale'])
.rangePoints([1,5])
rangePoints gives me an evenly spaced range of points from the minimum specified value to the max specified value, so this would result in the same range being generated.
I've made some circles that illustrate how to do this here.
When you change to a different data series, you'll have to update your domain. Since range corresponds to where on the page your points are mapping to, you won't need to update it, unless nvd3.js applies a secondary mapping and does ordinalDomain -> integers -> pointLocation in two steps.
Another option is to apply the scale in the function definition.
yfun = function (d) { return ys(d.Title) }

Categories