Related
I want show and hide a graph with the same button in d3.js.
I use d3.js to create this graph. I don't know if I have use a addlistener o something like that.
The d3.js code is as follows:
<style>
#wrapper
{
min-width:960px;
margin-left:auto;
margin-right:auto;
}
#top
{
width: 100%;
height: 40px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.dot {
stroke: #000;
}
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
/* pointer-events: none; This line needs to be removed */
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 1300 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var div = d3.select("body")
.append("div") // declare the tooltip div
.attr("class", "tooltip") // apply the 'tooltip' class
.style("opacity", 0);
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 + ")"));
d3.json("/projects/chart/data", function (error, data) {
if (error)
throw error;
data.forEach(function (d) {
d.sepalLength = +d.sepalLength;
d.sepalWidth = +d.sepalWidth;
});
x.domain(d3.extent(data, function (d) {
return d.sepalWidth;
})).nice();
y.domain(d3.extent(data, function (d) {
return d.sepalLength;
})).nice();
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("Sepal Width (cm)");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Sepal Length (cm)")
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function (d) {
return x(d.sepalWidth);
})
.attr("cy", function (d) {
return y(d.sepalLength);
})
.style("fill", function (d) {
return color(d.species);
})
.on("mouseover", function (d) {
div.transition()
.duration(500)
.style("opacity", 0);
div.transition()
.duration(200)
.style("opacity", .9);
div.html(
'<a href= "http://homestead.app/process/'+d.sepalWidth+'">' + // The first <a> tag
d.sepalWidth +
"</a>" + // closing </a> tag
"<br/>" + d.sepalLength)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
});
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function (d, i) {
return "translate(0," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function (d) {
return d;
});
});
</script>
I want to use the same button if it's possible.
Quick example of what could work :
HTML :
<button onclick='toggleGraph()'> </button>
JavaScript :
var showGraph = true;
function toggleGraph(){
var graph = d3.select('#graph'); //i recommend giving the graph an ID
if(showGraph){ //check bool
graph.style('visibility', 'hidden'); //hide graph
showGraph = false; //toggle bool
} else {
graph.style('visibility', 'visible'); //show graph
showGraph = true; //toggle bool
}
}
I am having some issues with tooltips for my bar graph. For each stopname column, there should be a corresponding value of boarding and alightings shown in the tooltip, however, I am getting undefined values like here
Here is my code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: orange;
}
.bar:hover {
fill: orangered ;
}
.x.axis path {
display: none;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var margin = {top: 40, right: 20, bottom: 300, left: 40},
width = 1250 - margin.left - margin.right,
height = 750 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["orange", "orangered"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Stop:</strong> <span style='color:red'>" + d.stopname + "</span>" + "<br><br><strong>Mean no. of boardings:</strong> <span style='color:red'>" + d.meanboardings + "</span>"+ "<br><br><strong>Mean no. of alightings:</strong> <span style='color:red'>" + d.meanalightings + "</span>";
})
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 + ")");
svg.call(tip);
d3.tsv("data.tsv", function(d){
return {
stopname: d.stopname,
meanboardings: +d.meanboardings,
meanalightings: +d.meanalightings
};
}, function(error, data) {
console.log(data);
var dataset = d3.keys(data[0]).filter(function(key) { return key !== "stopname"
});
data.forEach(function(d) {
d.passengers = dataset.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.stopname; }));
x1.domain(dataset).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.passengers, function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", function(d) {
return "rotate(-90)"
});
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Mean no. of boardings and alightings");
var stopname = svg.selectAll(".stopname")
.data(data)
.enter().append("g")
.attr("class", "stopname")
.attr("transform", function(d) { return "translate(" + x0(d.stopname) + ",0)"; });
stopname.selectAll("rect")
.data(function(d) { return d.passengers; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
var legend = svg.selectAll(".legend")
.data(dataset.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.name); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
});
function type(d) {
d.data = +d.data;
return d;
}
</script>
TSV file:
stopname maxboardings meanboardings minboardings varboardings maxalightings meanalightings minalightings varalightings maxload meanload minload varload noofbuses
The Boardwalk Terminal (3908) 7 2.571428571 0 6.952380952 0 0 0 0 7 2.571428571 0 6.952380952 7
Highview / Sugar Maple (3329) 2 0.333333333 0 0.666666667 1 0.166666667 0 0.166666667 6 3 0 6.4 6
Highview / Highview Pl (3330) 0 0 0 0 1 0.166666667 0 0.166666667 5 2.833333333 0 5.366666667 6
....
Any help is appreciated, thank you!
You are getting undefined because you are using an undefined value for generating tooltip text.
In your html function, the data-object associated d you get for every rectangle/bar is of following format:
{name: "meanlightings", value: <some_value>}
It does not contain the stopname property and will only contain value for one of the fields in the original dataset.
You will have to rewrite the html callback as
.html(function(d) {
return "<strong>" + d.name + " :</strong> <span style='color:red'>" + d.value + "</span>";
})
However, if you want to show more properties, you will have to change the data that you are binding to rectangles.
I'm trying to make a d3 scatterplot recurring to json data. I know that d3 has d3.json to load json data but my code isn't working. I'm not that good dealing with js (it's my first time with this language), that's why I need help in this.
Basically, I need to plot this data (date in xAxis and IADP_mGycm2 in yAxis):
[
{
"imageID": 1,
"value": 288.3,
"date": "2015-10-22"
},
{
"imageID": 2,
"value": 188.1,
"date": "2015-10-22"
}
]
JS:
var margin = { top: 50, right: 300, bottom: 50, left: 50 },
outerWidth = 1050,
outerHeight = 500,
width = outerWidth - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]).nice();
var y = d3.scale.linear()
.range([height, 0]).nice();
var xCat = "date",
yCat = "value";
d3.json("CR.json", function(error, rawData) {
if (error) {
console.error(error);
return;
}
var data = rawData.map(function (d) {
return {
date: d.date,
value: d.value
}
});
var xMax = d3.max(data, function(d) { return d["date"]; }),
xMin = d3.min(data, function(d) { return d["date"]; }),
xMin = xMin > 0 ? 0 : xMin,
yMax = d3.max(data, function(d) { return d["value"]; }) ,
yMin = d3.min(data, function(d) { return d["value"]; }),
yMin = yMin > 0 ? 0 : yMin;
x.domain([xMin, xMax]);
y.domain([yMin, yMax]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickSize(-width);
var color = d3.scale.category10();
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(function(d) {
return xCat + ": " + d["date"] + "<br>" + yCat + ": " + d["value"];
});
var zoomBeh = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([0, 500])
.on("zoom", zoom);
var svg = d3.select("#scatter")
.append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoomBeh);
svg.call(tip);
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.classed("x axis", true)
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.classed("label", true)
.attr("x", width)
.attr("y", margin.bottom - 10)
.style("text-anchor", "end")
.text(xCat);
svg.append("g")
.classed("y axis", true)
.call(yAxis)
.append("text")
.classed("label", true)
.attr("transform", "rotate(-90)")
.attr("y", -margin.left)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(yCat);
var objects = svg.append("svg")
.classed("objects", true)
.attr("width", width)
.attr("height", height);
objects.append("svg:line")
.classed("axisLine hAxisLine", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", width)
.attr("y2", 0)
.attr("transform", "translate(0," + height + ")");
objects.append("svg:line")
.classed("axisLine vAxisLine", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", height);
objects.selectAll(".dot")
.data(data)
.enter().append("circle")
.classed("dot", true)
.attr("cy", function (d) { return d.value; })
.attr("cx", function (d) { return d.date; })
.attr("transform", transform)
.style("fill", "red")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.classed("legend", true)
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("circle")
.attr("r", 3.5)
.attr("cx", width + 20)
.attr("fill", color);
legend.append("text")
.attr("x", width + 26)
.attr("dy", ".35em")
.text(function(d) { return d; });
d3.select("input").on("click", change);
function change() {
xCat = "date";
xMax = d3.max(data, function(d) { return d["date"]; });
xMin = d3.min(data, function(d) { return d["date"]; });
zoomBeh.x(x.domain([xMin, xMax])).y(y.domain([yMin, yMax]));
var svg = d3.select("#scatter").transition();
svg.select(".x.axis").duration(750).call(xAxis).select(".label").text("date");
objects.selectAll(".dot").transition().duration(1000).attr("transform", transform);
}
function zoom() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll(".dot")
.attr("transform", transform);
}
function transform(d) {
return "translate(" + x(d["date"]) + "," + y(d["value"]) + ")";
}
});
HTML:
<html>
<head>
<meta charset="utf-8">
<title>Visualization</title>
<link rel="stylesheet" href="scatter.css" charset="utf-8">
</head>
<body>
<div id="scatter"></div>
<input type="button" name="xAxis" value="xAxis">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script src="scatter.js" charset="utf-8"></script>
</body>
</html>
CSS:
rect {
fill: transparent;
shape-rendering: crispEdges;
}
.axis path,
.axis line {
fill: none;
stroke: rgba(0, 0, 0, 0.1);
shape-rendering: crispEdges;
}
.axisLine {
fill: none;
shape-rendering: crispEdges;
stroke: rgba(0, 0, 0, 0.5);
stroke-width: 2px;
}
.dot {
fill-opacity: .5;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
Thanks in advance!
One issue I see is that you're missing a }) at the end of this code chunk:
var data = rawData.map(function (d) {
return {
date: d.date,
IADP_mGycm2: d.IADP_mGycm2
};
Try changing it to this:
var data = rawData.map(function (d) {
return {
date: d.date,
IADP_mGycm2: d.IADP_mGycm2
}
});
It also helps in debugging if you include the specific error message you're getting.
Well, you define xCat as:
var xCat = "Date"
but your mapping function uses:
date: d.date
so, when you reference d[xCat] what you are getting is d.Date (which is undefined and would cause NaN) instead of d.date. That's all I can see with a quick look through.
You can fix this by using d['date'] or d.date instead of d[xCat].
Ok, after looking a little further at this, I've identified a couple of problems. The main issue is that the chart you are trying to emulate has numeric values on both the x and y axes. However, you are trying to use dates. In order to do that, you have to use d3.time.scale() for the x-axis instead of a linear scale. You also have to transform the date strings from your data to date objects and use your time scale to scale your x-axis values. Here is scatter.js with the changes:
var margin = { top: 50, right: 300, bottom: 50, left: 50 },
outerWidth = 1050,
outerHeight = 500,
width = outerWidth - margin.left - margin.right,
height = outerHeight - margin.top - margin.bottom;
// Use a time scale for the x-axis
var x = d3.time.scale()
.range([0, width]).nice();
var y = d3.scale.linear()
.range([height, 0]).nice();
var xCat = "date",
yCat = "Dose";
d3.json("CR.json", function(error, rawData) {
if (error) {
console.error(error);
return;
}
var data = rawData.map(function(d) {
return {
// Create date objects, not strings
date: new Date(d.date),
IADP_mGycm2: d.IADP_mGycm2
}
});
var xMax = d3.max(data, function(d) { return d["date"]; }),
xMin = d3.min(data, function(d) { return d["date"]; }),
//xMin = xMin > 0 ? 0 : xMin,
yMax = d3.max(data, function(d) { return d["IADP_mGycm2"]; }),
yMin = d3.min(data, function(d) { return d["IADP_mGycm2"]; });
//yMin = yMin > 0 ? 0 : yMin;
x.domain([xMin, xMax]);
y.domain([yMin, yMax]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickSize(-width);
var color = d3.scale.category10();
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(function(d) {
return xCat + ": " + d["date"] + "<br>" + yCat + ": " + d["IADP_mGycm2"];
});
var zoomBeh = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([0, 500])
.on("zoom", zoom);
var svg = d3.select("#scatter")
.append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoomBeh);
svg.call(tip);
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.classed("x axis", true)
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.classed("label", true)
.attr("x", width)
.attr("y", margin.bottom - 10)
.style("text-anchor", "end")
.text(xCat);
svg.append("g")
.classed("y axis", true)
.call(yAxis)
.append("text")
.classed("label", true)
.attr("transform", "rotate(-90)")
.attr("y", -margin.left)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(yCat);
var objects = svg.append("svg")
.classed("objects", true)
.attr("width", width)
.attr("height", height);
objects.append("svg:line")
.classed("axisLine hAxisLine", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", width)
.attr("y2", 0)
.attr("transform", "translate(0," + height + ")");
objects.append("svg:line")
.classed("axisLine vAxisLine", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", height);
objects.selectAll(".dot")
.data(data)
.enter().append("circle")
.classed("dot", true)
.attr("cy", function(d) { return d.IADP_mGycm2; })
// Use the time scale to scale the values for the x-axis
.attr("cx", function(d) { return x(d.date); })
.attr("transform", transform)
.style("fill", "red")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.classed("legend", true)
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("circle")
.attr("r", 3.5)
.attr("cx", width + 20)
.attr("fill", color);
legend.append("text")
.attr("x", width + 26)
.attr("dy", ".35em")
.text(function(d) { return d; });
d3.select("input").on("click", change);
function change() {
xCat = "date";
xMax = d3.max(data, function(d) { return d["date"]; });
xMin = d3.min(data, function(d) { return d["date"]; });
zoomBeh.x(x.domain([xMin, xMax])).y(y.domain([yMin, yMax]));
var svg = d3.select("#scatter").transition();
svg.select(".x.axis").duration(750).call(xAxis).select(".label").text("date");
objects.selectAll(".dot").transition().duration(1000).attr("transform", transform);
}
function zoom() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll(".dot")
.attr("transform", transform);
}
function transform(d) {
return "translate(" + x(d["date"]) + "," + y(d["IADP_mGycm2"]) + ")";
}
});
This gets rid of the errors you were seeing, but it still doesn't plot the circles correctly. Sorry, I don't have the time to work all that out. However, this should move you forward and get you closer to figuring it out yourself. To learn more about time scales, see https://github.com/mbostock/d3/wiki/Time-Scales. Also, if you really want to learn D3, I highly recommend the book D3.js in Action by Elijah Meeks. https://www.manning.com/books/d3-js-in-action. One of the better programming books I have read.
So, my code is here if you want to check it out.
Anyway, I'm developing a multi-line graph with tooltips and a legend that has each line disappear with a click. Only issue is, my lines don't want to generate inside the loop (in my case, dataNest) that will let me create a unique ID for each line.
This is the code I need to get working inside that loop:
svg.append("path")
.attr("class", "line")
.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", line(d.values));
Nesting your data with d3.nest() using key() will give you a different data structure for dataNest.
nest.key(function)
...Each time a key is registered, it is pushed onto the end of an internal keys array, and the resulting map or entries will have an additional hierarchy level.
nest.key(function)
So you have to call line when filling d attribute like this .attr("d", line(d.values[0].values)) .
Here are some examples on how d3.nest() works.
function init(){
var data = [
{
"label":"internal",
"values":[
{"week":1,"val":37},
{"week":2,"val":38},
{"week":3,"val":33},
{"week":4,"val":32},
{"week":5,"val":40},
{"week":6,"val":27},
{"week":7,"val":30},
{"week":8,"val":37},
{"week":9,"val":42},
{"week":10,"val":36},
{"week":11,"val":35},
{"week":12,"val":37},
{"week":13,"val":33}
]
},
{
"label": "high",
"values": [
{"week":1,"val":41},
{"week":2,"val":41},
{"week":3,"val":41},
{"week":4,"val":39},
{"week":5,"val":41},
{"week":6,"val":49},
{"week":7,"val":38},
{"week":8,"val":42},
{"week":9,"val":51},
{"week":10,"val":38},
{"week":11,"val":48},
{"week":12,"val":50},
{"week":13,"val":40},
]
},
{
"label": "low",
"values":[
{"week":1,"val":16},
{"week":2,"val":17},
{"week":3,"val":14},
{"week":4,"val":15},
{"week":5,"val":18},
{"week":6,"val":20},
{"week":7,"val":18},
{"week":8,"val":14},
{"week":9,"val":14},
{"week":10,"val":19},
{"week":11,"val":21},
{"week":12,"val":16},
{"week":13,"val":17},
],
},
{
"label":"average",
"values":[
{"week":1,"val":28.5},
{"week":2,"val":29},
{"week":3,"val":27.5},
{"week":4,"val":27},
{"week":5,"val":29.5},
{"week":6,"val":34.5},
{"week":7,"val":28},
{"week":8,"val":28},
{"week":9,"val":32.5},
{"week":10,"val":28.5},
{"week":11,"val":34.5},
{"week":12,"val":33},
{"week":13,"val":28.5}
]
}
]
var margin = {
top: 20,
right: 80,
bottom: 60,
left: 50
},
width = 895 - margin.left - margin.right,
height = 355 - margin.top - margin.bottom;
var x = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category20();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(6)
.tickSize(0);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickSize(0);
var line = d3.svg.line()
.x(function (d) {return x(d.week);})
.y(function (d) {return y(d.val);})
.interpolate("Linear");
// Define 'div' for tooltips
var div = d3.select('#multiline').append("div") // declare the properties for the div used for the tooltips
.attr("class", "tooltip") // apply the 'tooltip' class
.style("opacity", 0); //
var svg = d3.select('#multiline').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 + ")");
color.domain(data.map(function (d) { return d.label; }));
data.forEach(function (kv) {
var labelName = kv.label;
kv.values.forEach(function (d) {
d.val = +d.val;
d.label = labelName;
});
});
var dataNest = d3.nest()
.key(function(d) {return d.label;})
.entries(data);
function make_y_axis() { // function for the y grid lines
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10)
}
var minY = d3.min(data, function (kv) { return d3.min(kv.values, function (d) { return d.val; }) });
var maxY = d3.max(data, function (kv) { return d3.max(kv.values, function (d) { return d.val + 5; }) });
var padding = width/(data[0].values.length + 1)/2;
x.domain(data[0].values.map(function (d) { return d.week; }))
.rangePoints([padding, width-padding]);
y.domain([0, 1.3*(maxY)]);
svg.append("svg:rect") // Grid lines Bakcground
.attr("x", 0)
.attr("y", 0)
.attr("height", height)
.attr("width", width)
.attr("fill", "#E6E6E6")
.style("opacity", "0.3");
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", ".71em")
.style("text-anchor", "end");
svg.append("g") // Draw the y Grid lines
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
);
var city = svg.selectAll(".branch")
.data(data)
.enter().append("g")
.attr("class", "branch");
city.append("path")
.attr("class", "line")
.attr("d", function (d) {
return line(d.values);
})
.style("stroke", function (d) {
return color(d.label);
})
.style("fill", "none")
.style("stroke-width", 3);
svg.selectAll("g.dot")
.data(data)
.enter().append("g")
.attr("class", "dot")
.selectAll("circle")
.data(function(d) { return d.values; })
.enter().append("circle")
.attr("r", 2)
.attr("cx", function(d,i) { return x(d.week); })
.attr("cy", function(d,i) { return y(d.val); })
.style("stroke", function (d) {
return color(d.label);
})
.style("fill", "none")
.style("stroke-width", 3)
// Tooltip stuff after this
.on("mouseover", function(d) { // when the mouse goes over a circle, do the following
div.transition() // declare the transition properties to bring fade-in div
.duration(200) // it shall take 200ms
.style("opacity", .9); // and go all the way to an opacity of .9
div .html(d.label + "<br/>" + d.week + "<br/>" + d.val) // add the text of the tooltip as html
.style("left", (d3.event.pageX) + "px") // move it in the x direction
.style("top", (d3.event.pageY - 28) + "px"); // move it in the y direction
}) //
.on("mouseout", function(d) { // when the mouse leaves a circle, do the following
div.transition() // declare the transition properties to fade-out the div
.duration(500) // it shall take 500ms
.style("opacity", 0); // and go all the way to an opacity of nil
});
legendSpace = width/dataNest.length; // spacing for the legend
// Loop through each symbol / key
dataNest.forEach(function(d,i) {
svg.append("path")
.attr("class", "line")
.attr("d", line(d.values[0].values))
.attr("id", 'tag'+d.key.replace(/\s+/g, ''))
.style("stroke", color(d.label))
.style("fill", "none")
.style("stroke-width", 3);
// Add the Legend
svg.append("text")
.attr("x", (legendSpace/2)+i*legendSpace) // space legend
.attr("y", height + (margin.bottom/2)+ 20)
.attr("class", "legend") // style the legend
.style("fill", function() { // Add the colours dynamically
return d.color = color(d.key); })
.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(100)
.style("opacity", newOpacity);
// Update whether or not the elements are active
d.active = active;
})
.text(d.key);
});
}
init();
.axis path, .axis line {
fill: none;
shape-rendering: crispedges;
stroke: none;
}
.axis line{
fill:none;
shape-rendering: crispedges;
stroke:grey;
}
.grid .tick {
stroke: grey;
opacity: 0.5 !important;
}
.bar rect {
fill: #ed1e79;
}
.bar text.value {
fill: black;
}
circle {
fill: blue;
stroke: blue;
stroke-width: 2;
}
.tooltip {
background: none repeat scroll 0 0 #ed1e79;
border: 0 solid #ffffff;
border-radius: 8px;
color: #ffffff;
font: 12px sans-serif;
height: 38px;
padding: 2px;
pointer-events: none;
position: absolute;
text-align: center;
width: 90px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="multiline"></div>
I made a simple bar chart using D3.js. The data for the chart is coming from a csv file. I would like for the chart to be updated every 2.5 seconds showing the new data. Right now, after updating the csv file the X and Y axis will update but the bars and mouseover tooltip shows the old values. I have looked at many different examples. Here are a few I have referenced. Anyone know what is going on?
http://mbostock.github.io/d3/tutorial/bar-2.html
http://www.d3noob.org/search?q=update
d3 update data and update graph
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Bar Chart</title>
<style type="text/css">
.bar {
fill: steelblue;
}
.bar:hover {
fill: brown;
}
div.tooltip {
position: absolute;
text-align: left;
width: auto;
height: auto;
padding: 2px;
font-family: sans-serif;
font-size: 14px;
background: white;
border: 2;
border-radius: 5px;
pointer-events: none;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 45},
width = 1000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickPadding(5);
//var data = [{"label":"Boone","values":0.8},{"label":"Story","values":0.2},{"label":"Polk","values":0.4}]
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("opacity", 0);
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 + ")")
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.label = d.label;
d.values = +d.values;
});
x.domain(data.map(function(d) { return d.label; }));
y.domain([0, d3.max(data, function(d) { return d.values; })]);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-0)")
.attr("x", -10)
.attr("y", -16)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Values");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.on("mouseover", function(d) {
div.transition()
.duration(100)
.style("opacity", 1)
.style("left", (d3.event.pageX)+ "px")
.style("top", (d3.event.pageY) + "px");
div.html("<p>Label: " + d.label+ "<br>Value: " + d.values);
d3.select("#tooltip").classed("hidden", false);
})
.attr("class", "bar")
.attr("x", function(d) { return x(d.label); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.values); })
.attr("height", function(d) { return height - y(d.values); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", 30)
.style("text-anchor", "end")
.text("Label");
});
var inter = setInterval(function() {
updateData();
},2500);
function updateData() {
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.label = d.label;
d.values = +d.values;
});
x.domain(data.map(function(d) { return d.label; }));
y.domain([0, d3.max(data, function(d) { return d.values; })]);
var svg = d3.select("body")
var vis = svg.transition();
vis.select(".x.axis")
.duration(750)
.call(xAxis)
vis.select(".y.axis")
.duration(750)
.call(yAxis)
vis.select(".rect")
.duration(750)
.attr(".x", function(d) { return x(d.label); })
.attr(".y", function(d) { return y(d.values); })
});
}
</script>
</body>
</html>