How to place legends for stacked bar chart underneath in d3.js$location not working in AngularJS using d3.jshow to format time on xAxis use d3.jsDraw the line use the same y values, plots line at the bottomd3js - TypeError: string is undefinedHow to apply a pattern for a D3 bar chart?d3 - trigger event on second clickX Y Co-ordinates of Stacked BarX & Y Co-ordinates of selective bars in a stack graphD3 Y Scale, y vs height?D3 Bar Chart - Reverse Bars from Right to Left
WordPress 5.2.1 deactivated my jQuery
Why haven't we yet tried accelerating a space station with people inside to a near light speed?
How do I superimpose two math symbols?
Operators in C++ what does (::Type*)0 mean
WAS IT A CAT I SAW? Do Some Detective Work & Catch The Imposters
Mercedes C180 (W204) dash symbol
Take elements from a list based on two criteria
What weight should be given to writers groups critiques?
Where is Jon going?
ESTA validity after a visa denial
Is it legal to meet with potential future employers in the UK, whilst visiting from the USA
How to cut a climbing rope?
My players want to grind XP but we're using landmark advancement
How to melt snow without fire or body heat?
Is it truly impossible to tell what a CPU is doing?
Non-containing subsets of two sizes
Natural Armour and Weapons
When playing Edgar Markov, what is the definition of a "Vampire spell"?
Security vulnerabilities of POST over SSL
Parallel fifths in the orchestra
Public transport tickets in UK for two weeks
USPS Back Room - Trespassing?
Did this character show any indication of wanting to rule before S8E6?
Are runways booked by airlines to land their planes?
How to place legends for stacked bar chart underneath in d3.js
$location not working in AngularJS using d3.jshow to format time on xAxis use d3.jsDraw the line use the same y values, plots line at the bottomd3js - TypeError: string is undefinedHow to apply a pattern for a D3 bar chart?d3 - trigger event on second clickX Y Co-ordinates of Stacked BarX & Y Co-ordinates of selective bars in a stack graphD3 Y Scale, y vs height?D3 Bar Chart - Reverse Bars from Right to Left
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I am trying to place the legends underneath the stacked bar chart aligned block. Can not transition it properly. Below is the code i have, at this moment the legends appear on the left top corner, what i am trying to do is the tranistion it properly underneath the stacked bar, is there any suggestion of how can i transition it so it fits the svg as well. Any suggestion will be appriciated
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<style>
</style>
<body>
<div class="canvas">
</div>
<script>
var data = [
month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q3-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q4-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q7-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q8-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960,
month: "Q11-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q12-2016", apples: 320, bananas: 480, cherries: -640,
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries"])
.offset(d3.stackOffsetDiverging)
(data);
var margin = top: 20, right: 30, bottom: 30, left: 60,
width = 900,
height = 600,
padding = 40,
svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);
var x = d3.scaleBand()
.domain(data.map(function(d)return d.month;))
.rangeRound([margin.left, width-margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom, margin.top]);
var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
var z = d3.scaleOrdinal(colors);
//create and call the axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
console.log(series);
svg.append('g')
.selectAll('g')
.data(series)
.enter().append('g')
.attr('fill', function (d)
return z(d.key);
)
.selectAll('rect')
.data(function(d) return d; )
.enter().append('rect')
.attr('width', x.bandwidth)
.attr('x', function(d) return x(d.data.month))
.attr("y", function(d) return y(d[1]); )
.attr("height", function(d) return y(d[0]) - y(d[1]); )
svg.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
var legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(' + (padding + 12) + ',0)');
legend.selectAll('rect')
.data(series)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d,i)
return i * 18;
)
.attr('width', 12)
.attr('height', 12)
.attr('fill', function(d,i)
return z(i);
);
legend.selectAll('text')
.data(series)
.enter()
.append('text')
.text(function(d)
return d.key;
)
.attr('x', -18)
.attr('y', function(d, i)
return i * 18;
)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
function stackMin(serie)
return d3.min(serie, function(d) return d[0]; );
function stackMax(serie)
return d3.max(serie, function(d) return d[1]; );
</script>
</body>
</html>
d3.js
add a comment |
I am trying to place the legends underneath the stacked bar chart aligned block. Can not transition it properly. Below is the code i have, at this moment the legends appear on the left top corner, what i am trying to do is the tranistion it properly underneath the stacked bar, is there any suggestion of how can i transition it so it fits the svg as well. Any suggestion will be appriciated
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<style>
</style>
<body>
<div class="canvas">
</div>
<script>
var data = [
month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q3-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q4-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q7-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q8-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960,
month: "Q11-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q12-2016", apples: 320, bananas: 480, cherries: -640,
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries"])
.offset(d3.stackOffsetDiverging)
(data);
var margin = top: 20, right: 30, bottom: 30, left: 60,
width = 900,
height = 600,
padding = 40,
svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);
var x = d3.scaleBand()
.domain(data.map(function(d)return d.month;))
.rangeRound([margin.left, width-margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom, margin.top]);
var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
var z = d3.scaleOrdinal(colors);
//create and call the axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
console.log(series);
svg.append('g')
.selectAll('g')
.data(series)
.enter().append('g')
.attr('fill', function (d)
return z(d.key);
)
.selectAll('rect')
.data(function(d) return d; )
.enter().append('rect')
.attr('width', x.bandwidth)
.attr('x', function(d) return x(d.data.month))
.attr("y", function(d) return y(d[1]); )
.attr("height", function(d) return y(d[0]) - y(d[1]); )
svg.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
var legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(' + (padding + 12) + ',0)');
legend.selectAll('rect')
.data(series)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d,i)
return i * 18;
)
.attr('width', 12)
.attr('height', 12)
.attr('fill', function(d,i)
return z(i);
);
legend.selectAll('text')
.data(series)
.enter()
.append('text')
.text(function(d)
return d.key;
)
.attr('x', -18)
.attr('y', function(d, i)
return i * 18;
)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
function stackMin(serie)
return d3.min(serie, function(d) return d[0]; );
function stackMax(serie)
return d3.max(serie, function(d) return d[1]; );
</script>
</body>
</html>
d3.js
add a comment |
I am trying to place the legends underneath the stacked bar chart aligned block. Can not transition it properly. Below is the code i have, at this moment the legends appear on the left top corner, what i am trying to do is the tranistion it properly underneath the stacked bar, is there any suggestion of how can i transition it so it fits the svg as well. Any suggestion will be appriciated
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<style>
</style>
<body>
<div class="canvas">
</div>
<script>
var data = [
month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q3-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q4-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q7-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q8-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960,
month: "Q11-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q12-2016", apples: 320, bananas: 480, cherries: -640,
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries"])
.offset(d3.stackOffsetDiverging)
(data);
var margin = top: 20, right: 30, bottom: 30, left: 60,
width = 900,
height = 600,
padding = 40,
svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);
var x = d3.scaleBand()
.domain(data.map(function(d)return d.month;))
.rangeRound([margin.left, width-margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom, margin.top]);
var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
var z = d3.scaleOrdinal(colors);
//create and call the axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
console.log(series);
svg.append('g')
.selectAll('g')
.data(series)
.enter().append('g')
.attr('fill', function (d)
return z(d.key);
)
.selectAll('rect')
.data(function(d) return d; )
.enter().append('rect')
.attr('width', x.bandwidth)
.attr('x', function(d) return x(d.data.month))
.attr("y", function(d) return y(d[1]); )
.attr("height", function(d) return y(d[0]) - y(d[1]); )
svg.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
var legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(' + (padding + 12) + ',0)');
legend.selectAll('rect')
.data(series)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d,i)
return i * 18;
)
.attr('width', 12)
.attr('height', 12)
.attr('fill', function(d,i)
return z(i);
);
legend.selectAll('text')
.data(series)
.enter()
.append('text')
.text(function(d)
return d.key;
)
.attr('x', -18)
.attr('y', function(d, i)
return i * 18;
)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
function stackMin(serie)
return d3.min(serie, function(d) return d[0]; );
function stackMax(serie)
return d3.max(serie, function(d) return d[1]; );
</script>
</body>
</html>
d3.js
I am trying to place the legends underneath the stacked bar chart aligned block. Can not transition it properly. Below is the code i have, at this moment the legends appear on the left top corner, what i am trying to do is the tranistion it properly underneath the stacked bar, is there any suggestion of how can i transition it so it fits the svg as well. Any suggestion will be appriciated
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<style>
</style>
<body>
<div class="canvas">
</div>
<script>
var data = [
month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q3-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q4-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q7-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q8-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960,
month: "Q11-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q12-2016", apples: 320, bananas: 480, cherries: -640,
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries"])
.offset(d3.stackOffsetDiverging)
(data);
var margin = top: 20, right: 30, bottom: 30, left: 60,
width = 900,
height = 600,
padding = 40,
svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);
var x = d3.scaleBand()
.domain(data.map(function(d)return d.month;))
.rangeRound([margin.left, width-margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom, margin.top]);
var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
var z = d3.scaleOrdinal(colors);
//create and call the axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
console.log(series);
svg.append('g')
.selectAll('g')
.data(series)
.enter().append('g')
.attr('fill', function (d)
return z(d.key);
)
.selectAll('rect')
.data(function(d) return d; )
.enter().append('rect')
.attr('width', x.bandwidth)
.attr('x', function(d) return x(d.data.month))
.attr("y", function(d) return y(d[1]); )
.attr("height", function(d) return y(d[0]) - y(d[1]); )
svg.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
var legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(' + (padding + 12) + ',0)');
legend.selectAll('rect')
.data(series)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d,i)
return i * 18;
)
.attr('width', 12)
.attr('height', 12)
.attr('fill', function(d,i)
return z(i);
);
legend.selectAll('text')
.data(series)
.enter()
.append('text')
.text(function(d)
return d.key;
)
.attr('x', -18)
.attr('y', function(d, i)
return i * 18;
)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
function stackMin(serie)
return d3.min(serie, function(d) return d[0]; );
function stackMax(serie)
return d3.max(serie, function(d) return d[1]; );
</script>
</body>
</html>
d3.js
d3.js
asked Mar 24 at 0:52
bisamovbisamov
9418
9418
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
There were a few things going wrong in your code, so I tried to fix some of it.
Your chart elements (i.e. the bars and axis) should be added to a group. This will allow it to be moved/translated appropriately as needed. I create a
chart
variable and assigned these elements to it, rather than directly to the svg. This makes the structure easier to see when you view in the console too.The height of the legend area should be declared and accounted for in the chart. I declared this as a variable
legendh
and account for it in the y axis range.If you want your legend group to appear below the chart it needs to be translated below the chart. Your earlier transform on the group mentioned
.attr('transform', 'translate(' + (padding + 12) + ',0)');
making the y coordinates 0. I changed it to.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
. This tells the legend group to move down from the top by theheight - legendh
amount, thus placing it below the chart.Lastly, the colors in the legend were not matching the colors in the chart/bars. This was because your bar fill was goverened by
d.key
but your legend fill was based oni
. I chose to make it uniform and get the color usingz(i)
.
Here is the working block: https://bl.ocks.org/akulmehta/80153b35ab7498d30408f92cfa50f356
Here is the working code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<style>
</style>
<body>
<div class="canvas">
</div>
<script>
var data = [
month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q3-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q4-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q7-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q8-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960,
month: "Q11-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q12-2016", apples: 320, bananas: 480, cherries: -640,
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries"])
.offset(d3.stackOffsetDiverging)
(data);
var margin = top: 20, right: 30, bottom: 30, left: 60,
width = 900,
height = 500,
legendh = 100, //determines the height of the legend below the chart
padding = 40,
svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);
var x = d3.scaleBand()
.domain(data.map(function(d)return d.month;))
.rangeRound([margin.left, width-margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom - legendh, margin.top]);
var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
var z = d3.scaleOrdinal(colors);
//create and call the axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
var chart = svg.append('g').attr('id','chart'); //make a chart group inside the svg
chart.append('g')
.selectAll('g')
.data(series)
.enter().append('g')
.attr('fill', function (d,i) //because the legend is based on i this should also be based on i
return z(i);
)
.selectAll('rect')
.data(function(d) return d; )
.enter().append('rect')
.attr('width', x.bandwidth)
.attr('x', function(d) return x(d.data.month))
.attr("y", function(d) return y(d[1]); )
.attr("height", function(d) return y(d[0]) - y(d[1]); )
chart.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
chart.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
var legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
legend.selectAll('rect')
.data(series)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d,i)
return i * 18;
)
.attr('width', 12)
.attr('height', 12)
.attr('fill', function(d,i)
console.log(z(i));
return z(i);
);
legend.selectAll('text')
.data(series)
.enter()
.append('text')
.text(function(d)
return d.key;
)
.attr('x', 15)
.attr('y', function(d, i)
return i * 18;
)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
function stackMin(serie)
return d3.min(serie, function(d) return d[0]; );
function stackMax(serie)
return d3.max(serie, function(d) return d[1]; );
</script>
</body>
</html>
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55319777%2fhow-to-place-legends-for-stacked-bar-chart-underneath-in-d3-js%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
There were a few things going wrong in your code, so I tried to fix some of it.
Your chart elements (i.e. the bars and axis) should be added to a group. This will allow it to be moved/translated appropriately as needed. I create a
chart
variable and assigned these elements to it, rather than directly to the svg. This makes the structure easier to see when you view in the console too.The height of the legend area should be declared and accounted for in the chart. I declared this as a variable
legendh
and account for it in the y axis range.If you want your legend group to appear below the chart it needs to be translated below the chart. Your earlier transform on the group mentioned
.attr('transform', 'translate(' + (padding + 12) + ',0)');
making the y coordinates 0. I changed it to.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
. This tells the legend group to move down from the top by theheight - legendh
amount, thus placing it below the chart.Lastly, the colors in the legend were not matching the colors in the chart/bars. This was because your bar fill was goverened by
d.key
but your legend fill was based oni
. I chose to make it uniform and get the color usingz(i)
.
Here is the working block: https://bl.ocks.org/akulmehta/80153b35ab7498d30408f92cfa50f356
Here is the working code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<style>
</style>
<body>
<div class="canvas">
</div>
<script>
var data = [
month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q3-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q4-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q7-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q8-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960,
month: "Q11-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q12-2016", apples: 320, bananas: 480, cherries: -640,
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries"])
.offset(d3.stackOffsetDiverging)
(data);
var margin = top: 20, right: 30, bottom: 30, left: 60,
width = 900,
height = 500,
legendh = 100, //determines the height of the legend below the chart
padding = 40,
svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);
var x = d3.scaleBand()
.domain(data.map(function(d)return d.month;))
.rangeRound([margin.left, width-margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom - legendh, margin.top]);
var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
var z = d3.scaleOrdinal(colors);
//create and call the axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
var chart = svg.append('g').attr('id','chart'); //make a chart group inside the svg
chart.append('g')
.selectAll('g')
.data(series)
.enter().append('g')
.attr('fill', function (d,i) //because the legend is based on i this should also be based on i
return z(i);
)
.selectAll('rect')
.data(function(d) return d; )
.enter().append('rect')
.attr('width', x.bandwidth)
.attr('x', function(d) return x(d.data.month))
.attr("y", function(d) return y(d[1]); )
.attr("height", function(d) return y(d[0]) - y(d[1]); )
chart.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
chart.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
var legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
legend.selectAll('rect')
.data(series)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d,i)
return i * 18;
)
.attr('width', 12)
.attr('height', 12)
.attr('fill', function(d,i)
console.log(z(i));
return z(i);
);
legend.selectAll('text')
.data(series)
.enter()
.append('text')
.text(function(d)
return d.key;
)
.attr('x', 15)
.attr('y', function(d, i)
return i * 18;
)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
function stackMin(serie)
return d3.min(serie, function(d) return d[0]; );
function stackMax(serie)
return d3.max(serie, function(d) return d[1]; );
</script>
</body>
</html>
add a comment |
There were a few things going wrong in your code, so I tried to fix some of it.
Your chart elements (i.e. the bars and axis) should be added to a group. This will allow it to be moved/translated appropriately as needed. I create a
chart
variable and assigned these elements to it, rather than directly to the svg. This makes the structure easier to see when you view in the console too.The height of the legend area should be declared and accounted for in the chart. I declared this as a variable
legendh
and account for it in the y axis range.If you want your legend group to appear below the chart it needs to be translated below the chart. Your earlier transform on the group mentioned
.attr('transform', 'translate(' + (padding + 12) + ',0)');
making the y coordinates 0. I changed it to.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
. This tells the legend group to move down from the top by theheight - legendh
amount, thus placing it below the chart.Lastly, the colors in the legend were not matching the colors in the chart/bars. This was because your bar fill was goverened by
d.key
but your legend fill was based oni
. I chose to make it uniform and get the color usingz(i)
.
Here is the working block: https://bl.ocks.org/akulmehta/80153b35ab7498d30408f92cfa50f356
Here is the working code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<style>
</style>
<body>
<div class="canvas">
</div>
<script>
var data = [
month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q3-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q4-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q7-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q8-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960,
month: "Q11-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q12-2016", apples: 320, bananas: 480, cherries: -640,
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries"])
.offset(d3.stackOffsetDiverging)
(data);
var margin = top: 20, right: 30, bottom: 30, left: 60,
width = 900,
height = 500,
legendh = 100, //determines the height of the legend below the chart
padding = 40,
svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);
var x = d3.scaleBand()
.domain(data.map(function(d)return d.month;))
.rangeRound([margin.left, width-margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom - legendh, margin.top]);
var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
var z = d3.scaleOrdinal(colors);
//create and call the axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
var chart = svg.append('g').attr('id','chart'); //make a chart group inside the svg
chart.append('g')
.selectAll('g')
.data(series)
.enter().append('g')
.attr('fill', function (d,i) //because the legend is based on i this should also be based on i
return z(i);
)
.selectAll('rect')
.data(function(d) return d; )
.enter().append('rect')
.attr('width', x.bandwidth)
.attr('x', function(d) return x(d.data.month))
.attr("y", function(d) return y(d[1]); )
.attr("height", function(d) return y(d[0]) - y(d[1]); )
chart.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
chart.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
var legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
legend.selectAll('rect')
.data(series)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d,i)
return i * 18;
)
.attr('width', 12)
.attr('height', 12)
.attr('fill', function(d,i)
console.log(z(i));
return z(i);
);
legend.selectAll('text')
.data(series)
.enter()
.append('text')
.text(function(d)
return d.key;
)
.attr('x', 15)
.attr('y', function(d, i)
return i * 18;
)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
function stackMin(serie)
return d3.min(serie, function(d) return d[0]; );
function stackMax(serie)
return d3.max(serie, function(d) return d[1]; );
</script>
</body>
</html>
add a comment |
There were a few things going wrong in your code, so I tried to fix some of it.
Your chart elements (i.e. the bars and axis) should be added to a group. This will allow it to be moved/translated appropriately as needed. I create a
chart
variable and assigned these elements to it, rather than directly to the svg. This makes the structure easier to see when you view in the console too.The height of the legend area should be declared and accounted for in the chart. I declared this as a variable
legendh
and account for it in the y axis range.If you want your legend group to appear below the chart it needs to be translated below the chart. Your earlier transform on the group mentioned
.attr('transform', 'translate(' + (padding + 12) + ',0)');
making the y coordinates 0. I changed it to.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
. This tells the legend group to move down from the top by theheight - legendh
amount, thus placing it below the chart.Lastly, the colors in the legend were not matching the colors in the chart/bars. This was because your bar fill was goverened by
d.key
but your legend fill was based oni
. I chose to make it uniform and get the color usingz(i)
.
Here is the working block: https://bl.ocks.org/akulmehta/80153b35ab7498d30408f92cfa50f356
Here is the working code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<style>
</style>
<body>
<div class="canvas">
</div>
<script>
var data = [
month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q3-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q4-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q7-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q8-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960,
month: "Q11-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q12-2016", apples: 320, bananas: 480, cherries: -640,
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries"])
.offset(d3.stackOffsetDiverging)
(data);
var margin = top: 20, right: 30, bottom: 30, left: 60,
width = 900,
height = 500,
legendh = 100, //determines the height of the legend below the chart
padding = 40,
svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);
var x = d3.scaleBand()
.domain(data.map(function(d)return d.month;))
.rangeRound([margin.left, width-margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom - legendh, margin.top]);
var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
var z = d3.scaleOrdinal(colors);
//create and call the axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
var chart = svg.append('g').attr('id','chart'); //make a chart group inside the svg
chart.append('g')
.selectAll('g')
.data(series)
.enter().append('g')
.attr('fill', function (d,i) //because the legend is based on i this should also be based on i
return z(i);
)
.selectAll('rect')
.data(function(d) return d; )
.enter().append('rect')
.attr('width', x.bandwidth)
.attr('x', function(d) return x(d.data.month))
.attr("y", function(d) return y(d[1]); )
.attr("height", function(d) return y(d[0]) - y(d[1]); )
chart.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
chart.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
var legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
legend.selectAll('rect')
.data(series)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d,i)
return i * 18;
)
.attr('width', 12)
.attr('height', 12)
.attr('fill', function(d,i)
console.log(z(i));
return z(i);
);
legend.selectAll('text')
.data(series)
.enter()
.append('text')
.text(function(d)
return d.key;
)
.attr('x', 15)
.attr('y', function(d, i)
return i * 18;
)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
function stackMin(serie)
return d3.min(serie, function(d) return d[0]; );
function stackMax(serie)
return d3.max(serie, function(d) return d[1]; );
</script>
</body>
</html>
There were a few things going wrong in your code, so I tried to fix some of it.
Your chart elements (i.e. the bars and axis) should be added to a group. This will allow it to be moved/translated appropriately as needed. I create a
chart
variable and assigned these elements to it, rather than directly to the svg. This makes the structure easier to see when you view in the console too.The height of the legend area should be declared and accounted for in the chart. I declared this as a variable
legendh
and account for it in the y axis range.If you want your legend group to appear below the chart it needs to be translated below the chart. Your earlier transform on the group mentioned
.attr('transform', 'translate(' + (padding + 12) + ',0)');
making the y coordinates 0. I changed it to.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
. This tells the legend group to move down from the top by theheight - legendh
amount, thus placing it below the chart.Lastly, the colors in the legend were not matching the colors in the chart/bars. This was because your bar fill was goverened by
d.key
but your legend fill was based oni
. I chose to make it uniform and get the color usingz(i)
.
Here is the working block: https://bl.ocks.org/akulmehta/80153b35ab7498d30408f92cfa50f356
Here is the working code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
</style>
</head>
<style>
</style>
<body>
<div class="canvas">
</div>
<script>
var data = [
month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q3-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q4-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960,
month: "Q7-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q8-2016", apples: 320, bananas: 480, cherries: -640,
month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960,
month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960,
month: "Q11-2016", apples: 640, bananas: 960, cherries: -640,
month: "Q12-2016", apples: 320, bananas: 480, cherries: -640,
];
var series = d3.stack()
.keys(["apples", "bananas", "cherries"])
.offset(d3.stackOffsetDiverging)
(data);
var margin = top: 20, right: 30, bottom: 30, left: 60,
width = 900,
height = 500,
legendh = 100, //determines the height of the legend below the chart
padding = 40,
svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);
var x = d3.scaleBand()
.domain(data.map(function(d)return d.month;))
.rangeRound([margin.left, width-margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom - legendh, margin.top]);
var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
var z = d3.scaleOrdinal(colors);
//create and call the axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
var chart = svg.append('g').attr('id','chart'); //make a chart group inside the svg
chart.append('g')
.selectAll('g')
.data(series)
.enter().append('g')
.attr('fill', function (d,i) //because the legend is based on i this should also be based on i
return z(i);
)
.selectAll('rect')
.data(function(d) return d; )
.enter().append('rect')
.attr('width', x.bandwidth)
.attr('x', function(d) return x(d.data.month))
.attr("y", function(d) return y(d[1]); )
.attr("height", function(d) return y(d[0]) - y(d[1]); )
chart.append("g")
.attr("transform", "translate(0," + y(0) + ")")
.call(d3.axisBottom(x));
chart.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
var legend = svg.append('g')
.attr('class', 'legend')
.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');
legend.selectAll('rect')
.data(series)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d,i)
return i * 18;
)
.attr('width', 12)
.attr('height', 12)
.attr('fill', function(d,i)
console.log(z(i));
return z(i);
);
legend.selectAll('text')
.data(series)
.enter()
.append('text')
.text(function(d)
return d.key;
)
.attr('x', 15)
.attr('y', function(d, i)
return i * 18;
)
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
function stackMin(serie)
return d3.min(serie, function(d) return d[0]; );
function stackMax(serie)
return d3.max(serie, function(d) return d[1]; );
</script>
</body>
</html>
answered Mar 24 at 17:37
CoolaCoola
411514
411514
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55319777%2fhow-to-place-legends-for-stacked-bar-chart-underneath-in-d3-js%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown