Add space between x-axis and line with time scale - javascript

I am using an example below.
HTML-
<div id="chart-holder"></div>
CSS-
.chart-holder {
position: relative;
font-family: Helvetica, sans-serif;
}
.chart-tip {
display: none;
position: absolute;
min-width: 70px;
top: 0px;
left: 0px;
padding: 3px 5px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
font-size: .8em;
text-shadow: none;
text-align: center;
z-index: 10500;
border-radius: 3px;
}
.v {
display: block;
font-size: 1.2em;
}
path {
stroke: #0da9c0;
stroke-width: 2;
fill: none;
}
path.domain {
stroke: #aaa;
stroke-width: 1;
}
line {
stroke: #aaa;
}
text {
font-family: Arial;
font-size: 9pt;
fill: #555;
}
circle {
cursor: pointer;
}
Javascript-
var data = [["2013-01-24 06:38:02.235191", 52], ["2013-01-23 06:38:02.235310", 54], ["2013-01-22 06:38:02.235330", 45], ["2013-01-21 06:38:02.235346", 53]],
maxValue = d3.max(data, function (d) { return d[1]; }),
margin = {top: 20, right: 20, bottom: 50, left: 50},
width = 500 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom,
svg, x, y, xAxis, yAxis, line;
$.each(data, function(index, val) {
val[0] = new Date(val[0]);
});
x = d3.time.scale()
.range([0, width])
y = d3.scale.linear()
.domain([0, maxValue])
.range([height, 0]);
xAxis = d3.svg.axis()
.scale(x)
.tickSize(4, 2, 0)
.ticks(d3.time.days, 1)
.tickFormat(d3.time.format("%m/%d"))
.orient("bottom");
yAxis = d3.svg.axis()
.scale(y)
// .ticks(5)
// .tickValues([0, maxValue * 0.25, maxValue * 0.5, maxValue * 0.75, maxValue])
.tickSize(4, 2, 0)
.orient("left");
line = d3.svg.line()
.x(function(d) { return x(d[0]); })
.y(function(d) { return y(d[1]); });
svg = d3.select("#chart-holder").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 + ")");
x.domain(d3.extent(data, function(d) { return d[0]; }));
y.domain([d3.min(data, function (d) { return d[1]; })-1, maxValue]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("transform", function(d) {
return "rotate(-60)translate(" + -this.getBBox().height * 1.7 + "," +
-this.getBBox().width/4 + ")";
});
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("Engagement");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg
.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("fill", "#0b8da0")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d[0]); })
.attr("cy", function(d) { return y(d[1]); })
.on("mouseover", function(d) { showData(this, d);})
.on("mouseout", function() { hideData(this);});
function showData(obj, d) {
var coord = d3.mouse(obj);
var chartTip = d3.select(".chart-tip");
var format = d3.time.format("%b %d, %Y");
// enlarge circle
d3.select(obj)
.attr('r', 5);
// now we just position the chartTip roughly where our mouse is
chartTip.style("left", (coord[0] + 60) + "px" );
chartTip.style("top", (coord[1] + 10) + "px");
$(".chart-tip").html('<span class="v">' + d[1] + '</span>' + format(d[0]));
$(".chart-tip").fadeIn(100);
}
function hideData(obj) {
// enlarge circle
d3.select(obj)
.attr('r', 3.5);
$(".chart-tip").fadeOut(100);
}
$('#chart-holder').append($('<div />', {
'class': 'chart-tip'
}));
Here is the fiddle
http://jsfiddle.net/murli2308/n7Vmr/12/
I can add space between axis and line if I am using ordinal scale or linear scale. But when I am using time scale, I am not able to add space between axis and line.
I tried
x = d3.time.scale()
.range([0, width]);
It is not working.

The x.domain is the user space side of the user space to pixel space mapping. In your code you are setting the domain as:
x.domain(d3.extent(data, function(d) { return d[0] - 1; }));
Which says start my x axis at my min time minus 1 millisecond.
If you want some space before / after the line. Try:
x.domain([
d3.min(data, function(d) { return d[0].getTime() - 1.8e+7; }),
d3.max(data, function(d) { return d[0].getTime() + 1.8e+7; })
]);
Which says start my x axis 5 hours before my min date and stop it 5 hours after my max date.
Updated fiddle.
EDITS
Just used a percentage based scheme, say you want 5% padding (3.6 hours with your current data):
var minDate = d3.min(data, function(d) { return d[0].getTime(); }),
maxDate = d3.max(data, function(d) { return d[0].getTime(); }),
padding = (maxDate - minDate) * .05;
x.domain([minDate - padding, maxDate + padding]);
Updated fiddle.

Related

D3.js Line Graph - Adding Grid To Background and Making Line Crurve

Does anyone know how I would add a grid to the background of a d3 line graph I have made and does anyone know how I would make my line graph curve rather than be rather rigid like it is now. the code below is for the line graph and it all works with the data file I have I just need it to have a grid on the background and be curved rather than how it is now. I also need to have the y axis display a percent rather than a decimal
any help would be appreciated.
JS, CSS and HTML --
var margin = { top: 20 , right: 20, bottom: 30 , left: 40} ,
width= 960 - margin.left - margin.right ,
height = 500 - margin.top - margin.bottom;
var y = d3.scaleLinear()
.range([height, 0]) ; //remember: up / down are flipped
var x = d3.scaleBand()
.range([0, width]).padding([0.1]); //the last peramter adds padding
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(event,d) {
return "<strong>Frequency:</strong> <span style='color: rgba(223,222,79,255)'>" + d.frequency + "</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.csv("data/data.csv").then(function(data) {
x.domain(data.map(function(d){return d.letter;}));
y.domain([0, d3.max(data, function(d){return d.frequency;})]);
// Remember to add all data dependant calls in here
var xAxis = d3.axisBottom().scale(x); // Positions the Lables Under the xAxis
var yAxis = d3.axisLeft().scale(y); // positions the lables on the left of the yAxis
var line = d3.line()
.x(function(d) { return x(d.letter); })
.y(function(d) { return y(d.frequency); })
x.domain(data.map(function(d) { return d.letter; }));
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
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")
.text("Frequency");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("class", "circle")
.attr("cx", function(d) {return x (d.letter);})
.attr("cy", function(d) {return y (d.frequency);})
.attr("r", 4)
.attr("width", x.bandwidth())
.attr("height", function(d) {return height - y (d.frequency);})
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 + (margin.top / 2))
.attr("text-anchor", "middle")
.text("Relative Frequence of Letters in the English Alphabet") ;
});
.bar {
fill:rgba(55,125,34,255);
}
.bar:hover {
fill: rgba(55,125,34,255);
}
.axis--x path {
display: none;
}
.line {
fill: none;
stroke: rgba(55,125,34,255);
stroke-width: 3px;
}
.circle {
fill: rgba(55,125,34,255);
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
font-family: 'Courier New', Courier, monospace;
}
/* 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>
<title>Demo</title>
<link rel="stylesheet" href="css/mystyle.css">
</head>
<body>
<svg class="chart"></svg>
<script type="text/javascript"src="js/d3/d3.js"></script>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/bumbeishvili/d3-tip-for-v6#4/d3-tip.min.js"></script>
<script type="text/javascript"src="js/myscript1.js"></script>
</body>
</html>
You can add gridlines to an axis by using axis.tickSize([size]) or axis.tickSizeInner([size]).
Ex:
var xAxis = d3.axisBottom().scale(x).tickSize(.width);
As for the lines, you can make them curves by using the .curve method of the line, eg:
var line = d3.line()
.x(function(d) { return x(d.letter); })
.y(function(d) { return y(d.frequency); })
.curve(d3.curveBasis)
Check these pages for the full reference:
https://github.com/d3/d3-axis
https://github.com/d3/d3-shape

How to change the color of a single line in a Voronoi diagram?

I am working with D3 voronoi. I have several lines and would like to have only one of them have a specific color, while all the others have a different color. I have tried using an if statement, but to no avail. Below is my code:
Style:
.axis--y path {
display: none;
fill: none;
stroke: #17BED5;
stroke-width: 1.0;
}
.axis--y line {
stroke: lightgrey;
opacity: 1
}
.cities {
fill: none;
stroke: #000000;
stroke-linejoin: round;
stroke-linecap: round;
stroke-width: 1px;
}
.city--hover {
stroke: #4575b4;
stroke-width: 2px;
}
.focus text {
text-anchor: middle;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}
.voronoi path {
fill: none;
pointer-events: all;
}
.voronoi--show path {
stroke: red;
stroke-opacity: 0.2;
}
#form {
position: absolute;
top: 20px;
right: 30px;
}
</style>
JavaScript:
var years,
yearKeys,
yearParse = d3.timeParse("%Y");
//Sets out the margins of the chart frm the edges of the page/screen.
var svg = d3.select("svg"),
margin = {top: 20, right: 30, bottom: 30, left: 40},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//Now we define the x and y axes and their respective scales. X will be the date, and y will be the unemployment rates.
var x = d3.scaleTime()
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var voronoi = d3.voronoi()
.x(function(d) {
return x(d.date); })
.y(function(d) {
return y(d.value); })
.extent([[-margin.left, -margin.top], [width + margin.right, height + margin.bottom]]);
//And we set out the values of our lines.
var line = d3.line()
.x(function(d) {
return x(d.date); })
.y(function(d) {
return y(d.value); });
//Now we call our chart.
d3.csv("data/eloVoronoi.csv", type, function(error, data) {
if (error) throw error;
x.domain(d3.extent(years));
y.domain([1500, d3.max(data, function(c) {
return d3.max(c.values, function(d) {
return d.value; }); })]).nice();
//We tell the computer that we want our x-axis to be at the bottom.
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
//And the y axis on the left, with some style attributes.
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y)
.ticks(6)
.tickSize(-width))
.append("text")
.attr("transform", "rotate(360)")
.attr("x", 4)
.attr("y", -14)
.attr("dy", "1em")
.style("text-anchor", "start")
.style("fill", "black")
.style("font-weight", "bold")
.text("Elo Rating");
g.append("g")
.attr("class", "cities")
.selectAll("path")
.data(data)
.enter().append("path")
.attr("d", function(d) { d.line = this;
return line(d.values); });
var focus = g.append("g")
.attr("transform", "translate(-100,-100)")
.attr("class", "focus");
focus.append("circle")
.attr("r", 3.5);
focus.append("text")
.attr("y", -10);
//This is where we group all the vornoi together so tht we can apply the mouseovers all together, instead of one by one.
var voronoiGroup = g.append("g")
.attr("class", "voronoi");
//The mouseovers/outs.
voronoiGroup.selectAll("path")
.data(voronoi.polygons(d3.merge(data.map(function(d) {
return d.values; }))))
.enter().append("path")
.attr("d", function(d) {
return d ? "M" + d.join("L") + "Z" : null; })
.on("mouseover", mouseover)
.on("mouseout", mouseout);
//
d3.select("#show-voronoi")
.property("disabled", false)
.on("change", function() { voronoiGroup.classed("voronoi--show", this.checked); });
//Helper function to assist in the mouseover.
function mouseover(d) {
d3.select(d.data.city.line).classed("city--hover", true);
d.data.city.line.parentNode.appendChild(d.data.city.line);
focus.attr("transform", "translate(" + x(d.data.date) + "," + y(d.data.value) + ")");
focus.select("text").text(d.data.city.name);
}
//And a helper function for the mouseout.
function mouseout(d) {
d3.select(d.data.city.line).classed("city--hover", false);
focus.attr("transform", "translate(-100,-100)");
}
});
//Now we use an if statement to call our chart onto the page.
function type(d, i, columns) {
if (!years) yearKeys = columns.slice(1), years = yearKeys.map(yearParse);
var c = {name: d.name.replace(/ (msa|necta div|met necta|met div)$/i, ""), values: null};
c.values = yearKeys.map(function(k, i) {
return {city: c, date: years[i], value: d[k] / 1}; });
return c;
}

D3.js SVG wired size

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!

Using d3-tip and CSS hover effect with d3 stacked bar chart

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>

Tooltip displaying undefined values

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.

Categories