legend not visible in d3.js pie chart - d3.js

I am trying to add legend to pie chart. I can see the legend element added in the inspect element but I am not able to see it. Could it be due to background color ? I looked into other questions but I am not able to solve the problem.
Can somebody explain what is wrong with my code ?
I also pasted the image below showing that the legend is attached to the svg.
Here is the code snippet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>barchart</title>
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="piechart">
</div>
<script>
//chart dimensions
var width = 300;
var height = 300;
var radius = Math.min(width, height) / 2;
var labelHeight = 18;
var data = {
2011: 9,
2012: 12,
2013: 10,
2014: 8,
2015: 12,
2016: 20
}
//color scale
var color = d3.scaleOrdinal().range(["#126608", "#049a0d", "#587b08", "#048440", "#177c0a", "#4a8d36", "#3b712b", "#4a8b00", "#426b07", "#4b940b"]);
//arc
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.pie()
.value(function(d) {
return d.value;
})
var svg = d3.select("#piechart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var pie_data = pie(d3.entries(data))
console.log(pie_data)
//svg.selectAll("path").remove()
var g = svg.selectAll("path")
.data(pie_data)
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color(d.data.key)
});
g.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("fill", "white")
.text(function(d) {
return d.data.key
});
var legend = svg.append("g")
.attr("class", "legend")
.attr("font-family", "sans-serif")
.attr("font-size", 20)
.attr("text-anchor", "start")
.selectAll("g")
.data(pie_data)
.enter().append("g")
.attr("transform", function(d, i) {
return "translate(0," + i * 30 + ")";
});
legend.append("text")
.attr("x", radius + 30)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) {
return d.data.key;
});
legend.append("rect")
.attr("x", radius + 10)
.attr("width", 19)
.attr("height", 19)
.attr("fill", function(d) {
return color(d.data.key);
});
</script>
</body>
</html>

You simply missed to set a proper with for the content, but what you have to actually do is to implement margin convention for your chart:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>barchart</title>
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="piechart">
</div>
<script>
//chart dimensions
var width = 500;
var height = 300;
var radius = Math.min(width, height) / 2;
var labelHeight = 18;
var data = {
2011: 9,
2012: 12,
2013: 10,
2014: 8,
2015: 12,
2016: 20
}
//color scale
var color = d3.scaleOrdinal().range(["#126608", "#049a0d", "#587b08", "#048440", "#177c0a", "#4a8d36", "#3b712b", "#4a8b00", "#426b07", "#4b940b"]);
//arc
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.pie()
.value(function(d) {
return d.value;
})
var svg = d3.select("#piechart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var pie_data = pie(d3.entries(data))
//svg.selectAll("path").remove()
var g = svg.selectAll("path")
.data(pie_data)
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) {
return color(d.data.key)
});
g.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.style("text-anchor", "middle")
.attr("fill", "white")
.text(function(d) {
return d.data.key
});
var legend = svg.append("g")
.attr("class", "legend")
.attr("font-family", "sans-serif")
.attr("font-size", 20)
.attr("text-anchor", "start")
.selectAll("g")
.data(pie_data)
.enter().append("g")
.attr("transform", function(d, i) {
return "translate(0," + i * 30 + ")";
});
legend.append("text")
.attr("x", radius + 30)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) {
return d.data.key;
});
legend.append("rect")
.attr("x", radius + 10)
.attr("width", 19)
.attr("height", 19)
.attr("fill", function(d) {
return color(d.data.key);
});
</script>
</body>
</html>

Related

d3.js - add text above bar chart not show [duplicate]

This question already has answers here:
D3 Appending Text to a SVG Rectangle
(2 answers)
SVG: text inside rect
(5 answers)
Closed 1 year ago.
After study this excelent d3.js tutorial, I like to add the bar value on top of each bar! below example code the text not show up!
XYZ.csv
year,value
2011,45
2012,47
2013,52
2014,70
2015,75
2016,78
html file:
<!doctype html>
<html>
<head>
<style>
.bar {
fill: steelblue;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg width="600" height="500"></svg>
<script>
var svg = d3.select("svg"),
margin = 200,
width = svg.attr("width") - margin,
height = svg.attr("height") - margin
var xScale = d3.scaleBand().range([0, width]).padding(0.4),
yScale = d3.scaleLinear().range([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + 100 + "," + 100 + ")");
d3.csv("XYZ.csv", function(error, data) {
if (error) {
throw error;
}
xScale.domain(data.map(function(d) { return d.year; }));
yScale.domain([0, d3.max(data, function(d) { return d.value; })]);
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
g.append("g")
.call(d3.axisLeft(yScale).tickFormat(function(d){
return "$" + d;
}).ticks(10));
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return xScale(d.year); })
.attr("y", function(d) { return yScale(d.value); })
.attr("width", xScale.bandwidth())
.attr("height", function(d) { return height - yScale(d.value); })
.append("text")
.attr("x", function(d) { return xScale(d.year); })
.attr("y", function(d) { return yScale(d.value); })
.attr("text", function(d) { return d.value; })
});
</script>
</body>
</html>
Below code is added for text on top of each bar:
.append("text")
.attr("x", function(d) { return xScale(d.year); })
.attr("y", function(d) { return yScale(d.value); })
.attr("text", function(d) { return d.value; })
It's impossible to append a <text> to a <rect>. Just add the texts separately:
g.selectAll(".bar-title")
.data(data)
.enter()
.append("text")
.classed('bar-title', true)
.attr('text-anchor', 'middle')
.attr("x", d => xScale(d.year) + xScale.bandwidth()/2)
.attr("y", d => yScale(d.value))
.text(d => `$${d.value}`);
... or, you can append a <g> element on enter() and then append <text> and <rect> under <g>.
const data = [
{year: 2011, value: 45},
{year: 2012, value: 47},
{year: 2013, value: 52},
{year: 2014, value: 70},
{year: 2015, value: 75},
{year: 2016, value: 78}
];
var svg = d3.select("svg"),
margin = 200,
width = svg.attr("width") - margin,
height = svg.attr("height") - margin
var xScale = d3.scaleBand().range([0, width]).padding(0.4),
yScale = d3.scaleLinear().range([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + 100 + "," + 100 + ")");
xScale.domain(data.map(function(d) { return d.year; }));
yScale.domain([0, d3.max(data, function(d) { return d.value; })]);
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
g.append("g")
.call(d3.axisLeft(yScale).tickFormat(function(d){
return "$" + d;
}).ticks(10));
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return xScale(d.year); })
.attr("y", function(d) { return yScale(d.value); })
.attr("width", xScale.bandwidth())
.attr("height", function(d) { return height - yScale(d.value); })
g.selectAll(".bar-title")
.data(data)
.enter()
.append("text")
.classed('bar-title', true)
.attr('text-anchor', 'middle')
.attr("x", d => xScale(d.year) + xScale.bandwidth()/2)
.attr("y", d => yScale(d.value) - 5)
.text(d => `$${d.value}`);
.bar {
fill: steelblue;
}
.bar-title {
font-family: 'Ubuntu';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg width="600" height="500"></svg>

d3.js Grouped Bar Chart: text is not showing on bars

I am trying to add text on each bar in grouped bar chart. but it is not showing & no error is there on console.
I am using the sample code from https://bl.ocks.org/bricedev/0d95074b6d83a77dc3ad
I tried below code:
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
//display: none; //to show x axis
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 40, right: 60, bottom: 40, left: 40},
width = 560 - margin.left - margin.right,
height = 300 - 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 xAxis = d3.svg.axis()
.scale(x0)
.tickSize(0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var color = d3.scale.ordinal()
.range(["#ca0020","#f4a582","#d5d5d5","#92c5de","#0571b0"]);
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("data.json", function(error, data) {
var categoriesNames = data.map(function(d) { return d.categorie; });
var rateNames = data[0].values.map(function(d) { return d.rate; });
x0.domain(categoriesNames);
x1.domain(rateNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(categorie) { return d3.max(categorie.values, function(d) { return d.value; }); })]);
//Graph Title
svg.append("text")
.attr("transform", "translate(100,0)")
.attr("x", 100)
.attr("y", -20)
.attr("font-size", "24px")
.text("Grouped Bar Chart");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight','bold')
.attr("transform", "translate(" + width + ",10)")
.text("Months");
svg.append("g")
.attr("class", "y axis")
.style('opacity','0')
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight','bold')
.text("Incidents");
svg.select('.y').transition().duration(500).delay(1300).style('opacity','1');
var slice = svg.selectAll(".slice")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform",function(d) { return "translate(" + x0(d.categorie) + ",0)"; });
//draw bars
slice.selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.rate); })
.style("fill", function(d) { return color(d.rate) })
.attr("y", function(d) { return y(0); })
.attr("height", function(d) { return height - y(0); })
.on("mouseover", function(d) {
d3.select(this).style("fill", d3.rgb(color(d.rate)).darker(2));
})
.on("mouseout", function(d) {
d3.select(this).style("fill", color(d.rate));
});
slice.selectAll("text")
.data(function(d) {return d.values ;})
.enter()
.append("text")
.attr("x", function(d) { return x1(d.rate); })
.attr("y", function(d) { return ( y(0) ) ; })
.text(function(d) {
return (d.value); // Value of the text
});
slice.selectAll("rect")
.transition()
.delay(function (d) {return Math.random()*1000;})
.duration(1000)
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
//Legend
var legend = svg.selectAll(".legend")
.data(data[0].values.map(function(d) { return d.rate; }).reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d,i) { return "translate(60," + i * 20 + ")"; })
.style("opacity","0");
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) { return color(d); });
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {return d; });
legend.transition().duration(500).delay(function(d,i){ return 1300 + 100 * i; }).style("opacity","1");
});
</script>
</body>
</html>
But the output is output after adding block
It is showing object object in output.
Please help.
output of code is here
You're appending to slice, which is a selection of all the bar groups, not the bars themselves. Try something like this to get started:
slice.selectAll("text")
.data(function(d) { return d.values; })
.enter().append("text")
.attr("x", function(d) { return x1(d.rate); })
.attr("y", function(d) { return y(d.value); })
.text(function(d) { return d.value })

How do you change color of lines drawn in d3 with svg?

I'm using this tutorial, Making a cool Bitcoin price chart using D3.js and the CryptoCompare API and I am having trouble styling the lines that are drawn.
For example, I would like to be able to select and style the lines x and y to change their color to white. See this snippet from the tutorial:
var x = d3.scaleTime()
.range([0, width])
I've tried adding .attr("fill", "#fff"), but this only breaks it. How do I change the colors of d3.scaleTime() and d3.scaleLinear()?
I have also tried the following as described in the d3-scale documentation:
var x = d3.scaleTime()
.range([0, width])
x(20); // "#9a3439"
Here's the entire script:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="960" height="500"></svg>
</head>
<style>
body {
text-align: center;
margin-top: 5em;
background-color: #74b9ff;
}
h1 {
color: snow;
}
</style>
<body>
<h1>Bitcoin Prices in U.S. Dollars</h1>
<script>
var url = "https://min-api.cryptocompare.com/data/histoday?fsym=BTC&tsym=USD&limit=200&aggregate=3&e=CCCAGG";
d3.json(url).get(function(error, d) {
var data = d.Data;
data.forEach(function(d){ d.time = new Date(d.time * 1000) });
if (error) throw error;
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
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 + ")");
var x = d3.scaleTime()
.range([0, width])
var y = d3.scaleLinear()
.range([height, 0]);
var line = d3.line()
.x(function(d) { return x(d.time); })
.y(function(d) { return y(d.close); });
x.domain(d3.extent(data, function(d) { return d.time; }));
y.domain(d3.extent(data, function(d) { return d.close; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.attr("stroke-width", 2)
.attr("fill", "none")
.style("font-size",".8em");
g.append("g")
.call(d3.axisLeft(y))
.attr("stroke-width", 2)
.style("font-size",".8em")
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 20)
.attr("text-anchor", "end")
.attr("font-size", "1.2em")
.text("Price ($)")
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#ffeaa7")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 2)
.attr("d", line);
});
</script>
</body>
</html>
You can style the axes as shown below.
var xAxis = g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
xAxis.select("path") //Axis
.style("stroke","white");
xAxis.selectAll("line") //ticks
.style("stroke","white");
var yAxis = g.append("g")
.call(d3.axisLeft(y));
yAxis.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 20)
.attr("text-anchor", "end")
.attr("font-size", "1.2em")
.text("Price ($)");
yAxis.select("path") //Axis
.style("stroke","white");
yAxis.selectAll("line") //ticks
.style("stroke","white");
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="960" height="500"></svg>
</head>
<style>
body {
text-align: center;
margin-top: 5em;
background-color: #74b9ff;
}
h1 {
color: snow;
}
</style>
<body>
<h1>Bitcoin Prices in U.S. Dollars</h1>
<script>
var url = "https://min-api.cryptocompare.com/data/histoday?fsym=BTC&tsym=USD&limit=200&aggregate=3&e=CCCAGG";
d3.json(url).get(function(error, d) {
var data = d.Data;
data.forEach(function(d) {
d.time = new Date(d.time * 1000)
});
if (error) throw error;
var svg = d3.select("svg"),
margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
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 + ")");
var x = d3.scaleTime()
.range([0, width])
var y = d3.scaleLinear()
.range([height, 0]);
var line = d3.line()
.x(function(d) {
return x(d.time);
})
.y(function(d) {
return y(d.close);
});
x.domain(d3.extent(data, function(d) {
return d.time;
}));
y.domain(d3.extent(data, function(d) {
return d.close;
}));
var xAxis = g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.attr("stroke-width", 2)
.attr("fill", "none")
.style("font-size", ".8em")
xAxis.select("path") //Axis
.style("stroke", "white");
xAxis.selectAll("line") //ticks
.style("stroke", "white");
var yAxis = g.append("g")
.call(d3.axisLeft(y))
.attr("stroke-width", 2)
.style("font-size", ".8em");
yAxis.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 20)
.attr("text-anchor", "end")
.attr("font-size", "1.2em")
.text("Price ($)");
yAxis.select("path") //Axis
.style("stroke", "white");
yAxis.selectAll("line") //ticks
.style("stroke", "white");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#ffeaa7")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 2)
.attr("d", line);
});
</script>
</body>
</html>
While Gilsha's answer seems like best practice and allows for more direct control over styling, the answer got from that was to use selectAll() to select and style each "path" (axes), "line" (ticks), and "text" (display of price and date).
Including the following in the end of the function d3.json(url).get(function(error, d) styles everything as white:
g.selectAll("path") //Axes
.style("stroke","white");
g.selectAll("line") //Ticks
.style("stroke","white");
g.selectAll("text") //Text displaying date and price
.attr("fill", "white");
Note that this broad-stroke approach includes the path for the plotted data line as well. If you need to distinguish between them, you can define a variable for that and style it independently as Gilsha did for the axes.

How can I add a background colour behind PNG, when image URL is pulled from my D3.js dataset?

I am making a scatterplot, and pulling in an image fill for each circle on the plot. The problem is that the images are PNG's with transparent backgrounds. This means my overlapping circles show through each other:
Seen here - http://i.stack.imgur.com/bphon.png
I have tried setting a background colour with the CSS, but it seems to be completely overwritten by the .style("fill") in the JS. And I am looking to pull in 30ish images, so I don't want to have to save them all to be able to load the images with my CSS.
So, my question is, is there a way to put a white background behind my PNGs, while pulling those PNGs from URL's contained in my dataset?
Thanks for the help
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style type="text/css">
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis-text {
font-family: sans-serif;
font-size: 11px;
background-color: white;
font-weight: bold;
}
.teamcircle {
background-color: white;
}
</style>
</head>
<body>
<div>
<input type="button" id="playerbtn" value="See Player View">
<input type="button" id="teambtn" value="See Team View">
</div>
<div id="data">
<div id="player-circles">
</div>
</div>
<script type="text/javascript">
//Width and height
var margin = {top: 50, right: 20, bottom: 30, left: 40};
var w = 960 - margin.left - margin.right;
var h = 500 - margin.top - margin.bottom;
//Create scale functions
var xScale = d3.scale.linear()
.range([0, w]);
var yScale = d3.scale.linear()
.range([h, 0]);
// var color = d3.scale.color();
// Define the Axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//Load the TEAM data set
var teamdata = d3.tsv("team.tsv", function(error, teamdata) {
if (error) throw error;
teamdata.forEach(function(d) {
d.entriesper60 = +d.entriesper60;
d.carryinpercent = +d.carryinpercent;
});
xScale.domain(d3.extent(teamdata, function(d) { return d.carryinpercent; })).nice();
yScale.domain(d3.extent(teamdata, function(d) { return d.entriesper60; })).nice();
//Create X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis)
.append("text")
.attr("class", "axis-text")
.attr("x", w)
.attr("y", -6)
.style("text-anchor", "end")
.text("Carry-in %");
//Create Y axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "axis-text")
.attr("y", -20)
.attr("z", 0)
.style("text-anchor", "middle")
.text("Entries/60")
// DEFS & Pattern for images
svg.append("defs")
.selectAll("pattern")
.data(teamdata)
.enter()
.append("pattern")
.attr('id', function(d, i) {
return d.name;
})
// .attr('patternUnits', 'userSpaceOnUse')
.attr('width', 20)
.attr('height', 20)
.append("image")
.attr("xlink:href", function(d) {
return d.image + d.name;
})
.attr('width', 20)
.attr('height', 20)
.attr("transform", "translate(2, 2)");
// Create TEAM Circles
svg.selectAll("circle")
.data(teamdata)
.enter()
.append("circle")
.attr("class", "teamcircle")
.style("stroke", function(d) { return d.hex; })
.style("stroke-width", 2)
.style("stroke-opacity", .8)
.attr("r", 12)
.attr("cx", function(d) { return xScale(d.carryinpercent); })
.attr("cy", function(d) { return yScale(d.entriesper60); })
.attr("fill", function(d) { return "url(#" + d.name + ")";
});
});
</script>
</body>
</html>
The best way I can think of is to create a group for every circle, and create a circle with a white background first. Something like this:
var teamCircle = svg.selectAll("g.teamcircle")
.data(teamdata)
.enter()
.append("g")
.attr("class", "teamcircle")
.transform(function(d){return "translate(" + xScale(d.carryinpercent) + "," + yScale(d.entriesper60) + ")"});
teamCircle.append("circle")
.attr("fill", "white")
.attr("r", 12)
teamCircle.append("circle")
.style("stroke", function(d) { return d.hex; })
.style("stroke-width", 2)
.style("stroke-opacity", .8)
.attr("r", 12)
.attr("fill", function(d) { return "url(#" + d.name + ")";

d3.js adding id's to the stacked bar chart

I have created a stacked bar chart which depicts scanned and unscanned items as bars and also added the tooltip to represent the values of each stack when mouse is moved over. However when i move on a stack i would like to show tooltip like "UnScanned - 57 items" and when i move the mouse over the lower bar it should display "Scanned - 50" . I just need to differentiate the bar whether it is scanned or unscanned along with the data values displayed.
My code goes like:
<!DOCTYPE html>
<html>
<head>
<title>Scanned vs Non Scanned Data</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="../../js/Core_functions.js"></script>
<script type="text/javascript" src="../../js/graphic_functions.js"></script>
<style type="text/css">
svg {
width: 960px;
height: 500px;
border: solid 1px #ccc;
font: 10px sans-serif;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<div id="container">
<h1>Mockup of Component Scanned Mapping DV</h1>
</div>
<script type="text/javascript">
var w = 960,
h = 500,
p = [20, 50, 30, 20],
x = d3.scale.ordinal().rangeRoundBands([0, w - p[1] - p[3]]),
y = d3.scale.linear().range([0, h - p[0] - p[2]]),
z = d3.scale.ordinal().range(["#819FF7", "#CB491A"]),
parse = d3.time.format("%m/%Y").parse,
format = d3.time.format("%b-%y");
/*var yAxis = d3.svg.axis()
.scale(y)
.ticks(12)
.orient("left");*/
var svg = d3.select("#container").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + p[3] + "," + (h - p[2]) + ")");
d3.csv("scandata.csv", function(scan) {
// Transpose the data into layers by cause.
var scantypes = d3.layout.stack()(["scanned", "unscanned"].map(function(scans) {
return scan.map(function(d) {
return {x: parse(d.date), y: +d[scans]};
});
}));
// Compute the x-domain (by date) and y-domain (by top).
x.domain(scantypes [0].map(function(d) { return d.x; }));
y.domain([0, d3.max(scantypes[scantypes .length - 1], function(d) { return d.y0 + d.y; })]);
// Add a group for each column.
var cause = svg.selectAll("g.scan")
.data(scantypes)
.enter().append("svg:g")
.attr("class", "scan")
.style("fill", function(d, i) { return z(i); })
.style("stroke", function(d, i) { return d3.rgb(z(i)).darker(); });
// Add a rect for each date.
var rect = cause.selectAll("rect")
.data(Object)
.enter().append("svg:rect")
.attr("x", function(d,i) {
if (i ==0)
{
return x(d.x)+ 10 ;
}
else
{
return x(d.x);
}} )
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand()/2)
.on("mouseover", function(d){
return tooltip.style("visibility", "visible")
.text((d.y))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 20) + "px"); ;})
.on("mousemove", function(d){
return tooltip.style("visibility", "visible")
.text((d.y))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 20) + "px"); ;})
.on("mouseout", function(d){return tooltip.style("visibility", "hidden");})
.on("click", function(d){console.log(d);});
var tooltip = d3.select("#container")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "visible")
.text("Scanned vs UnScanned")
.style("font", "Arial")
.style("font-size", "14px");
// Add a label per date.
var label = svg.selectAll("text")
.data(x.domain())
.enter().append("svg:text")
.attr("x", function(d) { return x(d) + x.rangeBand() / 3; })
.attr("y", 6)
.attr("text-anchor", "middle")
.attr("dy", ".71em")
.text(format);
// Add y-axis rules.
var rule = svg.selectAll("g.rule")
.data(y.ticks(5))
.enter().append("svg:g")
.attr("class", "rule")
.attr("transform", function(d) { return "translate(0," + -y(d) + ")"; });
rule.append("svg:line")
.attr("x2", w - p[1] - p[3])
.style("stroke", function(d) { return d ? "#fff" : "#000"; })
.style("stroke-opacity", function(d) { return d ? .7 : null; });
rule.append("svg:text")
.attr("x", -15)
.style("font-family","Arial 12px")
.attr("dy", ".25em")
.text(d3.format(",d"));
});
</script>
</body>
</html> </script>
</body>
</html>
My csv data :
date,scanned,unscanned
01/2014,10,90
02/2014,55,40
03/2014,45,23
04/2014,65,35
05/2014,100,20
06/2014,50,30
07/2014,10,90
08/2014,22,48
09/2014,0,100
10/2014,3,97
11/2014,22,60
12/2014,57,37
You could make this part of the data that you make for the chart:
var scantypes = d3.layout.stack()(["scanned", "unscanned"].map(function(scans) {
return scan.map(function(d) {
return {x: parse(d.date), y: +d[scans], type: scans};
});
}));
// more code...
.on("mouseover", function(d){
return tooltip.text(d.type + " - " + d.y);
});

Resources