I am trying to load 1/2 million data point to the "simple graph" example. I guess there may be a limit for SVG rendering, because the line is not showing up. Can you advice me on how to deal with this "big" graph?
Thanks
// Here the code
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path{stroke: steelblue;
stroke-width: 4
;
fill: none;}
.axis path,
.axis line {fill: none;
stroke: grey;
stroke-width: 2.5;
shape-rendering: crispEdges;}
</style>
<h1>FDD Visualization</h1>
<h2>A simple Graph with visual aids using d3</h2>
<body>
<script type="text/javascript" src="d3/d3.v3.js"></script>
<script type="text/javascript"></script>
<script>
var margin = {top: 50, right: 20, bottom: 50, left: 50},
width = 1020 - margin.left - margin.right,
height = 580 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse;
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var valueline = d3.svg.line()
.x(function(d) { return x(d.timestamp); })
.y(function(d) { return y(d.temperature); });
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top +")")
.attr("fill",function(d){return"rgb(0,100,10)";} );
// Get the data
d3.csv("data/data_2.csv", function(error, data)
{data.forEach(function(d)
{d.timestamp = parseDate(d.timestamp);
d.temperature = +d.temperature;});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.timestamp; }));
y.domain([0, d3.max(data, function(d) { return d.temperature; })]);
svg.append("path") // Add the valueline path.
.attr("d", valueline(data));
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
});
</script>
</body>
// Here the data (only first rows...it amounts for approx. 500,000 rows)
timestamp,temperature
01/01/1900,23
02/01/1900,13
03/01/1900,13
04/01/1900,15
05/01/1900,12
06/01/1900,24
07/01/1900,12
08/01/1900,19
09/01/1900,12
10/01/1900,16
11/01/1900,16
12/01/1900,19
13/01/1900,24
14/01/1900,12
15/01/1900,20
16/01/1900,20
etc...
Nothing displays because your dates aren't being parsed correctly.
Your dates looks like this:
16/01/1900
but parseDate is using the format specifier:
"%Y-%m-%d"
Fixing this issue just requires a one line change:
var parseDate = d3.time.format("%d/%m/%Y").parse;
A suggestion: use the dev console to debug things! Trying to run your script shows an error:
Error: Problem parsing d="MNaN,20.000000000000057LNaN,220LNaN,220LNaN, ... "
which doesn't look like is has anything to do with trying to display too many values. Inspecting the data array, all the temperature values are undefined after parseDate is called on them.
Finally, I think Pablo's advice about not trying to show a line graph w/ 500,000 points is solid. Our screens and eyes don't have a high enough resolution to make that a useful display
Related
Following is my code. I have been trying to plot humidity and dew point in basis of months in the axis. But I am getting an error of data undefined and also the month in the axis comes in number.
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<title> Data Visualization - Binding Dataset to Shapes Using D3 </title>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.legend {
font-size: 16px;
font-weight: bold;
text-anchor: middle;
}
</style>
<body>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 70, left: 50},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%b").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var priceline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.dew); });
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.json("weatherdata.json", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.history.date.mon);
d.dew = +d.history.dailysummary[0].meandewptm;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain(d3.extent(data, function(d) { return d.dew; }));
// Nest the entries by symbol
var dataNest = d3.nest()
.key(function(d) {return d.dew;})
.entries(data);
var color = d3.scale.category10(); // set the colour scale
legendSpace = width/dataNest.length; // spacing for legend
// Loop through each symbol / key
dataNest.forEach(function(d,i) {
svg.append("path")
.attr("class", "line")
.style("stroke", function() { // Add the colours dynamically
return d.color = color(d.key); })
.attr("d", priceline(d.values));
// Add the Legend
svg.append("text")
.attr("x", (legendSpace/2)+i*legendSpace) // spacing
.attr("y", height + (margin.bottom/2)+ 5)
.attr("class", "legend") // style the legend
.style("fill", function() { // dynamic colours
return d.color = color(d.key); })
.text(d.key);
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
</script>
</body>
</html>
I am not sure how will i solve it. Can anyone please help. I am sharing the data file with the current issue I am facing.
I have attached the model data the way it should look like:
Thanks in advance.
For your question on Date format for the X axis , sorry i put an answer because i can't comment (need more reputation).
I think you need to do something like this
chart.xAxis
.tickFormat(function(d) {
return d3.time.format('%b')(format(d));
});
That will display only the month.
Using below d3 js code draw scale, but not able to figure out how i can convert x-axis dates to hours on zoom, trying to achieve x-axis dates get converted into hours on zoom in and on zoom out again into dates.
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")")
.call(d3.behavior.zoom().on("zoom", function () {
svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
}))
.append("g");
// Get the data
d3.csv("data.csv", function(error, data) {
data = [{
date:"1-May-12",
close:"58.13"
},
{
date:"30-Apr-12",
close:"53.98"
},{
date:"27-Apr-12",
close:"67.00"
},{
date:"26-Apr-12",
close:"89.70"
}
]
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
});
</script>
</body>
In a callback that implements the zoom event. You only transform the svg object. you have to process axis also. It seems that you have an effect of axis zooming.
xScale = d3.event.transform.rescaleX(xScale)
gX.call(xAxis.scale(xScale))
It rescales the scaler according to the zoom event and than the axis is rescaled and is applied to the axis group container.
I'm creating a bar chart using an ordinal scale for the x axis, and using rangeRoundBands. I'm following this example: https://bl.ocks.org/mbostock/3885304
However, my chart has outer padding -- big spaces at the beginning and end of the axis, where I'd like the bars to fully extend. The screen shot below shows the spaces I'm referring to circled in red.
How can I remove these spaces? I need my margins and the svg width and height to remain the same.
Here is a Plunker with the chart as it is now:
https://plnkr.co/edit/gMw7jvieKSlFbHLTNY9o?p=preview
Code is also below:
<!doctype html>
<html>
<head>
<style>
.axis path{
fill: none;
stroke: #cccccc;
stroke-width: 2px;
}
.x.axis text{
display:none;
}
.bar{
fill: blue;
}
body{
font-family:Helvetica, Arial, sans-serif;
}
</style>
</head>
<body>
<div id="barchart"></div>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 0, bottom: 50, left: 300},
width = 800 - margin.left - margin.right;
height = 465 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .5);
var y = d3.scale.linear().range([height, 0]);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom");
var barsvg = d3.select("#barchart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("class", "barchartbox")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.json("population.json", function(error, data1) {
x.domain(data1.map(function(d) { return d.country; }));
y.domain([0, d3.max(data1, function(d) { return d.value; })]);
barsvg.selectAll(".axis").remove();
// Add the Y Axis
barsvg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Add the X Axis
barsvg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var bars = barsvg.selectAll(".bar")
.data(data1);
bars.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.country); })
.attr("width", x.rangeBand())
.attr("y", function(d) {return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
bars.exit().remove();
});
</script>
</body>
</html>
You doing.
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .5);
Instead use rangeBands.
var x = d3.scale.ordinal()
.rangeBands([0, width], .5);
working code here
It is specified in the d3 document that while using rangeRoundBands, rounding introduces additional outer padding which is, on average, proportional to the length of the domain.
For example, for a domain of size 50, an additional 25px of outer padding on either side may be required. Modifying the range extent to be closer to a multiple of the domain length may reduce the additional padding.
Reference: rangeRoundBands
So the solution would be to use following lines after setting the x axis domain:
var mult = Math.max (1, Math.floor (width / x.domain().length));
x.rangeRoundBands ([0, (x.domain().length * mult)], 0.1, 0);
I have this piece of code which fetches data from MySQL and plots the graph, and it does it correctly. However, the marking segments such as the time span coming up in text appears to be in black. I've tried doing many changes but it was futile. I want to make it white.
Also, I want the x-axis to start with January and not 2015 as seen in the image.
<style>
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 900 - margin.left - margin.right,
height = 540 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.lsdate); })
.y(function(d) { return y(d.units); });
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.json("common/scripts/charts.php", function(error, data) {
data.forEach(function(d) {
d.lsdate = parseDate(d.lsdate);
d.units = +d.units;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.lsdate; }));
y.domain([0, d3.max(data, function(d) { return d.units; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
Screenshot:
As per #Lars's comment, you need to use the fill attribute to apply style to your text elements:
.axis text {
fill: white;
}
Working fiddle here: http://jsfiddle.net/henbox/jr6pk4bj/1/
Aside: To prevent the x-axis starting with the year, but to always use month names, add this line when you define xAxis:
.tickFormat(d3.time.format("%B"));
Here's an update to the fiddle showing that change too: http://jsfiddle.net/henbox/jr6pk4bj/2/
I am starting with this simple example but I have the following error (using Firebug)
TypeError: string is undefined
[Break On This Error]
var c, p, i = 0, n = template.length, m = string.length;
Any hint?? (I tried similar responses and it didn't work, I guess there is something wrong with the time and date format, but I believe the "%Y-%m-%d" format is the right one that I have in the csv file...)
Thanks!!
//here my prueba.html file
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body{font: 12px arial;}
path{stroke: steelblue;
stroke-width: 2;
fill: none;}
.axis path,
.axis line {fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;}
</style>
<body>
<script type="text/javascript" src="d3/d3.v3.js"></script>
<script>
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse; // HERE ERROR !!!
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var valueline = d3.svg.line()
.x(function(d) { return x(d.timestamp); })
.y(function(d) { return y(d.temperature); });
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top +")");
// Get the data
d3.tsv("data/data.csv", function(error, data)
{data.forEach(function(d)
{d.timestamp = parseDate(d.timestamp); // HERE ERROR !!!
d.temperature = +d.temperature;});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
svg.append("path") // Add the valueline path.
.attr("d", valueline(data));
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
});
</script>
</body>
//here my data.csv file
timestamp,temperature
1900-01-01,20
1900-01-02,20
1900-01-03,17
1900-01-04,23
1900-01-05,15
1900-01-06,22
1900-01-07,24
1900-01-08,15
1900-01-09,25
1900-01-10,19
1900-01-11,23
1900-01-12,19
1900-01-13,17
1900-01-14,15
1900-01-15,17
1900-01-16,21
1900-01-17,23
1900-01-18,25
1900-01-19,17
1900-01-20,22
1900-01-21,23
1900-01-22,17
1900-01-23,15
1900-01-24,23
1900-01-25,19
1900-01-26,25
1900-01-27,21
1900-01-28,22
1900-01-29,20
1900-01-30,15
1900-01-31,21
1900-02-01,19
1900-02-02,15
1900-02-03,15
1900-02-04,25
1900-02-05,23
1900-02-06,25
1900-02-07,15
1900-02-08,18
1900-02-09,22
1900-02-10,15
1900-02-11,19
1900-02-12,18
1900-02-13,24
1900-02-14,22
1900-02-15,16
1900-02-16,21
1900-02-17,24
1900-02-18,25
A picture of this using Chrome developer tools...
http://i.imgur.com/0vZhCgK.jpg?1
You are using d3.tsv, you should be using d3.csv instead.
Also if you want to use tsv (Tab-separated values) you'll need to replace every comas by a tabulation.
PS: care to not save the file with an editor that automatically replace the tabulations with spaces :)