I could really use some help fixing a d3js related problem.. I did everything I know and googled everywhere but still can’t figure out the solution. I’ve got a simple database as shown below.
when executing the code it reads all the data and everything is fine, when it’s doing it’s refresh it’s updating the temperature graph but not the humidity... I tried many things including adding valueline2 to the update function but it still doesn't work... Any help would be much appreciated thanks.
dtg | temperature | hum
2016-03-02 09:14:00 23 40
2016-03-02 09:10:00 22 45
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 14px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
/* Addon 5,6,7 - part 1*/
.grid .tick {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
</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: 60, bottom: 50, left: 50},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// Parse the date / time
/* var parseDate = d3.time.format("%d-%b-%y").parse; */
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").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(6);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(8);
// Define the line
var valueline = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.dtg); })
.y(function(d) { return y(d.temperature); });
// Define the 2nd line -- Addon 9 part 1
var valueline2 = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.dtg); })
.y(function(d) { return y(d.hum); });
// 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 + ")");
// Addon 5,6,7 - part 2
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(8)
}
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(8)
}
// Get the data
d3.json("data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
d.hum = +d.hum; // Addon 9 part 3
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, d3.max(data, function(d) { return Math.max(d.temperature, d.hum)+5; })]);
// y.domain([0, d3.max(data, function(d) { return d.temperature; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the valueline2 path - Addon 9 part 2
svg.append("path")
.attr("class", "line")
.style("stroke", "red")
.attr("d", valueline2(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);
// Addon 4
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
// Addon 5,6,7 - part 3
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
});
var inter = setInterval(function() {
updateData();
}, 5000);
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
d3.json("data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
d.hum = +d.hum;
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, d3.max(data, function(d) { return Math.max(d.temperature, d.hum) + 5; })]); // Addon 9 part 4
// Select the section we want to apply our changes to
var svg = d3.select("body").transition();
// Make the changes
svg.select(".line").duration(750).attr("d", valueline(data));
svg.select("x.axis").duration(750).call(xAxis);
svg.select("y.axis").duration(750).call(yAxis);
});
}
</script>
</body>
You need to give different names to your different lines. Right now both lines only have the same class: ".line".
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("id", "line1") //new id
.attr("d", valueline(data));
// Add the valueline2 path - Addon 9 part 2
svg.append("path")
.attr("class", "line")
.attr("id", "line2") //new id
.style("stroke", "red")
.attr("d", valueline2(data));
Then in the update, you need to actually update both lines:
// Make the changes
svg.select("#line1").duration(750).attr("d", valueline(data)); //update line 1
svg.select("#line2").duration(750).attr("d", valueline2(data)); //update line 2
svg.select("x.axis").duration(750).call(xAxis);
svg.select("y.axis").duration(750).call(yAxis);
Another more "D3-friendly" approach would be to give the temperature data to your first path, the humidity data to the second one, and then call a variant of valueline on each path, each one with their respective data.
Related
Here is my code. I m currently using 2 csv files and when i add third one nothing appears on the screen. How do i add multiple csv files here?
Graph should update itself for each csv files in every 5 seconds.
I need your help, what code has to be added to make it even more dynamic.
I tried this part in code to make it work with 3 csv, But it din work.
function updateData() {
// Get the data again
d3.csv("data-alt.csv", function(error, data) {
d3.csv("alt.csv-data", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
Here is the overall code.
<!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 + ")");
// Get the data
d3.csv("data.csv", function(error, data) {
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
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
var inter = setInterval(function() {
updateData();
}, 5000);
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
d3.csv("data-alt.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Select the section we want to apply our changes to
var svg = d3.select("body").transition();
// Make the changes
svg.select(".line") // change the line
.duration(750)
.attr("d", valueline(data));
svg.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
</script>
</body>
You should break your function that handles parsing the result into another function, then just call d3.csv multiple times passing in the correct URL for the csv and the specific handler for that csv file.
Here is a quick snippet with the changes i suggested:
// 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 + ")");
function processDataCsv(error, data) {
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
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
}
function processAnotherCsv(error, data) {
// TODO: implement processing
}
function processYetAnotherCsv(error, data) {
// TODO: implement processing
}
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
d3.csv("data.csv", processDataCsv);
d3.csv("another.csv", processAnotherCsv);
d3.csv("yetAnother.csv", processYetAnotherCsv);
}
// Get the data, just use the function you already wrote to do that
updateData();
var inter = setInterval(function() {
updateData();
}, 5000);
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;
}
<script src="http://d3js.org/d3.v3.min.js"></script>
How can I make a scatterplot plotting time of day against date, which looks like this in using javascript and d3? The problem I am having is formatting the time of day data and axis. Input of the date is in the y column format below.
Sample data:
Day Time
5-Feb-16 21:35:00
5-Feb-16 19:15:00
11-Dec-15 21:42:00
21-Jul-15 11:00:00
Code below inspired by:
http://bl.ocks.org/d3noob/38744a17f9c0141bcd04
What I have so far:
<!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.Day); })
.y(function(d) { return y(d.Time); });
// 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.csv("data.csv", function(error, data) {
data.forEach(function(d) {
console.log(d.Time);
d.Day = parseDate(d.Day);
d.Time = +d.Time;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.Day; }));
y.domain([0, d3.max(data, function(d) { return d.Time; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.Day); })
.attr("cy", function(d) { return y(d.Time); });
// 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>
My output:
Is there a way to parse times and be able to plot them directly using javascript and d3? Or do I need to convert them to decimal numbers like 12:30 = 12.5 to plot them?
If you're using time in the y scale, you should parse the Time column as well:
var parseDate = d3.time.format("%d-%b-%y").parse;
var parseTime = d3.time.format("%H:%M:%S").parse;
Here is your code with just 4 points (the ones of the CSV you copy/pasted in your question):
var margin = {
top: 30,
right: 20,
bottom: 30,
left: 80
},
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;
var parseTime = d3.time.format("%H:%M:%S").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.time.scale().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");
// Define the line
var valueline = d3.svg.line()
.x(function(d) {
return x(d.Day);
})
.y(function(d) {
return y(d.Time);
});
// 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
var data = d3.csv.parse(d3.select("#csv").text());
data.forEach(function(d) {
d.Day = parseDate(d.Day);
d.Time = parseTime(d.Time);
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.Day;
}));
y.domain([parseTime("00:00:01"), parseTime("23:59:59")]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3.5)
.attr("cx", function(d) {
return x(d.Day);
})
.attr("cy", function(d) {
return y(d.Time);
});
// 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);
pre {
display: none;
}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
<script src="//d3js.org/d3.v3.min.js"></script>
<pre id="csv">Day,Time
5-Feb-16,21:35:00
1-Feb-16,19:15:00
11-Dec-15,21:42:00
21-Jul-15,11:00:00</pre>
I'm using on d3.js, and it's working fine.But i'm not figuring out why the scatter serie is not displayed.
this is my code:
<!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>
<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: 70},
width = 1000 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%H-%M-%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);
// Adds the plot
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 + ")");
lineSerie();
scatterSerie();
function lineSerie(){
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
d3.csv("timeSeries.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain(d3.extent(data, function(d) { return d.close; }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".60em")
.style("text-anchor", "end")
.text("CPU RunQueue");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
});
}
function scatterSerie(){
d3.csv("scatterSerie.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); });
});
}
</script>
</body>
line serie:
date,close
05-17-14-Oct-14,223233.06250
05-18-14-Oct-14,223233.06250
05-19-14-Oct-14,223233.06250
05-20-14-Oct-14,223233.06250
05-21-14-Oct-14,223233.06250
05-22-14-Oct-14,223233.06250
05-23-14-Oct-14,223233.06250
05-24-14-Oct-14,223233.06250
05-25-14-Oct-14,223233.06250
line serie
date,close
10-27-02-Oct-14,223233.06250
10-28-02-Oct-14,223233.06250
10-29-02-Oct-14,223233.06250
10-30-02-Oct-14,223233.06250
10-31-02-Oct-14,223233.06250
10-32-02-Oct-14,223233.06250
10-33-02-Oct-14,223233.06250
10-34-02-Oct-14,223233.06250
10-35-02-Oct-14,223233.06250
10-36-02-Oct-14,223233.06250
10-37-02-Oct-14,223233.06250
10-38-02-Oct-14,223233.06250
the line serie is displayed, but the scatter serie is not being displayed.
Can someone tell me what's wrong?
thanks in advance.
In your scatterSerie() function, your select statement doesn't add up.
There's no such thing as a 'dot' element. You'll want to select all elements with class 'dot' like so (think jQuery):
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr('class','dot')
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); });
Don't forget to set that 'dot' class to your newly added elements, otherwise your future updates might go south.
One other thing you might wanna look into is the style of your circles. Right now they have no defined stroke color, stroke-width or fill. You can add those as CSS rules or add them within your d3 code.
I'm using code similar to this one, and actually plugged in this code to see if I get the same error and I do. This is the code:
<!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;
}
.legend {
font-size: 16px;
font-weight: bold;
text-anchor: start;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 30, right: 40, bottom: 70, left: 50},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse;
var x = d3.time.scale().range([0, width]);
var y0 = d3.scale.linear().range([height, 0]);
var y1 = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxisLeft = d3.svg.axis().scale(y0)
.orient("left").ticks(5);
var yAxisRight = d3.svg.axis().scale(y1)
.orient("right").ticks(5);
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y0(d.close); });
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y1(d.open); });
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 + ")");
var data = [
{"date":"9-Apr-12","close":436,"open":9.04},
{"date":"7-Apr-12","close":221,"open":4.02},
{"date":"5-Apr-12","close":113,"open":9.02},
{"date":"4-Apr-12","close":64,"open":32.05},
{"date":"3-Apr-12","close":29,"open":46.03},
{"date":"2-Apr-12","close":18,"open":51.03}
];
// Get the data
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
d.open = +d.open;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y0.domain([0, d3.max(data, function(d) {
return Math.max(d.close); })]);
y1.domain([0, d3.max(data, function(d) {
return Math.max(d.open); })]);
svg.append("path")
.attr("class", "line")
.attr("id", "blueLine")
.attr("d", valueline(data));
svg.append("path")
.attr("class", "line")
.style("stroke", "red")
.attr("id", "redLine")
.attr("d", valueline2(data));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// edit the Y Axis Left
svg.append("g")
.attr("class", "y axis")
.style("fill", "steelblue")
.attr("id", "blueAxis")
.call(yAxisLeft);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + " ,0)")
.style("fill", "red")
.attr("id", "redAxis")
.call(yAxisRight);
// Add the blue line title
svg.append("text")
.attr("x", 0)
.attr("y", height + margin.top + 10)
.attr("class", "legend")
.style("fill", "steelblue")
.on("click", function(){
// Determine if current line is visible
var active = blueLine.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements
d3.select("#blueLine").style("opacity", newOpacity);
d3.select("#blueAxis").style("opacity", newOpacity);
// Update whether or not the elements are active
blueLine.active = active;
})
.text("Blue Line");
// Add the red line title
svg.append("text")
.attr("x", 0)
.attr("y", height + margin.top + 30)
.attr("class", "legend")
.style("fill", "red")
.on("click", function(){
// Determine if current line is visible
var active = redLine.active ? false : true ,
newOpacity = active ? 0 : 1;
// Hide or show the elements
d3.select("#redLine").style("opacity", newOpacity);
d3.select("#redAxis").style("opacity", newOpacity);
// Update whether or not the elements are active
redLine.active = active;
})
.text("Red Line");
</script>
</body>
I'm getting errors saying that 'blueline' and 'redline' are not defined.
Where do I define those?
I've looked at similar code where the html, css, and js are separated into their own files which is how I've done it also, and other than what I see in the code above I don't find those variables used anyplace else or defined beyond what is there.
I made a plunk with the code you have there and everything works just fine. Let me explain a little of what is going on though.
Instead of using HTML that is already there, D3 will often generate its own (in fact it has to generate its own to do the visualizations). You see this with statements like the following:
svg.append("path")
.attr("class", "line")
.attr("id", "blueLine")
.attr("d", valueline(data));
D3 just created a path element and appended it to the svg element it created earlier. It gives this particular element an id of blueLine which it uses later to apply styles. It did not exist in any HTML prior to this script running. D3 created it.
It is my version of "Multi-line graph 4: Toggle" from http://bl.ocks.org/d3noob/e99a762017060ce81c76 but I ran into some problems pls help.
At first the initial graph is correct,
after the zooms, the line would become one which used data for both line and rotated.
I think it is the zoomed functions is not doing right, when I used "d.value" the browser would say "d. is not define"
Here are the codes:
// https://github.com/mbostock/d3/wiki/Ordinal-Scales#category10
var colors = d3.scale.category10();
var margin = {top: 20, right: 30, bottom: 80, left: 85},
width = 900 - margin.left - margin.right,
height = 570 - margin.top - margin.bottom;
// Kind of defining the length and the directions of the axis
var x = d3.scale.linear()
.range([0, width]);
// Since the origin is on the left corner, the y axis of the svg system points down
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.tickSize(-height)
.tickPadding(10) // Distance between axis and tick note
.tickSubdivide(true)
.tickFormat(d3.format(".0"))
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.tickPadding(10)
.tickSize(-width)
.tickSubdivide(true)
.tickFormat(d3.format(".3e")) // https://github.com/mbostock/d3/wiki/Formatting#d3_format
.orient("left");
var valueline = d3.svg.line()
.x(function(d) { return x(d.samples); })
.y(function(d) { return y(d.measurements); });
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([0.1, 50])
.on("zoom", zoomed);
// Adding svg canvas
var svg = d3.select("body").append("svg")
.call(zoom)
.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
data=[{"SAMPLES":"1","MEASUREMENTS":"2","ID":"ch1"},{"SAMPLES":"2","MEASUREMENTS":"3","ID":"ch1"},{"SAMPLES":"1","MEASUREMENTS":"4","ID":"ch2"},{"SAMPLES":"3","MEASUREMENTS":"5","ID":"ch1"},{"SAMPLES":"2","MEASUREMENTS":"6","ID":"ch2"}];
data.forEach(function(d) {
d.samples = +d.SAMPLES;
d.measurements = +d.MEASUREMENTS;
});
console.log(data);
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.samples; }));
y.domain([0, d3.max(data, function(d) { return d.measurements; })]);
// Creating X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Drawing notations
svg.append("g")
.attr("class", "x axis")
.append("text")
.attr("class", "axis-label")
.attr("x", (width - margin.left)/2)
.attr("y", height + margin.top + 45)
.text('Samples');
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "y axis")
.append("text")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.attr("y", (-margin.left) + 10)
.attr("x", -height/2)
.text('Volts');
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
// Nest the entries by channel id (ID)
var dataNest = d3.nest()
.key(function(d) {return d.ID;})
.entries(data);
// set the colour scale
var color = d3.scale.category10();
// Auto spacing for the legend
legendSpace = width/dataNest.length;
// Loop through each IDs / key to draw the lines and the legend labels
dataNest.forEach(function(d,i) {
svg.append("path")
.attr("class", "line")
.attr("clip-path", "url(#clip)")
.style("stroke", function() { // Add the colours dynamically
return d.color = color(d.key);
})
.attr("id", 'tag'+d.key.replace(/\s+/g, '')) // assign ID
.attr("d", valueline(d.values))
.style("stroke", function(){return d.color = color(d.key);});
// Adding legends
svg.append("text")
// Setting coordinates and classes
.attr("x", (legendSpace/2)+i*legendSpace)
.attr("y", height + (margin.bottom/2)+ 5)
.attr("class", "legend")
// Setting colors
.style("fill",function(){
return d.color = color(d.key);
})
// Setting 'click' events
.on("click", function(){
// Determine if current line is visible
var active = d.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements based on the ID
d3.select("#tag"+d.key.replace(/\s+/g, ''))
.transition().duration(600)
.style("opacity", newOpacity);
// Update whether or not the elements are active
d.active = active;
})
.text(function() {
if (d.key == '28-00043b6ef8ff') {return "Inlet";}
if (d.key == '28-00043e9049ff') {return "Ambient";}
if (d.key == '28-00043e8defff') {return "Outlet";}
else {return d.key;}
})
})
// Zoom specific updates
function zoomed() {
svg.select(".x.axis")
.transition().duration(500)
.call(xAxis);
svg.select(".y.axis")
.transition().duration(500)
.call(yAxis);
svg.selectAll('path.line')
.transition().duration(500)
.attr('d', valueline(data));
}
body {
font: 12px Arial;
margin: 50px;
}
.axis path {
fill: none;
stroke: #bbb;
stroke-width: 2;
shape-rendering: crispEdges;
}
.axis text {
fill: #555;
}
.axis line {
fill: none;
stroke-width: 1;
stroke: #e7e7e7;
shape-rendering: crispEdges;
}
.axis .axis-label {
font-size: 14px;
}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.legend {
font-size: 16px;
font-weight: bold;
text-anchor: middle;
}
You need to bind your paths to your data, so you can call valueLine with the correct data for the path when zooming.
Use d3 data and enter functions when adding a new path:
// choose all .line objects and append a path which is not already binded
// by comparing its data to the current key
svg.selectAll(".line").data([d], function (d) {
return d.key;
})
.enter().append("path")
.attr("class", "line")
Then when you zoom, change the d attribute path by calling valueLine with the path's correct values:
svg.selectAll('path.line')
.transition().duration(500)
.attr('d', function(d) {
return valueline(d.values)
});
Plunker