I want to create a Stacked bar chart like http://bl.ocks.org/mbostock/3886208 . But I don't want to use CSV file.
How can I change this sample by using JSON data?
Anyone could help?
Your question is a bit vague but let's say we convert that CSV file to JSON data as:
var data = [{
"State": "VT",
"Under 5 Years": 32635,
"5 to 13 Years": 62538,
"14 to 17 Years": 33757,
"18 to 24 Years": 61679,
"25 to 44 Years": 155419,
"45 to 64 Years": 188593,
"65 Years and Over": 86649
}, {
"State": "VA",
"Under 5 Years": 522672,
"5 to 13 Years": 887525,
"14 to 17 Years": 413004,
"18 to 24 Years": 768475,
"25 to 44 Years": 2203286,
"45 to 64 Years": 2033550,
"65 Years and Over": 940577
},
...
Then you would need to fix the pre-processing (to get the keys and totals) as:
// fix pre-processing
var keys = [];
for (key in data[0]){
if (key != "State")
keys.push(key);
}
data.forEach(function(d){
d.total = 0;
keys.forEach(function(k){
d.total += d[k];
})
});
Then the rest of the example falls into place:
<!DOCTYPE html>
<style>
.axis .domain {
display: none;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand()
.rangeRound([0, width])
.paddingInner(0.05)
.align(0.1);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var z = d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var data = [{
"State": "VT",
"Under 5 Years": 32635,
"5 to 13 Years": 62538,
"14 to 17 Years": 33757,
"18 to 24 Years": 61679,
"25 to 44 Years": 155419,
"45 to 64 Years": 188593,
"65 Years and Over": 86649
}, {
"State": "VA",
"Under 5 Years": 522672,
"5 to 13 Years": 887525,
"14 to 17 Years": 413004,
"18 to 24 Years": 768475,
"25 to 44 Years": 2203286,
"45 to 64 Years": 2033550,
"65 Years and Over": 940577
}, {
"State": "WA",
"Under 5 Years": 433119,
"5 to 13 Years": 750274,
"14 to 17 Years": 357782,
"18 to 24 Years": 610378,
"25 to 44 Years": 1850983,
"45 to 64 Years": 1762811,
"65 Years and Over": 783877
}, {
"State": "WV",
"Under 5 Years": 105435,
"5 to 13 Years": 189649,
"14 to 17 Years": 91074,
"18 to 24 Years": 157989,
"25 to 44 Years": 470749,
"45 to 64 Years": 514505,
"65 Years and Over": 285067
}, {
"State": "WI",
"Under 5 Years": 362277,
"5 to 13 Years": 640286,
"14 to 17 Years": 311849,
"18 to 24 Years": 553914,
"25 to 44 Years": 1487457,
"45 to 64 Years": 1522038,
"65 Years and Over": 750146
}, {
"State": "WY",
"Under 5 Years": 38253,
"5 to 13 Years": 60890,
"14 to 17 Years": 29314,
"18 to 24 Years": 53980,
"25 to 44 Years": 137338,
"45 to 64 Years": 147279,
"65 Years and Over": 65614
}];
// fix pre-processing
var keys = [];
for (key in data[0]){
if (key != "State")
keys.push(key);
}
data.forEach(function(d){
d.total = 0;
keys.forEach(function(k){
d.total += d[k];
})
});
data.sort(function(a, b) {
return b.total - a.total;
});
x.domain(data.map(function(d) {
return d.State;
}));
y.domain([0, d3.max(data, function(d) {
return d.total;
})]).nice();
z.domain(keys);
g.append("g")
.selectAll("g")
.data(d3.stack().keys(keys)(data))
.enter().append("g")
.attr("fill", function(d) {
return z(d.key);
})
.selectAll("rect")
.data(function(d) {
return d;
})
.enter().append("rect")
.attr("x", function(d) {
return x(d.data.State);
})
.attr("y", function(d) {
return y(d[1]);
})
.attr("height", function(d) {
return y(d[0]) - y(d[1]);
})
.attr("width", x.bandwidth());
g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(null, "s"))
.append("text")
.attr("x", 2)
.attr("y", y(y.ticks().pop()) + 0.5)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.text("Population");
var legend = g.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "end")
.selectAll("g")
.data(keys.slice().reverse())
.enter().append("g")
.attr("transform", function(d, i) {
return "translate(0," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width - 19)
.attr("width", 19)
.attr("height", 19)
.attr("fill", z);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9.5)
.attr("dy", "0.32em")
.text(function(d) {
return d;
});
</script>
Related
I'm new to D3JS and struggling with stacked bar below is my dummy code. I tried adding 10 to data to make it visible and then subtract 10 from label to make the label look correct but this cause problem with yAxis where value of bar is crossing the ticker with less then bar value, for example label was showing 95 but bar crossed 100 ticker coz bar size is 95 + 10 = 105. Help me with this.[In image you can find out small bars label are not visible.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>d3.js learning</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
svg {
font: 10px sans-serif;
shape-rendering: crispEdges;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
}
path.domain {
stroke: none;
}
.y .tick line {
stroke: #ddd;
}
</style>
</head>
<body>
<div id="ashu" style="width: 700px; height:400px;"></div>
<script>
var data = [{
"health": "JAN",
"INSOLVENCIES": 1,
"SPV/ASSETBACKED": 67,
"OPERATINGCOMPANIES": 13,
"Bank": 15
}, {
"health": "FEB",
"INSOLVENCIES": 60,
"SPV/ASSETBACKED": 9,
"OPERATINGCOMPANIES": 20,
"Bank": 5
}, {
"health": "MAR",
"INSOLVENCIES": 40,
"SPV/ASSETBACKED": 22,
"OPERATINGCOMPANIES": 21,
"Bank": 99
}, {
"health": "APR",
"INSOLVENCIES": 60,
"SPV/ASSETBACKED": 1,
"OPERATINGCOMPANIES": 99,
"Bank": 90
}, {
"health": "MAY",
"INSOLVENCIES": 2,
"SPV/ASSETBACKED": 27,
"OPERATINGCOMPANIES": 43,
"Bank": 82
}, {
"health": "JUN",
"INSOLVENCIES": 17,
"SPV/ASSETBACKED": 52,
"OPERATINGCOMPANIES": 79,
"Bank": 9
}, {
"health": "JUL",
"INSOLVENCIES": 37,
"SPV/ASSETBACKED": 24,
"OPERATINGCOMPANIES": 35,
"Bank": 51
}, {
"health": "AUG",
"INSOLVENCIES": 16,
"SPV/ASSETBACKED": 17,
"OPERATINGCOMPANIES": 53,
"Bank": 38
}, {
"health": "SEP",
"INSOLVENCIES": 15,
"SPV/ASSETBACKED": 32,
"OPERATINGCOMPANIES": 5,
"Bank": 31
}];
let xData = d3.keys(data[0]);
const yData = xData.shift();
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var margin = {
top: 20,
right: 50,
bottom: 30,
left: 50
},
width = 400,
height = 300,
padding = 100;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var y_axis = d3.svg.axis().scale(y).orient("left").ticks(6).innerTickSize(-width)
.tickPadding(10);
var svg = d3.select("#ashu").append("svg").attr("width",
"100%").attr("height",
"100%").append("g").attr(
"transform",
"translate(" + margin.left + "," + margin.top + ")");
var dataIntermediate = xData.map(function(c) {
return data.map(function(d, yData) {
return {
x: d[Object.keys(d)[0]],
y: d[c]
};
});
});
var dataStackLayout = d3.layout.stack()(dataIntermediate);
x.domain(dataStackLayout[0].map(function(d) {
return d.x;
}));
var total = 0;
var maximumY = d3.max(dataStackLayout[dataStackLayout.length - 1], function(d) {
return (d.y + d.y0);
});
y.domain([-(maximumY * .02), maximumY]).nice();
var layer = svg.selectAll(".stack").data(dataStackLayout).enter()
.append("g").attr("class", "stack").style("fill",
function(d, i) {
return color(i);
});
layer.selectAll("rect")
.data(function(d) {
return d;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x(d.x);
})
.attr("y", function(d) {
return y(d.y + d.y0);
})
.attr("height", function(d) {
return y(d.y0) - y(d.y + d.y0);
})
.attr("width", x.rangeBand())
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html("Total : " + (d.y + d.y0))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
layer.selectAll("text")
.data(function(d) {
return d;
})
.enter()
.append("text")
.text(function(d) {
let r = ((d.y < 10) ? (d.y - 10) : d.y);
return d.y;
})
.attr("x", function(d, i) {
return x(d.x) + 15;
})
.attr("y", function(d) {
return y(d.y0);
})
.attr("dy", "-0.15em")
.attr("text-anchor", "middle")
.style("fill", "black");
svg.append("g").attr("class", "axis").attr("transform",
"translate(0," + height + ")").call(xAxis);
svg.append("g").attr("class", "y axis").attr("transform", "translate(0,0)").call(y_axis);
var legend = svg.selectAll(".legend")
.data(color.domain().slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + Math.abs((i - 8) * 20) + ")";
});
legend.append("rect")
.attr("x", width + 10)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width + 32)
.attr("y", 10)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d, i) {
return xData[i];
});
</script>
</body>
</html>
the labels are being hidden due the order in which the g elements are creating in the DOM, in that elements created later will overlap elements created earlier. This means that the INSOLVENCIES group labels will be hidden by the orange rects for the SPV/ASSETBACKED.
A solution would be to create new g element for your labels, so they always appear on top of your rects. See the snippet below.
Now, where you have small values, there will always be a challenge about where to position the labels. The snippet places them in the middle of the bar, but you may need to play around with that
var data = [{
"health": "JAN",
"INSOLVENCIES": 1,
"SPV/ASSETBACKED": 67,
"OPERATINGCOMPANIES": 13,
"Bank": 15
}, {
"health": "FEB",
"INSOLVENCIES": 60,
"SPV/ASSETBACKED": 9,
"OPERATINGCOMPANIES": 20,
"Bank": 5
}, {
"health": "MAR",
"INSOLVENCIES": 40,
"SPV/ASSETBACKED": 22,
"OPERATINGCOMPANIES": 21,
"Bank": 99
}, {
"health": "APR",
"INSOLVENCIES": 60,
"SPV/ASSETBACKED": 1,
"OPERATINGCOMPANIES": 99,
"Bank": 90
}, {
"health": "MAY",
"INSOLVENCIES": 2,
"SPV/ASSETBACKED": 27,
"OPERATINGCOMPANIES": 43,
"Bank": 82
}, {
"health": "JUN",
"INSOLVENCIES": 17,
"SPV/ASSETBACKED": 52,
"OPERATINGCOMPANIES": 79,
"Bank": 9
}, {
"health": "JUL",
"INSOLVENCIES": 37,
"SPV/ASSETBACKED": 24,
"OPERATINGCOMPANIES": 35,
"Bank": 51
}, {
"health": "AUG",
"INSOLVENCIES": 16,
"SPV/ASSETBACKED": 17,
"OPERATINGCOMPANIES": 53,
"Bank": 38
}, {
"health": "SEP",
"INSOLVENCIES": 15,
"SPV/ASSETBACKED": 32,
"OPERATINGCOMPANIES": 5,
"Bank": 31
}];
let xData = d3.keys(data[0]);
const yData = xData.shift();
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var margin = {
top: 20,
right: 50,
bottom: 30,
left: 50
},
width = 400,
height = 300,
padding = 100;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var y_axis = d3.svg.axis().scale(y).orient("left").ticks(6).innerTickSize(-width)
.tickPadding(10);
var svg = d3.select("#ashu").append("svg").attr("width",
"100%").attr("height",
"100%").append("g").attr(
"transform",
"translate(" + margin.left + "," + margin.top + ")");
var dataIntermediate = xData.map(function(c) {
return data.map(function(d, yData) {
return {
x: d[Object.keys(d)[0]],
y: d[c]
};
});
});
var dataStackLayout = d3.layout.stack()(dataIntermediate);
x.domain(dataStackLayout[0].map(function(d) {
return d.x;
}));
var total = 0;
var maximumY = d3.max(dataStackLayout[dataStackLayout.length - 1], function(d) {
return (d.y + d.y0);
});
y.domain([0, maximumY]).nice();
var layer1 = svg.selectAll(".stack1").data(dataStackLayout).enter()
.append("g").attr("class", "stack").style("fill",
function(d, i) {
return color(i);
});
var layer2 = svg.selectAll(".stack2").data(dataStackLayout).enter()
.append("g")
.attr("class", "stack")
.style("fill", "black");
layer1.selectAll("rect")
.data(function(d) {
return d;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x(d.x);
})
.attr("y", function(d) {
return y(d.y + d.y0);
})
.attr("height", function(d) {
return y(d.y0) - y(d.y + d.y0);
})
.attr("width", x.rangeBand())
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html("Total : " + (d.y + d.y0))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
layer2.selectAll("text")
.data(function(d) {
return d;
})
.enter()
.append("text")
.text(function(d) {
return d.y;
})
.attr("x", function(d, i) {
return x(d.x) + (x.rangeBand())/2;
})
.attr("y", function(d) {
return y(d.y0 + (d.y/2));
})
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.style("fill", "black");
svg.append("g").attr("class", "axis").attr("transform",
"translate(0," + height + ")").call(xAxis);
svg.append("g").attr("class", "y axis").attr("transform", "translate(0,0)").call(y_axis);
var legend = svg.selectAll(".legend")
.data(color.domain().slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + Math.abs((i - 8) * 20) + ")";
});
legend.append("rect")
.attr("x", width + 10)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width + 32)
.attr("y", 10)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d, i) {
return xData[i];
});
svg {
font: 10px sans-serif;
shape-rendering: crispEdges;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
}
path.domain {
stroke: none;
}
.y .tick line {
stroke: #ddd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="ashu" style="width: 700px; height:400px;"></div>
I am having a hard time in finding the points in between the given X scale domain.
For eg. I have a bar chart having its X axis values as
[Bob,Robin,Anne,Mark,Joe,Eve,Karen,Kirsty,Chris,Lisa,Tom,Stacy,Charles,Mary]
The above values are used to plot the x-axis.I have used scaleBand method since the values are discrete.
var x = d3.scaleBand()
.range([0, width])
.padding(0.1);
x.domain(data.map(function(d) { return d.salesperson; }));
My Aim is to find points in between x scale from the given points,i.e
Is there any way that we can locate a point between Bob,Robinor Robin,Anne, So that it would be possible for me to plot a point provided a Y axis value is given.
I have added a plunker which illustrates bar chart having the mentioned x-axis.I need to plot a point on the chart having X value point between Bob,Robin
and Y value as 30(any value on Y axis)
Provided that Robin is the discrete value just after Bob, you can use a combination of bandwidth() and step():
x("Bob") + x.bandwidth() + (x.step()-x.bandwidth()) / 2
Ugly, but it works. Talking about ugliness, if you want an uglier math, you can also use a combination of step() and paddingInner():
x("Bob") + x.step() * (1 - x.paddingInner() / 2))
Here is a demo, I put the point at y(10) so you can better see that it will be right between the "Bob" and "Robin" bars:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleBand()
.range([0, width])
.padding(0.1);
var y = d3.scaleLinear()
.range([height, 0]);
// append the svg object to the body of the page
// append a 'group' element to 'svg'
// moves the 'group' element to the top left margin
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 + ")");
var data = [
{
"salesperson": "Bob",
"sales": 33
},
{
"salesperson": "Robin",
"sales": 12
},
{
"salesperson": "Anne",
"sales": 41
},
{
"salesperson": "Mark",
"sales": 16
},
{
"salesperson": "Joe",
"sales": 59
},
{
"salesperson": "Eve",
"sales": 38
},
{
"salesperson": "Karen",
"sales": 21
},
{
"salesperson": "Kirsty",
"sales": 25
},
{
"salesperson": "Chris",
"sales": 30
},
{
"salesperson": "Lisa",
"sales": 47
},
{
"salesperson": "Tom",
"sales": 5
},
{
"salesperson": "Stacy",
"sales": 20
},
{
"salesperson": "Charles",
"sales": 13
},
{
"salesperson": "Mary",
"sales": 29
}
];
// format the data
data.forEach(function(d) {
d.sales = +d.sales;
});
// Scale the range of the data in the domains
x.domain(data.map(function(d) { return d.salesperson; }));
y.domain([0, d3.max(data, function(d) { return d.sales; })]);
// append the rectangles for the bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.salesperson); })
.attr("width", x.bandwidth())
.attr("y", function(d) { return y(d.sales); })
.attr("height", function(d) { return height - y(d.sales); });
// add the x Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// add the y Axis
svg.append("g")
.call(d3.axisLeft(y));
var pointBetween = svg.append("circle")
.attr("r", 2)
.attr("cy", y(10))
.attr("cx", x("Bob") + x.bandwidth() + (x.step()-x.bandwidth())/2)
.bar { fill: steelblue; }
<script src="//d3js.org/d3.v4.min.js"></script>
I'm using the function d3.svg.symbol() to plot symbols on my Line Chart.
I wrote this code but nothing happens.
The part to generate the symbols is:
svg.selectAll("path")
.data(donnees)
.enter().append("path")
.attr("transform", function(d) { return "translate(" + xScale(d.xValue) + "," + yScale(d.yValue) + ")"; })
.attr("d", d3.svg.symbol());
First, lets talk about your data. You have an object with a key and a value structure. You've given d3 something it can work with by iterating your object like:
for (var i in donnees) {
svg.append("path")
...
While this works, we can do better. Say we try:
var data = d3.entries(donnees);
which returns:
[Object ,Object ,Object]
key: "Cbio" key: "Cres"
value: Array[10] value: Array[10]
Now we are talking about some data d3 will really like. So with that lets rewrite your line drawing.
First, create a group for each line:
var lineGroup = svg.selectAll(".line")
.data(data)
.enter()
.append("g")
.attr("class", "line");
Now, all the line path:
lineGroup
.append("path")
.attr("d", function(d){
return line(d.value);
})
.attr("fill", "none")
.attr("stroke", function(d,i){
return colors(i);
})
.attr("stroke-width", 1);
And finally, lets do some symbols:
var types = ["circle","cross","diamond"];
lineGroup
.selectAll("symbol")
.data(function(d){
return d.value; //<-- this is a subselection, and allows you to build a symbol for each datapoint of your line
})
.enter()
.append("path")
.attr("transform", function(d) {
return "translate(" + xScale(d.xValue) + "," + yScale(d.yValue) + ")";
})
.attr("d", function(d,i,j){ //<-- the j here is the parent selection, each lineGroup
return d3.svg.symbol()
.type(types[j])(d); //<-- fancy up our symbols
})
.attr("fill", function(d,i,j){
return colors(j);
});
Full code:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<style>
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
</style>
</head>
<body>
<script>
var w = 500,
h = 400,
padding = 30;
var donnees = {
"Cbio": [{
"xValue": 1,
"yValue": 21
}, {
"xValue": 20,
"yValue": 150
}, {
"xValue": 40,
"yValue": 200
}, {
"xValue": 60,
"yValue": 150
}, {
"xValue": 80,
"yValue": 125
}, {
"xValue": 100,
"yValue": 100
}, {
"xValue": 120,
"yValue": 90
}, {
"xValue": 140,
"yValue": 80
}, {
"xValue": 160,
"yValue": 80
}, {
"xValue": 180,
"yValue": 40
}],
"Cres": [{
"xValue": 1,
"yValue": 350
}, {
"xValue": 20,
"yValue": 30
}, {
"xValue": 40,
"yValue": 20
}, {
"xValue": 60,
"yValue": 30
}, {
"xValue": 80,
"yValue": 30
}, {
"xValue": 100,
"yValue": 30
}, {
"xValue": 120,
"yValue": 20
}, {
"xValue": 140,
"yValue": 30
}, {
"xValue": 160,
"yValue": 30
}, {
"xValue": 180,
"yValue": 30
}],
"tsol84": [{
"xValue": 1,
"yValue": 10
}, {
"xValue": 20,
"yValue": 15
}, {
"xValue": 40,
"yValue": 20
}, {
"xValue": 60,
"yValue": 25
}, {
"xValue": 80,
"yValue": 30
}, {
"xValue": 100,
"yValue": 25
}, {
"xValue": 120,
"yValue": 25
}, {
"xValue": 140,
"yValue": 25
}, {
"xValue": 160,
"yValue": 30
}, {
"xValue": 180,
"yValue": 25
}]
};
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var data = d3.entries(donnees);
var xScale = d3.scale.linear()
.domain([0,
d3.max(d3.max(data, function(d) {
return d.value;
}), function(d){
return d.xValue;
})
])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([0, d3.max(d3.max(data, function(d) {
return d.value;
}), function(d){
return d.yValue;
})
])
.range([h - padding, padding]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom');
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left');
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
var line = d3.svg.line()
.x(function(d) {
return xScale(d.xValue)
})
.y(function(d) {
return yScale(d.yValue)
});
var colors = d3.scale.category20();
var lineGroup = svg.selectAll(".line")
.data(data)
.enter()
.append("g")
.attr("class", "line");
lineGroup
.append("path")
.attr("d", function(d){
return line(d.value);
})
.attr("fill", "none")
.attr("stroke", function(d,i){
return colors(i);
})
.attr("stroke-width", 1);
var types = ["circle","cross","diamond"];
lineGroup
.selectAll("symbol")
.data(function(d){
return d.value;
})
.enter()
.append("path")
.attr("transform", function(d) {
return "translate(" + xScale(d.xValue) + "," + yScale(d.yValue) + ")";
})
.attr("d", function(d,i,j){
return d3.svg.symbol()
.type(types[j])(d);
})
.attr("fill", function(d,i,j){
return colors(j);
});
</script>
</body>
</html>
I want to create a Stacked bar chart like http://bl.ocks.org/mbostock/3886208 . But I don't want to use CSV file.
How can I create Stacked chart using array or JSON data?
In csv we are using like this :
State,Post,Comment
AL,310504,552339
AK,52083,85640
How can I define data in array or json like
var data = []
do it like this
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
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 + ")");
var data = [
{
"State": "AL",
"Under 5 Years": 10,
"5 to 13 Years": 20,
"14 to 17 Years": 30,
"18 to 24 Years": 40,
"25 to 44 Years": 50,
"45 to 64 Years": 60,
"65 Years and Over": 70
},{
"State": "AK",
"Under 5 Years": 15,
"5 to 13 Years": 25,
"14 to 17 Years": 35,
"18 to 24 Years": 45,
"25 to 44 Years": 55,
"45 to 64 Years": 65,
"65 Years and Over": 75
}];
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "State"; }));
data.forEach(function(d) {
var y0 = 0;
d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.ages[d.ages.length - 1].y1;
});
data.sort(function(a, b) { return b.total - a.total; });
x.domain(data.map(function(d) { return d.State; }));
y.domain([0, d3.max(data, function(d) { return d.total; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Population");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.State) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(color.domain().slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
</script>
I know late for replying to this one. I modified #heshjse's code for D3 version 4. When I tried the above code with d3 v3, it's working fine. But we had limitation to use version 4, I was getting problem bcoz of some changes in d3 v4. So adding the code which worked for me. I hope it helps.
This should work fine for Json format in d3 v4.
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<div id="Dash"></div>
</body>
</html>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
drawStackChart();
});
//Draw Stack Chart
var marginStackChart = { top: 20, right: 20, bottom: 30, left: 40 },
widthStackChart = 500 - marginStackChart.left - marginStackChart.right,
heightStackChart = 300 - marginStackChart.top - marginStackChart.bottom;
var xStackChart = d3.scaleBand()
.range([0, widthStackChart])
.padding(0.1);
var yStackChart = d3.scaleLinear()
.range([heightStackChart, 0]);
var colorStackChart = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"])
var canvasStackChart = d3.select("#Dash").append("svg")
.attr("width", widthStackChart + marginStackChart.left + marginStackChart.right)
.attr("height", heightStackChart + marginStackChart.top + marginStackChart.bottom)
.append("g")
.attr("transform", "translate(" + marginStackChart.left + "," + marginStackChart.top + ")");
function drawStackChart() {
var data = [
{
"Year": "2012",
"Category1": "20",
"Category2": "5",
"Category3": "5",
"Category4": "5",
"Category5": "5",
"Category6": "5",
"Category7": "5",
"Category8": "5",
"Category9": "5"
},
{
"Year": "2013",
"Category1": "30",
"Category2": "10",
"Category3": "10",
"Category4": "10",
"Category5": "10",
"Category6": "10",
"Category7": "10",
"Category8": "10",
"Category9": "10"
},
{
"Year": "2014",
"Category1": "35",
"Category2": "15",
"Category3": "15",
"Category4": "15",
"Category5": "15",
"Category6": "15",
"Category7": "15",
"Category8": "15",
"Category9": "15"
},
{
"Year": "2015",
"Category1": "60",
"Category2": "20",
"Category3": "20",
"Category4": "20",
"Category5": "20",
"Category6": "20",
"Category7": "20",
"Category8": "20",
"Category9": "20"
},
{
"Year": "2016",
"Category1": "70",
"Category2": "40",
"Category3": "40",
"Category4": "40",
"Category5": "40",
"Category6": "40",
"Category7": "40",
"Category8": "40",
"Category9": "40"
}
];
colorStackChart.domain(d3.keys(data[0]).filter(function (key) { return key !== "Year"; }));
data.forEach(function (d) {
var y0 = 0;
d.ages = colorStackChart.domain().map(function (name) { return { name: name, y0: y0, y1: y0 += +d[name] }; });
d.total = d.ages[d.ages.length - 1].y1;
});
data.sort(function (a, b) { return b.total - a.total; });
xStackChart.domain(data.map(function (d) { return d.Year; }));
yStackChart.domain([0, d3.max(data, function (d) { return d.total; })]);
canvasStackChart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + heightStackChart + ")")
.call(d3.axisBottom(xStackChart));
canvasStackChart.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yStackChart))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("No Of Buildings");
var state = canvasStackChart.selectAll(".Year")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function (d) { return "translate(" + xStackChart(d.Year) + ",0)"; });
state.selectAll("rect")
.data(function (d) { return d.ages; })
.enter().append("rect")
.attr("width", xStackChart.bandwidth())
.attr("y", function (d) { return yStackChart(d.y1); })
.attr("height", function (d) { return yStackChart(d.y0) - yStackChart(d.y1); })
.style("fill", function (d) { return colorStackChart(d.name); });
var legend = canvasStackChart.selectAll(".legend")
.data(colorStackChart.domain().slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", widthStackChart - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", colorStackChart);
legend.append("text")
.attr("x", widthStackChart - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function (d) { return d; });
}
</script>
If you have an array, data, you can use that just like the parameter data in the csv function in the example you linked. The code within that function will work as expected, provided that your data is in the same format.
If you can set breakpoints with your browser, you can have a look at what that format is fairly easily, set one just inside the csv function call in the js and look at the data variable.
I have been trying to get the data labels to appear on the bars of the d3 chart I have built. No joy. I have tried svg.selectAll("text")... but no error and no labels.
I have created a codePen Example
function arbByMonthDashboard2(targetDiv, monthToReport) {
var color_hash = { 1 : ["January", "green"],
2 : ["February", "orange"],
3 : ["March", "aquamarine"],
4 : ["April", "blue"],
5 : ["May", "yellow"],
6 : ["June", "silver"],
7 : ["July", "antiquewhite"],
8 : ["August", "cyan"],
9 : ["September", "blueviolet"],
10 : ["October", "black"],
11 : ["November", "cadetblue"],
12 : ["December", "red"]
}
var chartData = { "data": [
{ MonthNum: 4, Month: '4-2014', ARBs: 4 },
{ MonthNum: 5, Month: '5-2014', ARBs: 4 },
{ MonthNum: 6, Month: '6-2014', ARBs: 4 },
{ MonthNum: 7, Month: '7-2014', ARBs: 5 },
{ MonthNum: 8, Month: '8-2014', ARBs: 4 },
{ MonthNum: 9, Month: '9-2014', ARBs: 8 },
{ MonthNum: 10, Month: '10-2014', ARBs: 12 },
{ MonthNum: 11, Month: '11-2014', ARBs: 6 },
{ MonthNum: 12, Month: '12-2014', ARBs: 16 },
{ MonthNum: 1, Month: '1-2015', ARBs: 6 },
{ MonthNum: 2, Month: '2-2015', ARBs: 10 },
{ MonthNum: 3, Month: '3-2015', ARBs: 10 },
{ MonthNum: 4, Month: '4-2015', ARBs: 13 },
{ MonthNum: 5, Month: '5-2015', ARBs: 13 }
]};
var width = 400;
var height = 900;
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%m-%Y").parse;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format("%m-%Y"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
var svg = d3.select("#divChart").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 + ")");
chartData.data.forEach(function(d) {
d.Month = parseDate(d.Month);
d.ARBs = +d.ARBs;
}
);
x.domain(chartData.data.map(function(d) { return d.Month; }));
y.domain([0, d3.max(chartData.data, function(d) { return d.ARBs;})]);
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")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Total ARBs");
svg.selectAll("bar")
.data(chartData.data)
.enter().append("rect")
.style("fill", function(d) {
var color = color_hash[d.MonthNum][1];
return color;
})
.attr("class", "bar")
.attr("x", function(d) { return x(d.Month); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.ARBs); })
.attr("height", function(d) { return height - y(d.ARBs); });
};
I'm not sure to understand what you ask, sorry.
You can add text on bar by creating a new selection on your data :
svg.selectAll("text.legend")
.data(chartData.data)
.enter().append("text")
.attr("class", "legend")
.attr("x", function(d) { return x(d.Month) + x.rangeBand() / 2 ; })
.text(function(d){return d.ARBs})
.attr('y', height - 10);
You have a codepen here: http://codepen.io/anon/pen/EjKwjL
Hope it helps,
Regards