Prevent clipping using domain in d3.js - javascript

I'm trying to prevent clipping at the top most part of my chart by increasing the domain on the yAxis like so:
mainHeight = 640;
yScale = d3.scale.linear()
.range([mainHeight, 0])
.domain(d3.extent([0, d3.max(data, function (d) {
return (d.total)+1000;
})]));
The idea is to get the max data for the yAxis and increase it by 1000.
The highest total is 14348 so with 1000 added on it creates 15348
However the top of the chart is still being clipped off and my axis hasn't increased to prevent the clipping. Even if I increase the number by 9999999999 it still doesn't happen.
The line is generated with:
var totalLine = d3.svg.line()
.interpolate('monotone')
.x(function (d) {
return xScale(d.date);
})
.y(function (d) {
return yScale(d.total);
});

Try throwing a .nice() at the end.
yScale = d3.scale.linear()
.range([mainHeight, 0])
.domain(d3.extent([0, d3.max(data, function (d) {
return (d.total)+1000;
})]))
.nice();
This will try to make the axis end on nice round numbers. You can read more here: https://github.com/d3/d3-3.x-api-reference/blob/master/Quantitative-Scales.md#linear_nice
Hope this helps.

Related

Stumped by d3 error I'm receiving - Error: <path> attribute d: Expected number, "M0,NaNL21.923076923…"

I'm trying to convert a d3 sparkline example on codepen (https://codepen.io/jakelear-1472051722/pen/bRbqBB) so that it pulls data in from a csv file. Here is my code:
d3.csv("sparkline.csv", function (error, data) {
if (error) throw error;
// format the data
data.forEach(function (d) {
currentValue = +d.currentValue;
});
var graph = d3.select('.sparkline').append("svg").attr("width", "100%").attr("height", "100%");
var height = parseInt(graph.style("height"));
var width = parseInt(graph.style("width"));
var x = d3.scaleLinear()
.domain([0, data.length])
.range([0, width]);
var y = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([height, 0]);
var line = d3.line()
.x(function(d,i) {
return x(i);
})
.y(function(d) {
return y(currentValue);
});
graph.append("path")
.data([data])
.attr("class", "line")
.attr("d", line);
});
I'm receiving the following error: d3.v4.js:1382 Error: attribute d: Expected number, "M0,NaNL21.923076923…" and have been struggling trying to figure this out.
The contents of my CSV file:
currentValue
2.0
2.3
1.9
1.7
1.7
2.2
2.3
2.2
2.0
2.1
1.9
2.0
1.6
Any help is greatly appreciated. I'm sure it's something small I'm just not seeing.
Thanks
data is not a simple, flat array, but an array of objects.
Therefore, it should be:
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d){ return d.currentValue})])
.range([height, 0]);
Besides that, remember to correctly provide a reference to the object. In the forEach loop:
data.forEach(function (d) {
d.currentValue = +d.currentValue;
});
And in the line generator:
var line = d3.line()
.x(function(d,i) {
return x(i);
})
.y(function(d) {
return y(d.currentValue);
});

How to create X and y Intersect chart using d3js?

I have an data which show the performance of user and competency which is y and x axis respectively. Where its scaled from 1 to 10. I want to create an intersection point using d3js but as a beginner im having no idea where to start.
To create a dot at that point, you simply need to draw a new circle on the point of intersection. Here is a JSFiddle of a VERY simple graph with comments to make it easier to understand. The dots are drawn from data. The important piece for you is
.append("svg:circle")
.attr("cy", function(d) {
return y(d.y);
})
.attr("cx", function(d, i) {
return x(d.x);
})
.attr("r", 10)
which creates an svg circle, places it on the data point's x and y coordinates, and gives it a radius of 10. A more simplified version which might be easier to use for your application (because I don't know how your data is stored) is to feed in the data manually
.append("svg:circle")
.attr("cy", x(5))
.attr("cx", y(6))
.attr("r", 10)
This will create a single data point at 5,6 with a radius of 10. Note that this is using the scaling functions x() and y() to convert the data point 5,6 to pixel values
var x = d3.scale.linear()
.domain([0, 10])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, 10])
.range([height, 0]);

Interchange time and linear scaling depending on user selection

I am building a widget to let users decide what quantities to plot against what quantities (building off this animated scatter plot on bl.ocks. This is working fine for numeric quantities, but I also have date quantities, and I want users to be able to plot these too, in the same way, and against non-date quantities.
The original linear scaling and axes are set up like so as global functions:
var xScale = d3.scale.linear() // xScale is width of graphic
.domain([0, d3.max(dataset, function(d) {
return d[0]; // input domain
})])
.range([padding, canvas_width - padding * 2]); // output range
var yScale = d3.scale.linear() // yScale is height of graphic
.domain([0, d3.max(dataset, function(d) {
return d[1]; // input domain
})])
.range([canvas_height - padding, padding]); // remember y starts on top going down so we flip
// Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5);
// Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
My hope was that I could modify these globals inside the click function and even change the nature of the scaling and that this would feed back into the axis variables as well, so I put this inside the click function:
if(types[xName]==3){
console.log("resetting x scale to time type");
xScale = d3.time.scale().range([padding, canvas_width - padding * 2]); // output range
}
else{
// Create scale functions
xScale = d3.scale.linear() // xScale is width of graphic
.domain([0, d3.max(dataset, function(d) {
return d[0]; // input domain
})])
.range([padding, canvas_width - padding * 2]); // output range
}
xScale.domain([0, d3.max(dataset, function(d) {
return d[0]; })]);
if(types[xName] == 1){
xScale.domain([d3.max(dataset, function(d) {
return d[0]; }), 0]);
}
if(types[yName]==3){
console.log("resetting y scale to time type");
yScale = d3.time.scale().range([canvas_height - padding, padding]); // remember y starts on top going down so we flip
}
else {
yScale = d3.scale.linear() // yScale is height of graphic
.domain([0, d3.max(dataset, function(d) {
return d[1]; // input domain
})])
.range([canvas_height - padding, padding]); // remember y starts on top going down so we flip
}
yScale.domain([0, d3.max(dataset, function(d) {
return d[1]; })]);
if(types[yName] == 1){
yScale.domain([d3.max(dataset, function(d) {
return d[1]; }), 0]);
}
I also use a parseDate as appropriate on the data when it's date data. The above (and full code is here with widget here, the problematic date type being stored in Created) puts all the points in some crazy location all in one straight line off the graph when I choose the date type, and worse still produces the following error:
Error: Invalid value for <circle> attribute cx="naN" where I assume this is giving an error from the following code:
svg.selectAll("circle")
.data(dataset) // Update with new data
.transition() // Transition from old to new
...
.attr("cx", function(d) {
return xScale(d[0]); // Circle's X
})
So I assume the xScale is simply not working when it's been converted to a time scale. What am I doing wrong? Thanks for any corrections or troubleshooting advice.
The cx is calculating as NaN because the data you are storing created, as time stamp example:"created":1447686953 and you are writing a parse date function.
var parseDate = d3.time.format("%Y%m%d").parse;
This is incorrect as the date is not in 20151223 format.
So the scale as you suggesting get calculated wrongly.
if(types[xName]== 3){
newNumber1 = parseDate(String(data[i][xName]));//this is wrong
}
var newNumber2 = data[i][yName]/divisor[types[yName]]//Math.floor(Math.random() * maxRange); // New random integer
if(types[yName]== 3){
newNumber2 = parseDate(String(data[i][yName]));//this is wrong
}
So you need to do this for converting into date:
if(types[xName]== 3){
newNumber1 = new Date(data[i][xName]*1000);
}
var newNumber2 = data[i][yName]/divisor[types[yName]]//Math.floor(Math.random() * maxRange); // New random integer
if(types[yName]== 3){
newNumber2 = new Date(data[i][yName]*1000);
}
Hope this helps!

y scale on d3 bar chart

I am trying to build a stacked bar chart in d3.
Here's my jsfiddle:
http://jsfiddle.net/maneesha/gwjkgruk/4/
I'm trying to fix it so that the y-axis starts at zero.
I thought this is where that was set up and this is how it should be:
yScale = d3.scale.linear()
.domain([0, yMax])
.range([0, height]),
but it doesn't work. Changing domain to this gets the scale right but messes up all my rects.
yScale = d3.scale.linear()
.domain([yMax, 0])
.range([0, height]),
What am I doing wrong?
Try to modify your scale like that:
yScale = d3.scale.linear()
.domain([0,yMax])
.range([height,0]),
and then when you fill the rect:
.attr('y', function (d) {
return height - yScale(d.y0);
})
.attr('height', function (d) {
return height - yScale(d.y);
})

D3.js Line chart with relative min and max in Y axis

Consider the following VND3 line graph: http://jsfiddle.net/tramtom/hfv68yan/
The graph plots the line ok, however most of my data is the static over long periods, and the two series will always have one at the top of the graphic and other on the bottom axis.
How to create relative minimum and maximums for the Y axis in a way that lines for the series be almost in the middle or at least spaced so that the lower valued series does not lie almost entirely on the x-axis.
Need to add 100 units below the minimum and 100 units above the maximum so the lines don't be at the top or bottom of the graphic.
I tried setting a domain and range values like in here http://jsfiddle.net/tramtom/hfv68yan/1/ but have no effect
var yScale = d3.scale.linear()
.domain([
d3.min(data, function (d) {
return d.y;
}) - 100,
d3.max(data, function (d) {
return d.y;
}) + 100
])
.range([
d3.min(data, function (d) {
return d.y;
}),
d3.max(data, function (d) {
return d.y;
})
]);
You need to force the axis range by adding .forceY([0,500]) to the chart instantiation.
This SO answer might be helpful. That should at least point you in the right direction.

Categories

Resources