I know it is possible to display an image in a D3 tooltip. What I am trying to do is to display a bar graph in a tooltip (i.e when the mouse hovers over the object a bar graph appears). I have adapted code from http://bl.ocks.org/jarobertson/1483052#gistfile1.html and combined it with the bar graph code by Robert Lewand. And well, it doesn't work. I dont even get any errors in the console that could perhaps put me on the right path. Is it possible to do? Here is my code:
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?1.27.1"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<style type="text/css">
div.tooltip {
position: absolute;
text-align: center;
width: 500px;
height: 550px;
padding: 8px;
font: 10px sans-serif;
background: #ddd;
border: solid 1px #aaa;
border-radius: 8px;
pointer-events: none;
}
.chart rect {
fill: steelblue;
}
.chart text {
fill: white;
font: 10px sans-serif;
text-anchor: middle;
}
</style>
</head>
<body>
<script type="text/javascript">
var w = 960,
h = 500;
var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h);
svg.append("svg:g")
.attr("transform", "translate(480,50)rotate(60)scale(2)")
.append("svg:rect")
.attr("width", 140)
.attr("height", 140)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseout", mouseout);
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 1e-6);
function mouseover() {
div.transition()
.duration(500)
.style("opacity", 1);
}
// where the tooltip previosly contained an image
function mousemove() {
div
.html("<h1>Bar Graph</h1><br> <svg class='chart'></svg>")
.style("left", (d3.event.pageX - 34) + "px")
.style("top", (d3.event.pageY - 12) + "px");
}
function mouseout() {
div.transition()
.duration(500)
.style("opacity", 1e-6);
}
// make bar graph
var width = 300,
height = 300;
var y = d3.scale.linear()
.range([height, 0]);
var chart = d3.select(".chart")
.attr("width", width)
.attr("height", height);
d3.tsv("data.tsv", type, function(error, data) {
y.domain([0, d3.max(data, function(d) { return d.value; })]);
var barWidth = width / data.length;
var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(" + i * barWidth + ",0)"; });
bar.append("rect")
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.attr("width", barWidth - 1);
bar.append("text")
.attr("x", barWidth / 2)
.attr("y", function(d) { return y(d.value) + 3; })
.attr("dy", ".75em")
.text(function(d) { return d.value; });
});
function type(d) {
d.value = +d.value; // coerce to number
return d;
}
</script>
</body>
</html>
Thanks in advance!
apologies, the data.tsv file contains the following:
Sentiment value
Strongly positive 211
Positive 222
Neutral 654
Negative 618
Strongly negative 343
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?1.27.1"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<style type="text/css">
div.tooltip {
position: absolute;
text-align: center;
width: 500px;
height: 550px;
padding: 8px;
font: 10px sans-serif;
background: #ddd;
border: solid 1px #aaa;
border-radius: 8px;
pointer-events: none;
}
.chart rect {
fill: steelblue;
}
.chart text {
fill: white;
font: 10px sans-serif;
text-anchor: middle;
}
</style>
<script type="text/javascript">
var w = 960,
h = 500;
var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h);
svg.append("svg:g")
.attr("transform", "translate(480,50)rotate(60)scale(2)")
.append("svg:rect")
.attr("width", 140)
.attr("height", 140)
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseout", mouseout);
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 1e-6);
function mouseover() {
div.transition()
.duration(500)
.style("opacity", 1);
}
// where the tooltip previosly contained an image
function mousemove() {
div
.html("<h1>Bar Graph</h1><br> <svg class='chart'></svg>")
.style("left", (d3.event.pageX - 34) + "px")
.style("top", (d3.event.pageY - 12) + "px");
}
function mouseout() {
div.transition()
.duration(500)
.style("opacity", 1e-6);
}
// make bar graph
var width = 300,
height = 300;
var y = d3.scale.linear()
.range([height, 0]);
var chart = d3.select(".chart")
.attr("width", width)
.attr("height", height);
d3.tsv("data.tsv", type, function(error, data) {
y.domain([0, d3.max(data, function(d) { return d.value; })]);
var barWidth = width / data.length;
var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(" + i * barWidth + ",0)"; });
bar.append("rect")
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.attr("width", barWidth - 1);
bar.append("text")
.attr("x", barWidth / 2)
.attr("y", function(d) { return y(d.value) + 3; })
.attr("dy", ".75em")
.text(function(d) { return d.value; });
});
function type(d) {
d.value = +d.value; // coerce to number
return d;
}
</script>
'data.tsv' file is not with us,
and we have written only
function mousemove() {
div
.html("<h1>Bar Graph</h1><br> <svg class='chart'></svg>")
.style("left", (d3.event.pageX - 34) + "px")
.style("top", (d3.event.pageY - 12) + "px");
}
above function will place 'Bar Graph' text and one svg element in tooltip.
Hope you will get it.
If not ask for more......
Related
I have build the below code to create a customer vertical slider that can be plotted in an x and y axis plot.
I have taken input from a csv file and then using it to build the below output in d3.js.The code in d3.js is as below :
Edit 1: I am currently able to drag only the yellow rectangles only, but not all the rectangles. This is how the the modified graph looks like
Need your suggestions on -
1) How to drag all the rectangles individually
2) Keep the rectangle color belonging to a line same. For Example : all the rectangle with the first line will have same color and all the rectangles along the 2nd line will have another color and so on.
It will be of immense help, thanks !
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test Data</title>
<style>
div.tooltip {
position: absolute;
text-align: center;
width: 90px;
height: 32px;
padding: 1px;
font: 11px verdana;
background: rebeccapurple;
color: white;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
.grid .tick {
stroke: lightgrey;
opacity: 0.7;
}
.grid path {
stroke-width: 0;
}
svg {
float: left;
border-bottom: solid 1px #ccc;
border-right: solid 1px #ccc;
margin-right: -1px;
margin-bottom: -1px;
}
rect {
opacity: 0.9;
}
svg {
float: left;
border-bottom: solid 1px #ccc;
border-right: solid 1px #ccc;
margin-right: -1px;
margin-bottom: -1px;
}
rect {
opacity: 0.9;
}
</style>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script type="text/javascript">
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
// load csv from the same directory
d3.csv("test.csv", function (data) {
data.forEach(function (d) {
x_value: +data.x_value; // convert to number with +
promotedprice: +data.promotedprice; // convert to number with +
nonpromotedprice: +data.nonpromotedprice;
avgprice: +data.avgprice;
brand: data.brand;
});
var svg = d3.select("body").append("svg")
.attr("width", 700)
.attr("height", 450)
// Attach the Promoted Price Rectangle
var g = svg.selectAll("rect")
.data(data)
.enter()
.append("g")
.classed('rect', true)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var accent = d3.scaleOrdinal(d3.schemeAccent);
/*.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragend));*/
/*g.append("rect")
.attr("width", 18)
.attr("height", function (d) { return (d.nonpromotedprice - d.promotedprice) + 100; })
.attr("x", function (d) { return d.x_value; })
.attr("y", function (d) { return (d.nonpromotedprice - d.promotedprice) / 2; })
.attr("fill", "#E6EAEE")
*/
g.append("line") // attach a line
.style("stroke", "gray")
.style("stroke-width", 12) // colour the line
.attr("x1", function (d) { return d.x_value; }) // x position of the first end of the line
.attr("y1", function (d) { return d.nonpromotedprice; }) // y position of the first end of the line
.attr("x2", function (d) { return d.x_value; }) // x position of the second end of the line
.attr("y2", function (d) { return d.promotedprice; });
g.append("rect")
.attr("width", 20)
.attr("height", 15)
.attr("x", function (d) { return d.x_value - 10; })
.attr("y", function (d) { return d.promotedprice; })
.attr("fill", "#F9EA55")
g.append("rect")
.attr("width", 20)
.attr("height", 15)
.attr("x", function (d) { return d.x_value - 10; })
.attr("y", function (d) { return d.nonpromotedprice; })
.attr("fill", "#ED8B00")
g.append("rect")
.attr("width", 20)
.attr("height", 15)
.attr("x", function (d) { return d.x_value - 10; })
.attr("y", function (d) { return d.avgprice; })
.attr("fill", "#28468E")
;
g.selectAll("rect")
.style('cursor', 'pointer');
g.selectAll("text")
.data(data)
.enter()
.insert("text", "line")
.text(function (d) { return d.brand; })
.style("text-anchor", "top")
.style("fill", "red")
.style("font-family", "Arial")
.style("font-size", 34);
function dragstarted(d) {
d3.select(this).raise().classed("active", true);
}
function dragged(d) {
d3.select(this).select("rect")
//.attr("x", d.x = d3.event.x)
.attr("y", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("active", false);
}
});
</script>
</body>
Thanks in Advance
Created a d3.js bar chart based on some examples I've seen online and I've come across a problem. I'd like to align the starting datapoint based on the x-axis with the y-intercept. However, I can't seem to do so correctly even after various changes (changing scale.ordinal to scale.linear, adding transform to y-axis, etc.).
Likewise, I'd like the ending point in the x-axis to be aligned with the last data point. There's like an invisible padding before and after the range of starting and beginning of the datapoints in the chart.
I've consulted this question here as it seems similar to my problem but came up short with my expected results: D3Js Bar Chart Bars Starting Way After beginning of X-Axis
Here's the current code that I have:
var dataUrl = 'https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json';
// set the dimensions of the canvas
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40
},
width = 1500 - 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);
// set the ranges
var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.01, 1);
var y = d3.scale.linear().range([height, 0]);
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
// Added for the vertical lines (need to remove later)
.innerTickSize(-height)
.outerTickSize(0)
.tickPadding(10);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
var svg = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// load the data
d3.json(dataUrl, function(error, data) {
data.data.forEach(function(d) {
d.GDP = d[0];
d.Year = +d[1];
});
// scale the range of the data
x.domain(data.data.map(function(d) {
return d.GDP;
}));
y.domain([0, d3.max(data.data, function(d) {
return d.Year;
})]);
// add axis
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", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
// .attr("transform", "translate(" + margin.left + ", 0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Gross Domestic Product, USA");
// Add bar chart with tooltip
svg.selectAll("bar")
.data(data.data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.GDP);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.Year);
})
.attr("height", function(d) {
return height - y(d.Year);
})
.on("mouseover", function(d) {
var monthNameFormat = d3.time.format("%b-%Y")
var gdp_date = monthNameFormat(new Date(d[0]))
var formatDecimalComma = d3.format(",.2f")
var curr = formatDecimalComma(d[1])
div.transition()
.duration(200)
.style("opacity", .9);
div.html(gdp_date + "<br/> $" + curr + " Billion")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
});
.chart rect {
fill: steelblue;
}
.chart text {
fill: black;
font: 10px sans-serif;
text-anchor: middle;
}
bar {
fill: steelblue;
}
.bar:hover {
fill: red;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
div.tooltip {
position: absolute;
text-align: center;
width: 130px;
height: 30px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!-- Source: https://bost.ocks.org/mike/bar/3/ -->
<div id="chart" align="center">
<svg class="chart"></svg>
</div>
Change rangeRoundBands to rangeBands and remove all the paddings:
var x = d3.scale.ordinal().rangeBands([0, width]);
Here is your code with that change:
var dataUrl = 'https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json';
// set the dimensions of the canvas
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40
},
width = 1500 - 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);
// set the ranges
var x = d3.scale.ordinal().rangeBands([0, width]);
var y = d3.scale.linear().range([height, 0]);
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
// Added for the vertical lines (need to remove later)
.innerTickSize(-height)
.outerTickSize(0)
.tickPadding(10);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
var svg = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// load the data
d3.json(dataUrl, function(error, data) {
data.data.forEach(function(d) {
d.GDP = d[0];
d.Year = +d[1];
});
// scale the range of the data
x.domain(data.data.map(function(d) {
return d.GDP;
}));
y.domain([0, d3.max(data.data, function(d) {
return d.Year;
})]);
// add axis
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", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
// .attr("transform", "translate(" + margin.left + ", 0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Gross Domestic Product, USA");
// Add bar chart with tooltip
svg.selectAll("bar")
.data(data.data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.GDP);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.Year);
})
.attr("height", function(d) {
return height - y(d.Year);
})
.on("mouseover", function(d) {
var monthNameFormat = d3.time.format("%b-%Y")
var gdp_date = monthNameFormat(new Date(d[0]))
var formatDecimalComma = d3.format(",.2f")
var curr = formatDecimalComma(d[1])
div.transition()
.duration(200)
.style("opacity", .9);
div.html(gdp_date + "<br/> $" + curr + " Billion")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
});
.chart rect {
fill: steelblue;
}
.chart text {
fill: black;
font: 10px sans-serif;
text-anchor: middle;
}
bar {
fill: steelblue;
}
.bar:hover {
fill: red;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
div.tooltip {
position: absolute;
text-align: center;
width: 130px;
height: 30px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!-- Source: https://bost.ocks.org/mike/bar/3/ -->
<div id="chart" align="center">
<svg class="chart"></svg>
</div>
In my scatterplot, I am hovering on the points, to generate a tooltip. But, my X-cordinate values are not right, corresponding to the graph axis. Can a clue be provided for the same??
One thing to note- I have 2 dataset arrays- 1 corresponds to Y value, the other corresponds to Y-Error values.
var width = 700;
var height = 700;
var padding = 90;
var myData = [12, 18, 20, 9, 17, 25, 30];
var errData = [6, 9, 10, 4.5, 8.5, 12.5, 15];
var svg = d3.select("body").
append("svg")
.attr("width", width)
.attr("height", height);
var Mydiv = d3.select("body")
.append("div")
//.append("span")
//.text('X')
.data(myData)
.attr("class", "toolDiv")
//.attr("span", "close")
.style("opacity", "0");
var MyLine = d3.select("body")
.append("div")
.data(myData)
.attr("class", "error-line");
//.style("opacity", 1);
//var m1 = d3.max(myData + errData)
var yScale = d3.scaleLinear().domain([0, d3.max(myData)]).range([height / 2, 50]);
var xScale = d3.scaleLinear().domain([0, d3.max(myData)]).range([0, width - 100]);
var y_ErScale = d3.scaleLinear().domain([0, d3.max(errData)]).range([height / 2, 50]);
var x_ErScale = d3.scaleLinear().domain([0, d3.max(errData)]).range([0, width - 100]);
var valueline = d3.selectAll("scatter-dots")
.append("line")
.attr("x", function(d, i) {
return xScale(myData[i]);
})
.attr("y", function(d) {
return yScale(d);
});
//.curve();
svg.append("g")
.selectAll("scatter-dots")
.data(myData)
.enter()
.append("line")
.data(myData)
.attr("class", "line")
.attr("d", valueline);
// .style("opacity", 0);
var eBar = d3.select("body").append("svg");
//var x_min =
var x_axis = d3.axisBottom()
.scale(xScale);
var y_axis = d3.axisLeft()
.scale(yScale);
svg.append("g")
.attr("transform", "translate(50, 10)")
.call(y_axis);
var xAxisTranslate = height / 2 + 10;
svg.append("g")
.attr("transform", "translate(50, " + xAxisTranslate + ")")
.call(x_axis);
svg.append("text")
.attr("transform",
"translate(" + (width / 1.2) + " ," + (height - 280) + ")")
.style("text-anchor", "middle")
.style("left", "70px")
.text("Points");
svg.append("text")
.attr("transform",
"translate(" + (width / 2) + " ," + (height - 280) + ")")
.style("text-anchor", "middle")
.style("left", "70px")
.text("X-Axis");
svg.append("text")
.attr("transform",
"translate(" + (height / 40) + " ," + (width - 500) + ")rotate(-90)")
.style("text-anchor", "middle")
.style("left", "70px")
.text("Y-Axis");
// svg.append("text")
// .attr("transform",
// "translate(" + (height/10) + " ," + (width - 690) + ")rotate(-90)")
// .style("text-anchor", "middle")
// .style("left", "70px")
// .text("Y");
svg.append("g")
.selectAll("scatter-dots")
.data(myData)
.enter().append("svg:circle")
.attr("cx", function(d, i) {
return xScale(myData[i]);
})
.attr("cy", function(d) {
return yScale(d);
})
.attr("r", 3)
.style("opacity", 0.8)
.style("cursor", "help")
// .on("click", function(d, i){
// var active = Mydiv.active ? false : true ,
// newOpacity = active ? 0 : 0.9;
// Mydiv.transition()
// .duration(200)
// .style("opacity", newOpacity);
// Mydiv.html("X" + "-" + errData[i] + "<br/>" + "Y" + "-" + myData[i] )
// .style("left", (d3.event.pageX + 10) + "px")
// .style("top", (d3.event.pageY - 18) + "px");
// Mydiv.active = active;
// });
.on("mouseover", function(d, i) {
//console.log(this);
//console.log(d3.select(this));
//d3.select(this);
//console.log(d3.select(this));
Mydiv.transition()
.duration(200)
.style("opacity", 0.9);
Mydiv.html("X" + "-" + errData[i] + "<br/>" + "Y" + "-" + myData[i])
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
//div.html(yScale(d));
})
.on("mouseout", function(d) {
Mydiv.transition()
.duration(500)
.style("opacity", 0);
});
// var errorBar = eBar.append("path")
// .attr("d", yScale(errData))
// .attr("stroke", "red")
// .attr("stroke-width", 1.5);
// svg.append("g")
// .selectAll("error-bars")
// .data(errData)
// .enter().append("svg:path")
// .attr("cx", function (d,i) { return x_ErScale(errData[i]); } )
// .attr("cy", function (d) { return y_ErScale(d); } )
// .attr("stroke", "red")
// .attr("stroke-width", 1.5);
svg.append("g")
.selectAll("line")
.data(errData)
.enter()
.append("line")
.attr("class", "error-line")
.attr("x1", function(d) {
return x_ErScale(d);
})
.attr("y1", function(d) {
return y_ErScale(d) + 30;
})
.attr("x2", function(d) {
return x_ErScale(d);
})
.attr("y2", function(d) {
return y_ErScale(d) + 2;
})
.on("mouseover", function(d) {
MyLine.transition()
//.duration(200)
.style("opacity", "1");
//.style("fill-opacity", 0);
})
.on("mouseout", function(d) {
MyLine.transition()
//.duration(200)
.style("opacity", 0.0);
//.style("fill-opacity", 1);
});
svg.append("g").selectAll("line")
.data(errData).enter()
.append("line")
.attr("class", "error-cap")
.attr("x1", function(d) {
return x_ErScale(d) - 8;
})
.attr("y1", function(d) {
return y_ErScale(d) - 30;
})
.attr("x2", function(d) {
return x_ErScale(d) + 8;
})
.attr("y2", function(d) {
return y_ErScale(d) - 30;
});
svg.append("g")
.selectAll("line")
.data(errData)
.enter()
.append("line")
.attr("class", "error-line")
.attr("x1", function(d) {
return x_ErScale(d);
})
.attr("y1", function(d) {
return y_ErScale(d) - 30;
})
.attr("x2", function(d) {
return x_ErScale(d);
})
.attr("y2", function(d) {
return y_ErScale(d) - 2;
})
.on("mouseover", function(d) {
MyLine.transition()
//.duration(200)
.style("opacity", "1");
//.style("fill-opacity", 0);
})
.on("mouseout", function(d) {
MyLine.transition()
//.duration(200)
.style("opacity", "0.6");
//.style("fill-opacity", 1);
});
// .on("mouseover", function(d){
// MyLine.transition()
// .duration(200)
// .style("opacity", 0);
// })
// .on("mouseout", function(d){
// MyLine.transition()
// .duration(200)
// .style("opacity", 1);
// });
// Add Error Bottom Cap
svg.append("g").selectAll("line")
.data(errData).enter()
.append("line")
.attr("class", "error-cap")
.attr("x1", function(d) {
return x_ErScale(d) - 8;
})
.attr("y1", function(d) {
return y_ErScale(d) + 30;
})
.attr("x2", function(d) {
return x_ErScale(d) + 8;
})
.attr("y2", function(d) {
return y_ErScale(d) + 30;
});
//svg.selectAll("scatter-dots")
// .data(myData)
// .enter()
// .on("mouseover", function()
// {
// //console.log(this);
// //console.log(d3.select(this));
// //d3.select(this);
// //console.log(d3.select(this));
// //div.transition()
// //.duration(200)
// //.style("opacity", 0.8);
// //div.html(myData);
// });
//// .on("mouseout", function(d)
//// {
//// div.transition()
//// .duration(500)
//// .style("opacity", 0);
//// });
/*body {
font: 10px sans-serif;
}
*/
#d1 {
position: relative;
top: 100px;
}
#svg1 {
position: relative;
bottom: 80px;
}
.axis_path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis_line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.dot {
stroke: #000;
cursor: pointer;
}
.error-line {
stroke: #b30059;
stroke-width: 2px;
opacity: 0.6;
stroke-dasharray: 2;
/*fill-opacity: 1;*/
/*opacity: 1;*/
}
.error-cap {
stroke: #b30059;
stroke-width: 2px;
stroke-type: solid;
}
.toolDiv {
position: absolute;
text-align: center;
width: 120px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
/*.toolDiv.image
{
position: static;
content: url(http://wfarm1.dataknet.com/static/resources/icons/set28/7f8535d7.png);
}*/
/*.close {
width: 10px;
height: 10px;
background: #fff;
position: absolute;
top: 0;
right: 0;
background: url('http://i.imgur.com/Idy9R0n.png') no-repeat 0 0;
cursor: pointer;
}
.close:hover {
background-position: -13px 0;
}*/
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
<head>
<title>Scatter Plot Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<!-- <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script> -->
<link rel="stylesheet" type="text/css" href="scatter.css">
</head>
<body>
<script src="scatterplot.js" type="text/javascript"></script>
<div id="d1">
<svg id="svg1">
<div id="d2"></div>
</svg>
</div>
</body>
I've included a fiddle for reference.
I am doing research for a professor at my school and I am coding in d3. I am creating a graph that has tool tips and you can toggle the graph by clicking on the legend. However, when I toggle the lines disappears but I can't get the tool tips associated to that line. I know I need to somehow add an id to these circles but I have no idea how. I have included my code below to show what I have so far. Any help would be appreciated!
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: white;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
div.tooltip {
position: absolute;
text-align: center;
width: 170px;
height: 500px;
padding: 1px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 5px;
pointer-events: none;
}
.legend {
font-size: 16px;
font-weight: bold;
text-anchor: middle;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 20, right: 150, bottom: 60, left: 80},
width = 1160 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// Parse the date / time
// Set the ranges
var x = d3.scaleTime().range([0, width-100]);
var formatxAxis=d3.format('.0f');
var y = d3.scaleLinear().range([height, 0]);
// Define the axe
var xAxis = d3.axisBottom().scale(x)
.tickFormat(formatxAxis).ticks(20);
var yAxis = d3.axisLeft().scale(y)
.ticks(5);
// Define the line
var valueline = d3.line()
.curve(d3.curveMonotoneX)
.x(function(d) { return x(d.year); })
.y(function(d) { return y(d.count); });
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.json("satisfaction.json", function(error, data) {
data.forEach(function(d) {
d.year = +d.year;
d.count = +d.count;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.year; }));
y.domain([0, d3.max(data, function(d) { return d.count; })]);
//nest the entries by symbol
var dataNest = d3.nest()
.key(function(d) {
return d.word;
})
.entries(data);
//define colors for the lines
var color = d3.scaleOrdinal(d3.schemeCategory10);
// spacing for the legend
legendSpace = width/dataNest.length;
var circleid = svg.selectAll("circle")
.data(dataNest)
.enter()
.append("g")
.attr("id", function(d){
return "circle" + d.key.replace(/\s+/g, '');
});
// Loop through each symbol / key
dataNest.forEach(function(d,i) {
svg.append("path")
.attr("class", "line")
.style("stroke", function() { // Add the colours dynamically
return d.color = color(d.key); })
.attr("id", 'tag'+d.key.replace(/\s+/g, '')) // assign ID
.attr("d", valueline(d.values));
// Add the Legend
svg.append("text")
.attr("x", width - margin.left + 50)
.attr("y", legendSpace/4 + i*(legendSpace/6))
.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;
// Hide or show the elements based on the ID
d3.select("circle" + d.key.replace(/\s+/g, ''))
.transition().duration(100)
.style("opacity", newOpacity);
})
.text(d.key);
});
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 5)
.attr("cx", function(d) { return x(d.year); })
.attr("cy", function(d) { return y(d.count); })
.on("click", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(d.word + "<br/>" + d.count + "<br/>" + d.songs)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 25) + "px");
})
.on("dblclick", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
;
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
</script>
</body>
Right now, you are trying to set your id before you have added the circles to the graph. Instead, you can set the id when you're appending the circles to your graph.
// Add the scatterplot
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("id", function(d){ return "circle" + d.key.replace(/\s+/g, ''); })
// ^---- add the id here when you're appending the circles
.attr("r", 5)
.attr("cx", function(d) { return x(d.year); })
.attr("cy", function(d) { return y(d.count); })
.on("click", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(d.word + "<br/>" + d.count + "<br/>" + d.songs)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 25) + "px");
})
.on("dblclick", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})
;
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<style type="text/css">
#container {
margin: 20px;
}
#chart {
position: absolute;
background-color: #eee;
}
#chart legend{
position: absolute;
margin: 100px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #900C3F;
display: inline-block;
font-size: 12px;
left: 600px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 150px;
z-index: 10;
opacity: 1;
}
rect {
stroke-width: 2;
}
path {
stroke: #ffffff;
stroke-width: 0.5;
}
div.tooltip {
position: absolute;
z-index: 999;
padding: 10px;
background: #f4f4f4;
border: 0px;
border-radius: 3px;
pointer-events: none;
font-size: 11px;
color: #080808;
line-height: 16px;
border: 1px solid #d4d4d4;
}
</style>
</head>
<body>
<div id="container">
<svg id="chart" width="600" height="300" viewBox="0 0 600 300" perserveAspectRatio="xMinYMid">
<div id="toolTip" class="tooltip" style="opacity: 0;"></div>
<script type="text/javascript">
var div = d3.select("#toolTip");
var data = [
{"IP":"192.168.12.1", "count":20},
{"IP":"76.09.45.34", "count":40},
{"IP":"34.91.23.76", "count":80},
{"IP":"192.168.19.32", "count":16},
{"IP":"192.168.10.89", "count":50},
{"IP":"192.178.34.07", "count":18},
{"IP":"192.168.12.98", "count":30}];
var width = 300,
height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
radius = Math.min(width, height) / 2 - 10;
var legendRectSize = 18,
legendSpacing = 4;
var color = d3.scale.category20b();
var arc = d3.svg.arc()
.outerRadius(radius);
var arcOver = d3.svg.arc()
.outerRadius(radius + 5);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.count; });
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#chart").append("svg")
.datum(data)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var arcs = svg.selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var arcs2 = svg.selectAll(".arc2")
.data(pie)
.enter().append("g")
.attr("class", "arc2");
arcs.append("path")
.attr("fill", function(d, i) { return color(i); })
.on("mouseover", function(d) {
var htmlMsg="";
div.transition()
.style("opacity",0.9);
var total = d3.sum(data.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
div.html(
"IP :"+ d.data.IP +""+"<br/>"+
"Count : " + d.data.count +"<br/>" +
"Percent: " + percent + '%'+ htmlMsg)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
svg.selectAll("path").sort(function (a, b) {
if (a != d) return -1;
else return 1;
});
var endAngle = d.endAngle + 0.1;
var startAngle = d.startAngle - 0.1;
var arcOver = d3.svg.arc()
.outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
d3.select(this)
.attr("stroke","white")
.transition()
.ease("bounce")
.duration(1000)
.attr("d", arcOver)
.attr("stroke-width",6);
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this).transition()
.attr("d", arc)
.attr("stroke","none");
})
.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
var k=0;
arcs2.append("text")
.transition()
.ease("elastic")
.duration(2000)
.delay(function (d, i) {
return i * 250;
})
.attr("x","6")
.attr("dy", ".35em")
.text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
.attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
.attr("font-size", "10px");
function type(d) {
d.count = +d.count;
return d;
}
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
var legend = d3.select("#chart")
.append("svg")
.attr("class", "legend")
.attr("width", radius+50)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain())
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.data(data)
.text(function(d,i) { return d.IP; });
</script>
</svg>
</div>
<script type="text/javascript">
var chart = $("#chart"),
aspect = chart.width() / chart.height(),
container = chart.parent();
$(window).on("resize", function() {
var targetWidth = container.width();
chart.attr("width", targetWidth);
chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");
</script>
</script>
</body>
</html>
Hello, I am new to D3.js. I am facing issues when building a responsive pie chart. The chart is responsive with tooltips also attached to it. But when I try to attach the legend to the chart the legend is overlapping the chart. Please help me. I am stuck. How can I place the legend beside my pie chart. Here are my codes that I have tried so far.
Thank for any help in advance.
This could be resolved in 3 ways:
Width of chart:
Here, the pie chart is too big for the given dimensions. Hence, the legends overlap. You could try changing the width: 300 to width: 700
Radius of circle:
If you can't change the width, you could reduce the radius of the pie chart. Currently, it selects minimum of the width/height and divides by two subtracting 10 for margin. radius = Math.min(width, height) / 2 You could additionally specify radius = Math.min(width, height) / 2 - 50 to further reduce the radius by pixels.
Transform of the center:
Or you can also move the center of the pie chart further right. Currently, it is located halfway of the dimensions. .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"). You could make it say to be at 3/4 of the width and 40% of height .attr("transform", "translate(" + width * 3 / 4 + "," + height * 2 / 5 + ")")
I have utilised all three of the ways in your snippet:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<style type="text/css">
#container {
margin: 20px;
}
#chart {
position: absolute;
background-color: #eee;
}
#chart legend{
position: absolute;
margin: 100px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #900C3F;
display: inline-block;
font-size: 12px;
left: 600px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 150px;
z-index: 10;
opacity: 1;
}
rect {
stroke-width: 2;
}
path {
stroke: #ffffff;
stroke-width: 0.5;
}
div.tooltip {
position: absolute;
z-index: 999;
padding: 10px;
background: #f4f4f4;
border: 0px;
border-radius: 3px;
pointer-events: none;
font-size: 11px;
color: #080808;
line-height: 16px;
border: 1px solid #d4d4d4;
}
</style>
</head>
<body>
<div id="container">
<svg id="chart" width="600" height="300" viewBox="0 0 600 300" perserveAspectRatio="xMinYMid">
<div id="toolTip" class="tooltip" style="opacity: 0;"></div>
<script type="text/javascript">
var div = d3.select("#toolTip");
var data = [
{"IP":"192.168.12.1", "count":20},
{"IP":"76.09.45.34", "count":40},
{"IP":"34.91.23.76", "count":80},
{"IP":"192.168.19.32", "count":16},
{"IP":"192.168.10.89", "count":50},
{"IP":"192.178.34.07", "count":18},
{"IP":"192.168.12.98", "count":30}];
var width = 400,
height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
radius = Math.min(width, height) / 2 - 50;
var legendRectSize = 18,
legendSpacing = 4;
var color = d3.scale.category20b();
var arc = d3.svg.arc()
.outerRadius(radius);
var arcOver = d3.svg.arc()
.outerRadius(radius + 5);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.count; });
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#chart").append("svg")
.datum(data)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width * 3 / 4 + "," + height * 2/ 5 + ")");
var arcs = svg.selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var arcs2 = svg.selectAll(".arc2")
.data(pie)
.enter().append("g")
.attr("class", "arc2");
arcs.append("path")
.attr("fill", function(d, i) { return color(i); })
.on("mouseover", function(d) {
var htmlMsg="";
div.transition()
.style("opacity",0.9);
var total = d3.sum(data.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
div.html(
"IP :"+ d.data.IP +""+"<br/>"+
"Count : " + d.data.count +"<br/>" +
"Percent: " + percent + '%'+ htmlMsg)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
svg.selectAll("path").sort(function (a, b) {
if (a != d) return -1;
else return 1;
});
var endAngle = d.endAngle + 0.1;
var startAngle = d.startAngle - 0.1;
var arcOver = d3.svg.arc()
.outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
d3.select(this)
.attr("stroke","white")
.transition()
.ease("bounce")
.duration(1000)
.attr("d", arcOver)
.attr("stroke-width",6);
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this).transition()
.attr("d", arc)
.attr("stroke","none");
})
.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
var k=0;
arcs2.append("text")
.transition()
.ease("elastic")
.duration(2000)
.delay(function (d, i) {
return i * 250;
})
.attr("x","6")
.attr("dy", ".35em")
.text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
.attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
.attr("font-size", "10px");
function type(d) {
d.count = +d.count;
return d;
}
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
var legend = d3.select("#chart")
.append("svg")
.attr("class", "legend")
.attr("width", radius+50)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain())
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.data(data)
.text(function(d,i) { return d.IP; });
</script>
</svg>
</div>
<script type="text/javascript">
var chart = $("#chart"),
aspect = chart.width() / chart.height(),
container = chart.parent();
$(window).on("resize", function() {
var targetWidth = container.width();
chart.attr("width", targetWidth);
chart.attr("height", Math.round(targetWidth / aspect));
}).trigger("resize");
</script>
</script>
</body>
</html>