Labels on a D3 line chart not working - javascript

I want to have "tooltips" on my line chart permanently (in, other words, I want labels). Code I have written for this is below, but it doesn't even show any such tooltip/label on my chart. What would be the problem?
<!DOCTYPE html>
<style>
body {
font: 15px sans-serif;
}
.axis line, .axis path {
fill: none;
stroke: gray;
stroke-width:4;
shape-rendering: crispEdges;
}
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 3px;
}
</style>
<html>
<body>
<script type="text/javascript" src="d3.v3.min.js"></script>
<script type="text/javascript">
var data = [
{time:0,ftRem1:100,ftRem2:100,ftRem3:100},{time:4,ftRem1:95.7,ftRem2:89.4,ftRem3:88.9},
{time:4.5,ftRem1:94.9,ftRem2:87.3,ftRem3:86.7},{time:8.5,ftRem1:93.8,ftRem2:84.3,ftRem3:83.2},
{time:32.5,ftRem1:91.2,ftRem2:76.8,ftRem3:73.7},{time:56.5,ftRem1:87.8,ftRem2:67.1,ftRem3:61.7},
{time:58.5,ftRem1:87.5,ftRem2:66.4,ftRem3:60.8},{time:82.5,ftRem1:83.7,ftRem2:55.7,ftRem3:47.6},
{time:94.5,ftRem1:82.3,ftRem2:51.5,ftRem3:42.4}
];
var margin = {top: 20,left: 30, bottom: 30,right: 40},
height = 500 - margin.top - margin.bottom,
width = 900 - margin.left - margin.right;
var color = d3.scale.category10();
var x = d3.scale.linear()
.range([0,width]);
var y = d3.scale.linear()
.range([height,0]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var chart = 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 line = d3.svg.line()
.x(function(d){return x(d.hours);})
.y(function(d){return y(d.ftRem);})
.interpolate("linear");
color.domain(d3.keys(data[0]).filter(function(d){ return d!='time' }));
var points = color.domain().map(function(duration){
return {
ftPoints:duration,
values: data.map(function(d){
return{hours: d.time,ftRem: d[duration]};
})
}
});
x.domain([0,d3.max(data,function(d){return d.time})]);
y.domain([
0,
d3.max(points,function(c){ return d3.max(c.values,function(d){ return d.ftRem;});})
]);
chart.append("g")
.attr("class","x axis")
.attr("transform","translate(0,"+height+")")
.call(xAxis);
chart.append("g")
.attr("class","y axis")
.call(yAxis);
var freshTime=chart.selectAll(".ftpoint")
.data(points)
.enter().append("g")
.attr("class","ftpoint");
freshTime.append("path")
.attr("class","line")
.attr("d",function(d,i){return line(d.values);})
var lineColor = ["#1abc9c","#3498db","#e74c3c"];
freshTime.select(".line")
.style("stroke",function(d,i){return lineColor[i];})
Step = ["","a","b","c","d","e","f","g","h"];
var tooltip = chart.selectAll(".tooltip")
.data(points[0].values)
.enter()
.append("div")
.attr("class","tooltip")
.style("left", function (d) { return y(d.hours)+"px";})
.style("top", function (d) { return x(d.ftRem)+"px";})
.text(function(d,i) { return Step[i]; });
</script>
</body>
</html>

You would be better off if you use just svg elements within your chart. Its just not practical to mix and match svg and divs. So, you can just use svg element text for labels (you created class "tooltip" for the purpose of labels, maybe you should change the name of the class, since you actually want labels, not tooltips):
var tooltip = chart.selectAll(".tooltip")
.data(points[0].values)
.enter()
.append("text")
.attr("class","tooltip")
.attr("y", function (d) { return y(d.hours)+"px";})
.attr("x", function (d) { return x(d.ftRem)+"px";})
.text(function(d,i) { return Step[i]; });
(note: if you make this change, labels will appear, but I guess their positions are not Ok, but thats problem of different kind that you must solve)

Related

Convert vertical stacked bar to horizontal stacked bar D3.js v4

I found a vertical stack bar graph sample on google - http://bl.ocks.org/juan-cb/43f10523858abf6053ae
I want to convert it in horizontal stacked bar graph. I have done the changes but something is wrong. Graph is not correct.I think all the bars are overlapped.
Please help me to resolve this. Code is copied.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
position: center;
}
text{
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
.legend {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 60%;
}
text {
font: 10px sans-serif;
}
.axis text {
font: 10px sans-serif;
}
.axis path{
fill: none;
stroke: #000;
}
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
</style>
<body>
<div class="barGraph" id='stacked-bar'></div>
<script src="http://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.7.0/d3-legend.min.js"></script>
<script>
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
init();
function init(){
var dataset = [{
"goodRating": 27,
"avgRating": 21,
"badRating": 16,
"rooms": "0.01"
},
{
"goodRating": 26,
"avgRating": 22,
"badRating": 31,
"rooms": "0.02"
},
{
"goodRating": 100,
"avgRating": 0,
"badRating": 0,
"rooms": "1"
}];
var groupSpacing = 6;
var margin = {top: 10, right: 10, bottom: 60, left: 100},
width = 1000 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var y = d3.scaleBand()
.range([height, 0]);
var x = d3.scaleLinear()
.range([0, width], .1,.3);
// var colorRange = d3.scale.category20();
var color = d3.scaleOrdinal(d3.schemeCategory20);
var xAxis = d3.axisBottom(x).tickFormat(dataset.rooms),
yAxis = d3.axisLeft(y);
var svg = d3.select("#stacked-bar").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 divTooltip = d3.select("body").append("div").attr("class", "toolTip");
color.domain(d3.keys(dataset[0]).filter(function(key) { return key !== "rooms"; }));
dataset.forEach(function(d) {
var y0 = 0;
var y1 = 0;
d.values = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.values[d.values.length - 1].y1;
});
y.domain(dataset.map(function(d) { return d.rooms; }));
x.domain([0, d3.max(dataset, function(d) { return d.total; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".5em")
.attr("transform", "rotate(-65)");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 9)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Satisfaction %");
var bar = svg.selectAll(".rooms")
.data(dataset)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + y(d.rooms) + ",0)"; });
svg.selectAll(".x.axis .tick text")
.call(wrap, y.bandwidth());
var bar_enter = bar.selectAll("rect")
.data(function(d) { return d.values; })
.enter();
bar_enter.append("rect")
.attr("height", y.bandwidth())
.attr("x", function(d) { return x(d.y1); })
.attr("width", function(d) { return x(d.y1) - x(d.y0) })
.style("fill", function(d) { return color(d.name); });
bar_enter.append("text")
.text(function(d) { return d3.format(".2s")(d.y1-d.y0)+"%"; })
.attr("x", function(d) { return x(d.y1)+(x(d.y0) - x(d.y1))/2; })
.attr("y", y.bandwidth()/3)
.style("fill", '#ffffff');
bar.on("mousemove", function(d){
divTooltip.style("left", d3.event.pageX+10+"px");
divTooltip.style("top", d3.event.pageY-25+"px");
divTooltip.style("display", "inline-block");
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l-1
element = elements[l].__data__
value = element.y1 - element.y0
divTooltip.html("Room No : "+(d.rooms)+"<br>"+element.name+" : "+value+"%");
});
bar.on("mouseout", function(d){
divTooltip.style("display", "none");
});
}
</script>
</body>
Regards,
Pinki Sharma
A few minor things were missing/incorrect:
The group (<g>) containing the bars was being transformed incorrectly (I'm guessing you missed this while changing from vertical stacked to horizontal) i.e. the following line
.attr("transform", function(d) { return "translate(" + y(d.rooms) + ",0)"; });
translates the bar groups from the left and the y position would be 0 and hence the overlap. I've changed that to this:
.attr("transform", function(d) { return "translate(0, " + y(d.rooms) + ")"; });
The rects' x value is changed from x(d.y1) to x(d.y0) (might be a typo)
bar_enter.append("rect")
.attr("height", y.bandwidth())
.attr("x", function(d) { return x(d.y0); })
Axis padding was missing for the scaleBand(). I've added that (check docs for more info)
var y = d3.scaleBand()
.rangeRound([height, 0]).padding(0.1);
Reset the margins to adapt to the SVG dimensions:
var margin = {top: 10, right: 60, bottom: 60, left: 50},
Combining all of the above, here's a fork of your codepen:
HORIZONTAL STACKED BAR CHART DEMO
Hope this helps.

Running code accurately on a local server but when i run this in a browser directly without server its not showing display

i am making a bar graph
code is working fine when I run this code on a local server but when I run this code directly in a browser without local server then the output is nothing
how can i solve the problem
i want to run this code directly in a browser without server
Bar graph
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Bar Graph</title>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: relative;
width: 960px;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #fa8787;
shape-rendering: crispEdges;
}
.bar {
fill: blue;
fill-opacity: 15;
}
.x.axis path {
display: none;
}
label {
position: absolute;
top: 10px;
right: 10px;
}
</style>
</head>
<body>
<label><input type="checkbox"> Sort values</label>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/topojson/1.1.0/topojson.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
<script type="text/javascript">
var barMargin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - barMargin.left - barMargin.right,
height = 500 - barMargin.top - barMargin.bottom;
var formatPercent = d3.format("0");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1, .1);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(formatPercent);
var svg = d3.select("body").append("svg")
.attr("width", width + barMargin.left + barMargin.right)
.attr("height", height + barMargin.top + barMargin.bottom)
.append("g")
.attr("transform", "translate(" + barMargin.left + "," + barMargin.top + ")");
d3.csv("http://www.cis.umassd.edu/~dkoop/cis468-2017sp/a4/occupations.csv", function (error, data) {
data.forEach(function(d) {
d.jobs_1000 = +d.jobs_1000;
});
x.domain(data.map(function(d) { return d.area_title; }));
y.domain([0, d3.max(data, function(d) { return d.jobs_1000; })]);
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", "translate(-30," + (height / 2) + ") rotate(-90)")
.attr("y", 2)
.style("text-anchor", "end")
.text("jobs Per 1000");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.area_title); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.jobs_1000); })
.attr("height", function(d) { return height - y(d.jobs_1000); });
d3.select("input").on("updateBars", updateBars);
var sortTimeout = setTimeout(function() {
d3.select("input").property("checked", true).each(updateBars);
}, 2000);
function updateBars() {
clearTimeout(sortTimeout);
// Copy-on-write since tweens are evaluated after a delay.
var x0 = x.domain(data.sort(this.checked
? function(a, b) { return b.jobs_1000 - a.jobs_1000; }
: function(a, b) { return d3.ascending(a.area_title, b.area_title); })
.map(function(d) { return d.area_title; }))
.copy();
svg.selectAll(".bar")
.sort(function(a, b) { return x0(a.area_title) - x0(b.area_title); });
var transition = svg.transition().duration(750),
delay = function(d, i) { return i * 50; };
transition.selectAll(".bar")
.delay(delay)
.attr("x", function(d) { return x0(d.area_title); });
transition.select(".x.axis")
.call(xAxis)
.selectAll("g")
.delay(delay);
}
});
</script>
</body>
</html>

How to append text to d3js dispatch chart

I've got this d3js v3 chart and was wondering if it's possible to append the values in a text format to both the bar and the donut chart, and if so, how you would go about doing it?
Here is the code:
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
<style>
body {
font-family:arial;
font-size:10px;
margin:auto;
width:1100px;
}
.axis text {
font: 10px sans-serif;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
select {
background-color: #fff;
border: 1px solid #fff;
border-bottom: 1px solid #ccc;
color: #000;
padding: 3px 3px;
text-align: center;
text-decoration: none;
font-size: 10px;
margin: 2px 2px;
cursor: pointer;
}
select:focus {outline:0;}
.Row
{
display: table;
width: 100%;
table-layout: fixed;
}
.Column
{
display: table-cell;
position:relative;
}
</style>
</head>
<body>
<div class="Row">
<div class="Column" id="chart"></div>
</div>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var dispatch = d3.dispatch("load", "statechange");
var groups = [
"Team 1",
"Team 2",
"Team 3"
];
d3.csv("data.csv", type, function(error, states) {
if (error) throw error;
var stateById = d3.map();
states.forEach(function(d) { stateById.set(d.id, d); });
dispatch.load(stateById);
dispatch.statechange(stateById.get("CA"));
});
// A drop-down menu for selecting a state; uses the "menu" namespace.
dispatch.on("load.menu", function(stateById) {
var select = d3.select("#chart")
.append("div")
.append("select")
.on("change", function() { dispatch.statechange(stateById.get(this.value)); });
select.selectAll("option")
.data(stateById.values())
.enter().append("option")
.attr("value", function(d) { return d.id; })
.text(function(d) { return d.id; });
dispatch.on("statechange.menu", function(state) {
select.property("value", state.id);
});
});
// A bar chart to show total population; uses the "bar" namespace.
dispatch.on("load.bar", function(stateById) {
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 80 - margin.left - margin.right,
height = 290 - margin.top - margin.bottom;
var y = d3.scale.linear()
.domain([0, d3.max(stateById.values(), function(d) { return d.total; })])
.rangeRound([height, 0])
.nice();
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var rect = svg.append("rect")
.attr("x", 4)
.attr("width", width - 4)
.attr("y", height)
.attr("height", 0)
.style("fill", "#aaa");
dispatch.on("statechange.bar", function(d) {
rect.transition()
.attr("y", y(d.total))
.attr("height", y(0) - y(d.total));
});
});
// A pie chart to show population by age group; uses the "pie" namespace.
dispatch.on("load.pie", function(stateById) {
var width = 260,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.domain(groups)
.range(["steelblue", "lightblue", "darkorange"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 60);
var pie = d3.layout.pie()
.sort(null);
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(groups)
.enter().append("path")
.style("fill", color)
.each(function() { this._current = {startAngle: 0, endAngle: 0}; });
dispatch.on("statechange.pie", function(d) {
path.data(pie.value(function(g) { return d[g]; })(groups)).transition()
.attrTween("d", function(d) {
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
});
});
// Coerce population counts to numbers and compute total per state.
function type(d) {
d.total = d3.sum(groups, function(k) { return d[k] = +d[k]; });
return d;
}
</script>
</body>
</html>
And here's the dataset:
id,Team 1,Team 2,Team 3
AL,3105,5523,2590
AK,5208,8564,4215
AZ,5159,8286,3626
AR,2020,3432,1572
CA,2704,4499,2159
CO,3582,5871,2617
CT,2116,4036,1969
DE,5931,9949,4741
DC,3635,5043,2522
FL,1140,1938,9250
GA,7405,1250,5578
HI,8720,1340,6401
You have to create the label :
var label = svg.append("text")
.attr("x", 4)
.attr("y", height)
.attr("dy", ".35em")
.text(function(d) { return "0"; });
Then add a transition on this new text
label.transition()
.attr("y", y(d.total) + 5)
.text(d.total);
See https://plnkr.co/edit/wtq96BAZ3Zh1SaczjLT6?p=preview

d3 x axis custom values

Is it possible to force my x-axis to display ticks as below ?
3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,1,2
As you see from the jsfiddle example below, my line chart jumps back to the begining because my line values go as follow: 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,1,2...so basically when it comes to the highest value (24) it jumps back to the begining and it finishes the last 2 values there...we do not want that, we want the line to continue from 24 to 1 and 2..all in one line.
Please check my jsfiddle example below.
http://jsfiddle.net/a6psrawt/
Hmm, I can't figure out how to get the ordinal scale to play nice so here's my attempt with a fudged linear scale.
Changes in the code:
// max of the data, find this dynamically if needed
var maxValue = 24;
// which points are skipping up front
var wrapValue = 3;
var x = d3.scale.linear()
// adjust domain
.domain([wrapValue, maxValue + wrapValue])
.range([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.ticks(maxValue)
.tickFormat(function(d){
if (d > maxValue){
return d - maxValue; // fix axis value
} else {
return d;
}
})
.orient("bottom");
var line = d3.svg.line()
.x(function(d,i) {
if (d[0] < wrapValue) {
return x(d[0] + maxValue); // fix data value
} else {
return x(d[0]);
}
})
.y(function(d, i) {return y(d[1]);});
Updated fiddle.
Full code:
var data =
[{"name":"Zu Hause","data":[[3,95.2],[3.15,95.2],[3.3,95.2],[3.45,95.3],[4,95.4],[4.15,95.2],[4.3,95],[4.45,94.7],[5,94.1],[5.15,93.7],[5.3,92.6],[5.45,91.9],[6,90.4],[6.15,89],[6.3,86.2],[6.45,83.7],[7,77.4],[7.15,74.5],[7.3,69.7],[7.45,66.6],[8,62.2],[8.15,60.2],[8.3,57.2],[8.45,55.6],[9,51.4],[9.15,50.5],[9.3,47.7],[9.45,47.1],[10,44.6],[10.15,44.3],[10.3,43.9],[10.45,44.1],[11,43.4],[11.15,44],[11.3,44.8],[11.45,45.7],[12,47.5],[12.15,49.4],[12.3,50.3],[12.45,50.3],[13,49.1],[13.15,49],[13.3,48.2],[13.45,47.9],[14,45.1],[14.15,45.4],[14.3,45.5],[14.45,45.9],[15,44.7],[15.15,45.4],[15.3,46.1],[15.45,46.7],[16,46.8],[16.15,48],[16.3,49.8],[16.45,51.4],[17,53.5],[17.15,55.8],[17.3,58.5],[17.45,60.2],[18,61.8],[18.15,64.6],[18.3,66.5],[18.45,68.1],[19,71.4],[19.15,72.2],[19.3,73.9],[19.45,74.7],[20,76],[20.15,77.8],[20.3,79.4],[20.45,80.8],[21,81.6],[21.15,82.7],[21.3,83.8],[21.45,85],[22,86.5],[22.15,87.6],[22.3,89.2],[22.45,90.2],[23,91.7],[23.15,92.3],[23.3,92.8],[23.45,93.4],[0,93.9],[0.15,94.3],[0.3,94.7],[0.45,95],[1,95.5],[1.15,95.6],[1.3,95.9],[1.45,96.1],[2,96.4],[2.15,96.6],[2.3,96.7],[2.45,96.9]]},{"name":"Unterwegs","data":[[3,0.7],[3.15,0.7],[3.3,0.9],[3.45,0.7],[4,0.6],[4.15,0.8],[4.3,0.9],[4.45,1.2],[5,1.2],[5.15,1.5],[5.3,2.1],[5.45,2.2],[6,3],[6.15,3.9],[6.3,5.8],[6.45,6.8],[7,8.9],[7.15,9.9],[7.3,10.6],[7.45,10.3],[8,9.3],[8.15,9.4],[8.3,10.1],[8.45,9.6],[9,11.1],[9.15,10.2],[9.3,11.4],[9.45,10.6],[10,12],[10.15,11.7],[10.3,11.5],[10.45,11.4],[11,13.5],[11.15,12.4],[11.3,11.8],[11.45,11.9],[12,12.4],[12.15,11.4],[12.3,11.3],[12.45,10.9],[13,12.8],[13.15,12.3],[13.3,13],[13.45,12.8],[14,15.2],[14.15,14.1],[14.3,13.6],[14.45,13.1],[15,17.3],[15.15,15.6],[15.3,14.8],[15.45,14.6],[16,17.2],[16.15,15.7],[16.3,16.4],[16.45,15.6],[17,17.2],[17.15,15.4],[17.3,14.3],[17.45,13.2],[18,15.3],[18.15,12.2],[18.3,11.6],[18.45,10.3],[19,10.3],[19.15,8.7],[19.3,7.2],[19.45,6.9],[20,6.6],[20.15,5.5],[20.3,5.1],[20.45,4.1],[21,4.5],[21.15,4],[21.3,3.8],[21.45,3.2],[22,3.7],[22.15,3.3],[22.3,2.9],[22.45,2.4],[23,2.3],[23.15,1.7],[23.3,1.5],[23.45,1.4],[0,1.3],[0.15,1],[0.3,1.2],[0.45,1],[1,0.9],[1.15,0.8],[1.3,0.8],[1.45,0.7],[2,0.7],[2.15,0.6],[2.3,0.6],[2.45,0.5]]}];
var width = 560;
var height = 300;
var legendRectSize = 18;
var legendSpacing = 4;
var margin = {top: 50, right: 80, bottom: 30, left: 50}
var color = d3.scale.category20();
//Create SVG container
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top);
var maxValue = 24;
var wrapValue = 3;
var ticks = [0,25,50,75,100];
//X and Y Scales
var x = d3.scale.linear()
.domain([wrapValue, maxValue + wrapValue])
.range([0, width]);
var y = d3.scale.linear()
.domain([0,100])
.range([height, 0]);
//X and Y Axis init
var xAxis = d3.svg.axis()
.scale(x)
.ticks(24)
.tickFormat(function(d){
if (d > maxValue){
return d - maxValue;
} else {
return d;
}
})
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.tickValues(ticks)
.tickFormat(function(d) { return d+'%'; })
.orient("bottom");
var xAxisGroup = svg.append("g")
.call(xAxis)
.attr("class", "x axis")
.attr("transform", "translate("+margin.left+"," + (height + 20) + ")");
var yAxisGroup = svg.append("g")
.call(yAxis)
.attr("class", "y axis")
.attr("transform", "translate(" + margin.left + "," + 20 + ") rotate(90)")
.selectAll("text")
.attr("transform", function(d) {return "translate(-15,25) rotate(-90)"});
//Create a path container
var line = d3.svg.line()
.x(function(d,i) {
if (d[0] < wrapValue) {
return x(d[0] + maxValue);
} else {
return x(d[0]);
}
})
.y(function(d, i) {return y(d[1]);});
var g = svg.append("g")
.attr('class','series-container')
.attr("transform", "translate(" + margin.left + "," + 20 + ")");
var path = g.selectAll("path")
.data(data).enter()
.append("g")
.attr('class','series')
.attr('id', function(d,i){ return 'pathid_'+d.name; })
.append("path")
.attr("d", function(d,i){ return line(d.data); }) //Set d for every path
.attr("fill", "none")
.attr("stroke", function(d,i) { return color(i); })
.attr("stroke-width", 3);
var path_text = g.selectAll(".series")
.append("text")
.attr("transform", function(d,i) { return "translate("+(width+20)+", "+ y(d.data[d.data.length-1][1]) +")"; }) //+d[d.length-1].y+
.attr("dy", ".35em")
.style("fill", function(d,i) { return color(i); })
.text( function(d,i) {return d.name;} )
body { font-family: 'Open Sans', sans-serif; font-size: 12px; color: #000; }
rect { stroke-width: 2; }
.chart-line { fill: none; stroke: black; stroke-width: 1px; }
.axis text { font-size: 12px; }
.axis .label { font-size: 22px; }
.axis path,
.axis line { fill: none; stroke: #000; shape-rendering: crispEdges; }
.tooltip { background: #000; color: #fff; padding: 3px; font-size: 11px; position: relative; }
.tooltip:before { content: ""; display: block; border-right: solid 3px #000; border-top: solid 3px transparent; border-bottom: solid 3px transparent; position: absolute; left: -3px; top: 50%; margin-top: -3px; }
.path-point circle,
.legend { cursor: pointer; font-size: 12px; }
.legend-container { display: none; }
.legend-title { margin: 0 0 4px }
.legend-container-jq { float: left; width: 100%; }
.legend-container-jq { list-style: none; margin: 0 0 10px 13px; padding: 0; }
.legend-container-jq li { float: left; width: 100%; margin: 3px 0; cursor: pointer; }
.legend-container-jq div { width: 15px; height: 15px; float: left; margin: 0 8px 0 0; }
.legend-container-jq span { float: left; margin: -2px 0 0 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Stacked Bar Chart with D3

I want to create stacked bar chart with d3.
I have this data in CSV file:
Type Sum Color
Regular 29756.85897 green
Regular 9756.85897 blue
and I want that each row will appear above the other in Y axis.
for example in this photo, the blue area should start in y=9756 until y=39512.
what should I change?
this is the relevant html code:
the whole code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
margin:auto;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar1 {
fill: #00FF66;
}
.bar1:hover {
fill: black ;
}
.x.axis path {
display: none;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var margin = {top: 80, right: 90, bottom: 30, left: 90},
width = 1000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
//יצירת X
//יאכלס את סוגי הרכב השונים
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
//יצירת ציר y
//יציג בר עבור מחיר הרכב המוצע לדילרים
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
//יצירת ציר הY
//והצמדתו לצד שמאל
var yAxis = d3.svg.axis()
.scale(y)
.orient("left").ticks(4)
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong></strong>"+d.Type+"<br><strong></strong> <span style='color:#00FF66'>" + d.Sum + "</span>";
})
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.call(tip);
//קליטת הטבלה והגדרת הטווחים על הצירים
d3.csv("Targil2.csv", type, function(error, data) {
x.domain(data.map(function(d) { return d.Type; }));
y.domain([0, d3.max(data, function(d) { return d.Sum*2; })]);
var stack = d3.layout.stack();
.x(function(d) { return d.Type }) // tell d3 to use Type as x value
.y(function(d) { return d.Sum }); // tell d3 to use Sum as y value
var stackData = stack(data);
//הוספה של 2 הצירים
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis axisLeft")
.attr("transform", "translate(0,0)")
.call(yAxis)
.append("text")
.attr("y", 6)
.attr("dy", "-2em")
.style("text-anchor", "end")
.style("text-anchor", "end")
.text("Price");
//הוספת בר הנתונים
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("x", function(d) { return x(d.Type); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return d.y0 })
.attr("height", function(d) { return (height - y(d.Sum)); })
.style("fill", function(d){
if(d["Color"] == "green"){ return "green";}
else return "#0066FF";})
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
});
function type(d) {
d.Sum = +d.Sum;
return d;
}
</script>
</body>
</html>
I tried to use that stack function as you told me, and changed the attribute of "y" , but it's not work for me now. I think I did something wrong.
Here you go.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
margin:auto;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar1 {
fill: #00FF66;
}
.bar1:hover {
fill: black ;
}
.x.axis path {
display: none;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var margin = {top: 80, right: 90, bottom: 30, left: 90},
width = 1000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
//יצירת X
//יאכלס את סוגי הרכב השונים
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
//יצירת ציר y
//יציג בר עבור מחיר הרכב המוצע לדילרים
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
//יצירת ציר הY
//והצמדתו לצד שמאל
var yAxis = d3.svg.axis()
.scale(y)
.orient("left").ticks(4)
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong></strong>"+d.Type+"<br><strong></strong> <span style='color:#00FF66'>" + d.Sum + "</span>";
})
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.call(tip);
//קליטת הטבלה והגדרת הטווחים על הצירים
d3.csv("Targil2.csv", type, function(error, data) {
window.dataSet = data;
data.sort(function(x,y){
var a = x.Sum;
var b = y.Sum;
return a > b ? -1 : a < b ? 1 : 0
})
x.domain(data.map(function(d) { return d.Type; }));
y.domain([0, d3.max(data, function(d) { return d.Sum*2; })]);
var stack = d3.layout.stack()
.x(function(d) { return d.Type }) // tell d3 to use Type as x value
.y(function(d) { return d.Sum }); // tell d3 to use Sum as y value
// var stackData = stack(data);
//הוספה של 2 הצירים
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis axisLeft")
.attr("transform", "translate(0,0)")
.call(yAxis)
.append("text")
.attr("y", 6)
.attr("dy", "-2em")
.style("text-anchor", "end")
.style("text-anchor", "end")
.text("Price");
var stackSoFar = 0;
//הוספת בר הנתונים
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("x", function(d) { return x(d.Type); })
.attr("width", x.rangeBand())
.attr("y", function(d){
d3.select(this)
.attr("height", function(d2){
var thisHeight = height - y(d.Sum);
stackSoFar += thisHeight
return thisHeight
});
return (height - stackSoFar)
})
.style("fill", function(d){
if(d["Color"] == "green"){ return "green";}
else return "#0066FF";})
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
});
function type(d) {
d.Sum = +d.Sum;
return d;
}
</script>
</body>
</html>
first of all, I guess that when you say
for example in this photo, the blue area should start in y=9756 until
y=39512
You actually mean
for example in this photo, the blue area should start in y=29756 until
y=39512
What happens is that your green area is painted from 0 to 29756 then your blue area on top of it from 0 to 9756. You need to shift each area on top of the previous one.
Easiest is to preprocess your data to do it.
D3.js can do it for you, see Stack Layout. This computes the y0 and y for all of your layers.
EDIT:
var stack = d3.layout.stack()
.x(function(d) { return d.Type }) // tell d3 to use Type as x value
.y(function(d) { return d.Sum }); // tell d3 to use Sum as y value
var stackData = stack(data);
After that, you data is augmented, i.e. each entry contains an additional y and y0 values that you can use directly to plot (in your y and height attribute).

Categories

Resources