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
}
}
Related
I was just wondering how to add a box with text in it to my D3.js chart. It will be acting as my legend, and will describe each variable on my x-axis. It should look something like this like this .
I would like to match each of the "wuc" labels to the "nomenclature" labels in this json array:
data = [{
"Wuc": "23A",
"Nomenclature": "Engine, Basic (F117-PW)",
"Hours": 155899.90
},
{
"Wuc": "23V",
"Nomenclature": "Fan Thrust Reverser",
"Hours": 56576
}
]
The bottom code is for my D3.js chart. Thanks for the help!
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<style>
.bars:hover {
fill: blue;
}
.legend:hover {
fill: blue;
}
/* tooltip for bar chart */
div.tooltip {
position: absolute;
text-align: center;
width: 50px;
height: 60px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<div id="bar_chart">
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// d3.json("data.json", function(error, data) {
// if (error) throw error;
// var parseTime = d3.timeParse("%M:%S");
// var timeformat = d3.timeFormat("%M:%S")
data = [{
"Wuc": "23A",
"Nomenclature": "Engine, Basic (F117-PW)",
"Hours": 155899.90
},
{
"Wuc": "23V",
"Nomenclature": "Fan Thrust Reverser",
"Hours": 56576
}
]
data.forEach(function(d) {
// d.atime = parseTime(d.atime);
d.Hours = +d.Hours;
});
var margin = {
top: 70,
right: 50,
bottom: 100,
left: 80
},
width = 600 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
//Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var x = d3.scaleBand()
.domain(data.map(function(d) {
return d.Wuc
}))
.range([0, width])
.padding([0.8]); //sets decimal of the space between bar centres
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.Hours
})])
.range([height, 0]);
var svg = d3.select("#bar_chart")
.data(data)
.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 + ")");
// Add the X Axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// text label for the x axis
svg.append("text")
.attr("x", width / 2)
.attr("y", margin.top + height)
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text("x-Axis Title");
// Add the Y Axis
svg.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y)
.ticks(5));
// text label for the y axis
svg.append("text")
.attr("class", "blah")
.attr("transform", "rotate(-90)")
.attr("x", 0 - height / 2)
.attr("y", -50)
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text("y-Axis Title");
// graph main title
svg.append("text")
.attr("x", width / 2)
.attr("y", -20)
.style("text-anchor", "middle")
.style("font-weight", "bold")
.style("font-size", "20px")
.text("Main Title");
//********* Bar Chart ****************
var rects = svg.selectAll('rect')
.data(data)
.enter();
rects.append('rect')
.on("mouseover", function(d, i, node) { //this is repeated should be in a function
div.transition()
.duration(200)
.style("opacity", .85);
div.html("<strong> Name:</strong> " + d.Wuc + "</br><strong> Value:</strong> " + d.Hours)
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
d3.select(this)
.style("fill", "blue");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this)
.style("fill", "lightblue");
})
.attr("class", "bars") //should fill blue on mouseover, not working???
.attr('x', function(d, i) {
return x(d.Wuc);
})
.attr('y', function(d, i) {
return y(d.Hours);
})
.attr('height', function(d, i) {
return height - y(d.Hours)
})
.attr('width', x.bandwidth())
.attr("transform", "translate(0,0)")
.style('fill', 'lightblue')
.style('stroke', 'lightgray');
// }); //closes function d3.json("data.json", function(error, data) {.....
</script>
You can simply append a 'rect' to the svg and also append text with data.
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<style>
.bars:hover {
fill: blue;
}
.legend:hover {
fill: lightblue;
}
/* tooltip for bar chart */
div.tooltip {
position: absolute;
text-align: center;
width: 50px;
height: 60px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<div id="bar_chart">
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// d3.json("data.json", function(error, data) {
// if (error) throw error;
// var parseTime = d3.timeParse("%M:%S");
// var timeformat = d3.timeFormat("%M:%S")
data = [{
"Wuc": "23A",
"Nomenclature": "Engine, Basic (F117-PW)",
"Hours": 155899.90
},
{
"Wuc": "23V",
"Nomenclature": "Fan Thrust Reverser",
"Hours": 56576
}
]
data.forEach(function(d) {
// d.atime = parseTime(d.atime);
d.Hours = +d.Hours;
});
var margin = {
top: 70,
right: 50,
bottom: 100,
left: 80
},
width = 600 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
//Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var x = d3.scaleBand()
.domain(data.map(function(d) {
return d.Wuc
}))
.range([0, width])
.padding([0.8]); //sets decimal of the space between bar centres
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.Hours
})])
.range([height, 0]);
var svg = d3.select("#bar_chart")
.data(data)
.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 + ")");
// Add the X Axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// text label for the x axis
svg.append("text")
.attr("x", width / 2)
.attr("y", margin.top + height)
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text("x-Axis Title");
// Add the Y Axis
svg.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y)
.ticks(5));
// text label for the y axis
svg.append("text")
.attr("class", "blah")
.attr("transform", "rotate(-90)")
.attr("x", 0 - height / 2)
.attr("y", -50)
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text("y-Axis Title");
// graph main title
svg.append("text")
.attr("x", width / 2)
.attr("y", -20)
.style("text-anchor", "middle")
.style("font-weight", "bold")
.style("font-size", "20px")
.text("Main Title");
//************* Legend ***************
// add legend rect gray
svg.append("rect")
.attr("class", "legend")
.attr("x", 280)
.attr("y", 30)
.attr("rx", "5px")
.attr("width", 230)
.attr("height", 80)
.attr("stroke", "darkgray")
.attr("fill", "white");
var legend_text = svg.selectAll("legend_text")
.data(data)
.enter();
legend_text.append("text")
.attr("class", "legend_text")
.attr("x", 290)
.attr("y", function(d, i) {
return (i * 20) + 40;
})
.attr("dy", "0.32em")
.style("font-weight", "bold")
.text(function(d) {
return d.Wuc + " " + d.Nomenclature;
});
//********* Bar Chart ****************
var rects = svg.selectAll(".bars")
.data(data)
.enter();
rects.append('rect')
.attr("class", "bars")
.on("mouseover", function(d, i, node) { //this is repeated should be in a function
div.transition()
.duration(200)
.style("opacity", .85);
div.html("<strong> Name:</strong> " + d.Wuc + "</br><strong> Value:</strong> " + d.Hours)
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
d3.select(this)
.style("fill", "blue");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this)
.style("fill", "lightblue");
})
.attr("class", "bars") //should fill blue on mouseover, not working???
.attr('x', function(d, i) {
return x(d.Wuc);
})
.attr('y', function(d, i) {
return y(d.Hours);
})
.attr('height', function(d, i) {
return height - y(d.Hours)
})
.attr('width', x.bandwidth())
.attr("transform", "translate(0,0)")
.style('fill', 'lightblue')
.style('stroke', 'lightgray');
// }); //closes function d3.json("data.json", function(error, data) {.....
</script>
You may also want to make the height of the rect dynamic to fit different amounts of of data.
I'm new to D3 and doing a project with student data from my college. I was following some tutorials to create a multi-line chart and I can't figure out what happened to my SVG. I set my height and width but it displays wired on screen. Here is my code:
<body>
<p>Students' Major by Gender.</p>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var MARGINS = {top: 50, right: 20, bottom: 50, left: 50},
WIDTH = 1500 - MARGINS.left - MARGINS.right,
HEIGHT = 800 - MARGINS.top - MARGINS.bottom;
var xScale = d3.scale.linear().range([0, WIDTH]),
yScale = d3.scale.linear().range([HEIGHT, 0]),
xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom").ticks(5),
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left").ticks(5);
var svg = d3.select("body")
.append("svg")
.attr("WIDTH", WIDTH + MARGINS.left + MARGINS.right)
.attr("HEIGHT", HEIGHT + MARGINS.top + MARGINS.bottom)
.append("g")
.attr("transform", "translate(" + MARGINS.left + "," + MARGINS.top + ")");
var colorScale = ["#FF0000", "#0000FF"];
var color = d3.scale.ordinal().range(colorScale);
d3.json("data/majors/major_ARCH.json", function(data) {
data.forEach(function(d) {
d.Year = +d.Year;
d.Gndr = d.Gndr;
d.Count = +d.Count;
});
function sortByDateAscending(a, b) {
//Years will be cast to numbers automagically:
return a.Year - b.Year;
}
data = data.sort(sortByDateAscending);
console.log(data);
var dataNest = d3.nest()
.key(function(d) { return d.Gndr; })
.entries(data);
var lSpace = WIDTH/dataNest.length;
var GenderLine = d3.svg.line()
.x(function(d) {
return xScale(d.Year);
})
.y(function(d) {
return yScale(d.Count);
})
xScale.domain([d3.min(data, function(d) {
return d.Year;
}), d3.max(data, function(d) {
return d.Year;
})]);
yScale.domain([d3.min(data, function(d) {
return d.Count;
}), d3.max(data, function(d) {
return d.Count;
})]);
dataNest.forEach(function(d, i) {
svg.append("path")
.attr('d', GenderLine(d.values, xScale, yScale))
.attr('stroke', function() {
return d.color = color(d.key);
})
.attr('stroke-width', 2)
.attr('id', 'line_' + d.key)
.attr('fill', 'none');
svg.append("text")
.attr("x", (lSpace / 2) + i * lSpace)
.attr("y", HEIGHT)
.style("fill", "black")
.attr("class", "legend")
.on('click', function() {
var active = d.active ? false : true;
var opacity = active ? 0 : 1;
d3.select("#line_" + d.key).style("opacity", opacity);
d.active = active;
})
.attr("stroke", function() {
return d.color = color(d.key);
})
.text(d.key);
})
svg.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("r", 5)
.attr("cx", function(d) { return xScale(d.Year); })
.attr("cy", function(d) { return yScale(d.Count); })
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9)
div.html(d.Year + "<br/>" +d.Count)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + HEIGHT + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
</script>
CSS:
.axis path {
fill: none;
stroke: #777;
shape-rendering: crispEdges;
}
.axis text {
font-family: Lato;
font-size: 13px;
}
/* Legend */
.legend {
font-size: 14px;
font-weight: bold;
}
/*Tooltip*/
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;
}
I tried to follow a post (Resize svg when window is resized in d3.js) to create a responsive svg but it was not working...
The two tutorials that I used to create my chart are:
http://bl.ocks.org/d3noob/a22c42db65eb00d4e369
https://code.tutsplus.com/tutorials/building-a-multi-line-chart-using-d3js-part-2--cms-22973
I want to make my svg responsive, and know the problems with my code. Thanks!
I am trying to make a stacked bar chart for a simple dataset (Below you can find codes and the data).
For the bar my mouse hovers on, I try to use CSS hover effect to change the color of the bar (A rect svg element with a class of .bar), and use d3-tip to show a tooltip displaying the region name that bar belongs.
Problems I am having are:
1 - The CSS hover effect is not working at all. (Please find the style sheet below)
2 - the tooltip is showing, but only if I move my mouse cursor from under the bar to enter it. If I move my mouse cursor from left/right/top of the bar, the "mouseover" seems like not being detected. When it is not detected, however if you click on the bar, it will be detected and tooltip will show.
3 - The tooltip is supposed to show the data for "d.State" (which is the region's abbreviation text), but it gives me undefined. "d.State" is working fine with the bar chart itself though - the axis ticks are created using these data.
The stacked bar is made based on this one: https://bl.ocks.org/mbostock/3886208
The tooltip and hover effect is based on this one: http://bl.ocks.org/Caged/6476579
The index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
</head>
<body>
<script type="text/javascript" src="viz.js"></script>
</body>
</html>
The viz.js:
// begin of the js file
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 320 - margin.left - margin.right,
height = 320 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#7b6888", "#a05d56", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
//define tooltip
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 0])
.html(function(d) {
return "<strong>Region:</strong> <span style='color:red'>" + d.State + "</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 + ")");
//call tooltip
svg.call(tip);
d3.csv("data.csv", function(error, data) {
if (error) throw error;
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "State"; }));
data.forEach(function(d) {
var y0 = 0;
d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.ages[d.ages.length - 1].y1;
});
data.sort(function(a, b) { return b.total - a.total; });
x.domain(data.map(function(d) { return d.State; }));
y.domain([0, d3.max(data, function(d) { return d.total; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("font-size", 7);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -40)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Number of Organizations");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.State) + ",1)"; });
state.selectAll(".bar")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("class", "bar")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); })
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
var legend = svg.selectAll(".legend")
.data(color.domain().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; });
});
// end of the js file
The style.css:
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar:hover {
fill: steelblue;
pointer-events: all;
}
.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;
}
The data.csv:
State,Non Profit,For Profit,Developer Group,Other
EP,28,142,15,16
EC,81,292,39,22
LC,73,91,23,9
MN,3,5,2,1
NA,102,561,26,19
SA,11,49,9,4
SS,28,10,10,3
If there is any part not clear please let me know. I am new to d3 and stackoverflow. Thanks!
The CSS hover effect is not working at all.(not was missing I guess ?)
The problem was it was already filled using d3. To override it just add !important to on hover fill
fill: steelblue !important;
The tooltip is showing, but only if I move my mouse cursor from under the bar to enter it. If I move my mouse cursor from left/right/top of the bar.(I didn't face any issue with your code ?)
I am not sure what exactly is the problem but, my guess is that, onmouseover will work only when you hover on it. So if the mouse pointer is already on the graph before it was generated, it won't show the tooltip.
The tooltip is supposed to show the data for "d.State".
The problem here is the State data is not attached to the element i.e, d.ages doesn't contain state value. Just attach the state value while binding data.
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 320 - margin.left - margin.right,
height = 320 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#7b6888", "#a05d56", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
//define tooltip
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 0])
.html(function(d) {
return "<strong>Region:</strong> <span style='color:red'>" + d.State + "</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 + ")");
//call tooltip
svg.call(tip);
d3.csv("data.csv", function(error, data) {
if (error) throw error;
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "State"; }));
data.forEach(function(d) {
var y0 = 0;
d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.ages[d.ages.length - 1].y1;
});
data.sort(function(a, b) { return b.total - a.total; });
x.domain(data.map(function(d) { return d.State; }));
y.domain([0, d3.max(data, function(d) { return d.total; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("font-size", 7);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -40)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Number of Organizations");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.State) + ",1)"; });
state.selectAll(".bar")
.data(function(d) {
for(var l = 0 ; l < d.ages.length ; l++) {
d.ages[l].State = d.State;
}
return d.ages; })
.enter().append("rect")
.attr("class", "bar")
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); })
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
var legend = svg.selectAll(".legend")
.data(color.domain().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; });
});
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar:hover {
fill: steelblue !important;
pointer-events: all;
}
.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;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
</head>
<body>
<script type="text/javascript" src="viz.js"></script>
</body>
</html>
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 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>