D3 vertical line beetween grouped chart bars spacing - javascript

The problem:
The number of groups is dynamic, and vertical line (separator) needs dynamic padding. Group width im getting with x0.rangeBand(). Is there any way to get width of space beetween two groups dynamically?
Peace of code:
.....
var slice = svg.selectAll(".chart")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function (d) {
return "translate(" + x0(d.category) + ",0)";
});
// Create rectangles of the correct width
slice.selectAll("rect")
.data(function (d) {
return d.values;
})
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function (d) {
return x1(d.rate);
})
.style("fill", function (d) {
return color(d.rate)
})
.attr("y", function (d) {
return y(0);
})
.attr("height", function (d) {
return height - y(0);
})
.on("mouseover", function (d) {
d3.select(this).style("fill", d3.rgb(color(d.rate)).darker(2));
tip.show(d);
})
.on("mouseout", function (d) {
tip.hide
d3.select(this).style("fill", color(d.rate));
})
slice.append("line")
.attr("class", "blabla")
.attr("x1", x0.rangeBand()+20)
.attr("x2", x0.rangeBand()+20)
.attr("y1", 0)
.attr("y2", height + margin.top + margin.bottom)
.style("stroke-width", 1)
.style("stroke", "#000");
.....
This is how it looks with few groups
This is how it looks with many groups

Because I see no reason why to stick to d3v3 and I can't find the d3v3 documentation easily for ordinal scales here is a d3v5 version of the code with correct placement of the vertical bars. You have to use the bandwidth and the step to calculate the position.
It is an adaptation of the example in your other question : https://bl.ocks.org/bricedev/0d95074b6d83a77dc3ad
I doubled the number of groups and it looks nice.
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scaleBand()
.rangeRound([0, width])
.paddingInner(0.1);
var x1 = d3.scaleBand();
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
.scale(x0)
.tickSize(0);
var yAxis = d3.axisLeft()
.scale(y);
var color = d3.scaleOrdinal()
.range(["#ca0020","#f4a582","#d5d5d5","#92c5de","#0571b0"]);
var svg = d3.select('body').append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("barchart.json", {credentials: 'same-origin'}).then(function(data) {
var categoriesNames = data.map(function(d) { return d.categorie; });
var rateNames = data[0].values.map(function(d) { return d.rate; });
x0.domain(categoriesNames);
x1.domain(rateNames).range([0, x0.bandwidth()]);
y.domain([0, d3.max(data, function(categorie) { return d3.max(categorie.values, function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.style('opacity','0')
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight','bold')
.text("Value");
svg.select('.y').transition().duration(500).delay(1300).style('opacity','1');
var slice = svg.selectAll(".slice")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform",function(d) { return "translate(" + x0(d.categorie) + ",0)"; });
slice.selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("width", x1.bandwidth())
.attr("x", function(d) { return x1(d.rate); })
.style("fill", function(d) { return color(d.rate) })
.attr("y", function(d) { return y(0); })
.attr("height", function(d) { return height - y(0); })
.on("mouseover", function(d) {
d3.select(this).style("fill", d3.rgb(color(d.rate)).darker(2));
})
.on("mouseout", function(d) {
d3.select(this).style("fill", color(d.rate));
});
slice.selectAll("rect")
.transition()
.delay(function (d) {return Math.random()*1000;})
.duration(1000)
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
slice.append("line")
.attr("class", "blabla")
.attr("x1", (x0.step() - x0.bandwidth())*0.5 + x0.bandwidth())
.attr("x2", (x0.step() - x0.bandwidth())*0.5 + x0.bandwidth())
.attr("y1", 0)
.attr("y2", height + margin.top + margin.bottom)
.style("stroke-width", 1)
.style("stroke", "#000");
//Legend
var legend = svg.selectAll(".legend")
.data(data[0].values.map(function(d) { return d.rate; }).reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d,i) { return "translate(0," + i * 20 + ")"; })
.style("opacity","0");
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) { return color(d); });
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {return d; });
legend.transition().duration(500).delay(function(d,i){ return 1300 + 100 * i; }).style("opacity","1");
});

So the trick is to recalculate padding self. V3 does not have band.step() function so I added this method to get the middle of two items:
function getMiddle(x0){
var rng = x0.range();
var band = x0.rangeBand();
var padding = 0;
if(rng.length>1){
padding = (rng[1]-rng[0] - band) *0.5;
}
return band + padding;
}
And usage:
slice.append("line")
.attr("x1", getMiddle(x0))
.attr("x2", getMiddle(x0))
.attr("y1", 0)
.attr("y2", height + margin.top + margin.bottom)
.style("stroke-width", 1)
.style("stroke", "#000");

Related

d3.js lollipop chart - animated

I am working on a d3 application - which features a bar chart with nodules on the top. I am keen to get this animated - so the bars grow to the point of rest and the nodules sprout like flowers.
So the nodules are either developed at the start and the bars just rise -- or the bars rise up and then the nodules flower.
//old js fiddle
http://jsfiddle.net/s1f4hzpu/1/
//current animation attempts
http://jsfiddle.net/9yvn8c4q/
var $this = $('.lollipopchart');
var data = [{
label: 'Toblerone',
value: 10,
},
{
label: 'Snickers',
value: 25,
},
{
label: 'Jawbreakers',
value: 60,
},
{
label: 'Gummi Worms',
value: 20,
},
];
var width = $this.data('width'),
height = $this.data('height');
var color = d3.scaleOrdinal()
.range(["#eb6383", "#fa9191", "#ffe9c5", "#b4f2e1"]);
data.forEach(function(d) {
d.total = +d.value;
});
var margin = {
top: 20,
right: 20,
bottom: 85,
left: 20
},
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
var x = d3.scaleBand()
.range([0, width])
.padding(0.9);
var y = d3.scaleLinear()
.range([height, 0]);
x.domain(data.map(function(d) {
return d.label;
}));
y.domain([0, d3.max(data, function(d) {
return d.total;
})]);
var svg = d3.select($this[0])
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr('class', 'lollipopchart')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var lollipop = svg.append('g').attr('class', 'lollipop');
var bars = lollipop
.append("g")
.attr('class', 'bars')
bars.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr('fill', function(d, i) {
return color(i);
})
.attr("x", function(d) {
return x(d.label);
})
.attr("width", x.bandwidth())
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.total);
});
var lolliradian = 10;
var circles = lollipop
.append("g")
.attr('class', 'circles');
circles.selectAll("circle")
.data(data)
.enter()
.append("circle")
//.transition()
//.duration(1000)
.attr("cx", function(d) {
return (x(d.label) + x.bandwidth() / 2);
})
.attr("cy", function(d) {
return y(d.value);
})
.attr("r", lolliradian)
.attr('fill', function(d, i) {
return color(i);
})
var innercircles = lollipop
.append("g")
.attr('class', 'innercircles');
innercircles.selectAll("circle")
.data(data)
.enter()
.append("circle")
//.transition()
//.duration(1000)
.attr("cx", function(d) {
return (x(d.label) + x.bandwidth() / 2);
})
.attr("cy", function(d) {
return y(d.value);
})
.attr("r", lolliradian - 5)
.attr('fill', '#ffffff')
lollipop.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
lollipop.append("g")
.call(d3.axisLeft(y));
body {
background: #eeeeee;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<h1>LolliPop I</h1>
<div class="lollipopchart" data-width="300" data-height="300" />
Firstly, you don't need jQuery, you can do everything you want with regular d3.
Regardless, if you want to make the bars grow, you need to know that y=0 is the top and y=height is the bottom, so you need to actually decrease y as you increase height.
I also wouldn't draw a circle in front of another circle, but would use stroke and fill colours instead. If you make a stroke of 5 pixels wide, then it looks the same as in your example.
var data = [{
label: 'Toblerone',
value: 10,
},
{
label: 'Snickers',
value: 25,
},
{
label: 'Jawbreakers',
value: 60,
},
{
label: 'Gummi Worms',
value: 20,
},
];
var width = +d3.select(".lollipopchart").attr('data-width'),
height = +d3.select(".lollipopchart").attr('data-height');
var color = d3.scaleOrdinal()
.range(["#eb6383", "#fa9191", "#ffe9c5", "#b4f2e1"]);
data.forEach(function(d) {
d.total = +d.value;
});
var margin = {
top: 20,
right: 20,
bottom: 85,
left: 20
},
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
var x = d3.scaleBand()
.range([0, width])
.padding(0.9);
var y = d3.scaleLinear()
.range([height, 0]);
x.domain(data.map(function(d) {
return d.label;
}));
y.domain([0, d3.max(data, function(d) {
return d.total;
})]);
var svg = d3.select('.lollipopchart')
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr('class', 'lollipopchart')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var lollipop = svg.append('g').attr('class', 'lollipop');
var bars = lollipop
.append("g")
.attr('class', 'bars')
bars.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr('fill', function(d, i) {
return color(i);
})
.attr("x", function(d) {
return x(d.label);
})
.attr("width", x.bandwidth())
.attr("y", height)
.transition()
.duration(1500)
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.total);
});
var lolliradian = 10;
var circles = lollipop
.append("g")
.attr('class', 'circles');
circles.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return (x(d.label) + x.bandwidth() / 2);
})
.attr("cy", height)
.attr("r", x.bandwidth() / 2)
.attr("fill", "white")
.attr("stroke-width", 5)
.attr('stroke', function(d, i) {
return color(i);
})
.transition()
.duration(1500)
.attr("cy", function(d) {
return y(d.value);
})
.on("end", function() {
d3.select(this)
.transition()
.duration(500)
.attr("r", lolliradian);
});
lollipop.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
lollipop.append("g")
.call(d3.axisLeft(y));
body {
background: #eeeeee;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<h1>LolliPop I</h1>
<div class="lollipopchart" data-width="300" data-height="300" />

Problems with grouped bar chart

I am new to d3 and trying to make a grouped bar chart following this and this websites.
The following is my code for the scales
x0 = d3.scaleTime()
.domain([
d3.min(dataset, function(d) {return d.date;}),
d3.max(dataset, function(d) {return d.date;})
])
.range([0,w]);
x1 = d3.scaleOrdinal()
.domain([dataset.WorldPopulation, dataset.InternetUser]);
// .rangeRound([0, x0.bandwidth()]);
y = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) {return d.WorldPopulation})])
.range([h,0]);
In the website above they use scaleOrdinal but I used scaleTime as x0. Therefore I'm not too sure if that works.
This is my code for the append(rect) for the bar chart
var date = svg.selectAll(".date")
.data(dataset)
.enter()
.append("g")
.attr("class", "g")
.attr("transform", function(d) {return "translate(" + x0(d.date) + ",0)";});
/* Add field1 bars */
date.selectAll(".bar.field1")
.data(d => [d])
.enter()
.append("rect")
.attr("class", "bar field1")
.style("fill","blue")
.attr("x", d => x0(d.WorldPopulation))
.attr("y", d => y(d.WorldPopulation))
.attr("width", x1.bandwidth())
.attr("height", d => {
return height - margin.top - margin.bottom - y(d.WorldPopulation)
});
/* Add field2 bars */
date.selectAll(".bar.field2")
.data(d => [d])
.enter()
.append("rect")
.attr("class", "bar field2")
.style("fill","red")
.attr("x", d => x0(d.InternetUser))
.attr("y", d => y(d.InternetUser))
.attr("width", x1.bandwidth())
.attr("height", d => {
return height - margin.top - margin.bottom - y(d.InternetUser)
});
And this is my csv file. Not too sure how to upload excel so I took a screenshot.
Any help provided will be appreciated. Feel free to request for any extra snippets of my code for clarification.
edit: After tweaking the code, no errors are shown but the svg is not produced either.
Using scaleBand for both x0 and x1, the following code works:
<script src="js/d3.v4.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 x0 = d3.scaleBand()
.rangeRound([0, width]).padding(.1);
var x1 = d3.scaleBand();
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
.scale(x0)
.tickSize(0);
var yAxis = d3.axisLeft()
.scale(y);
var svg = d3.select('body').append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("InternetUserStats.csv", function (error, data) {
var dates = data.map(function (d) { return d.date; });
var ymax = d3.max(data, function (d) { return Math.max(d.WorldPopulation, d.InternetUser); });
x0.domain(dates);
x1.domain(['WorldPopulations', 'InternetUsers']).rangeRound([0, x0.bandwidth()]);
y.domain([0, ymax]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var date = svg.selectAll(".g")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function (d) { return "translate(" + x0(d.date) + ",0)"; });
/* Add field1 bars */
date/*.selectAll(".bar.field1")
.data(data)
.enter()*/
.append("rect")
.attr("class", "bar field1")
.style("fill", "blue")
.attr("x", function (d) { return x1('WorldPopulations'); })
.attr("y", function (d) { return y(+d.WorldPopulation); })
.attr("width", x0.bandwidth() / 2)
.attr("height", function (d) {
return height /*- margin.top - margin.bottom*/ - y(d.WorldPopulation)
});
/* Add field2 bars */
date/*.selectAll(".bar.field1")
.data(data)
.enter()*/
.append("rect")
.attr("class", "bar field2")
.style("fill", "red")
.attr("x", function (d) { return x1('InternetUsers'); })
.attr("y", function (d) { return y(d.InternetUser); })
.attr("width", x0.bandwidth() / 2)
.attr("height", function (d) {
return height /*- margin.top - margin.bottom*/ - y(d.InternetUser)
});
});
</script>
EDIT: the following code adds a legend that is based on your comment and your second link:
//This code goes after field2 bars are added.
/* Legend */
var legend = svg.selectAll(".legend")
.data(['WorldPopulations', 'InternetUsers']) //Bind an array of the legend entries
.enter().append("g")
.attr("class", "legend")
.attr("font-family", "sans-serif")
.attr("font-size", 13)
.style("text-anchor", "end")
.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", function (d) {
// Return "blue" for "WorldPopulations" and "red" for "InternetUsers":
return ((d === "WorldPopulations") ? "blue" : "red");
});
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
//.style("text-anchor", "end") //Already applied to .legend
.text(function (d) { return d; });

D3 V4: Zoom & drag multi-series line chart

I am drawing charts with d3 4.2.2 in my Angular2 project. I created a multi series line chart and added zoom and drag properties. Now the chart is zooming on mouse scroll event but it zoom only X-axis and Y-axis. And it can be dragged only X-axis & Y-axis but chart cannot be dragged. When I do zooming or dragging those events are applying only to the two axis es but not for the chart. Following is what I am doing with my code.
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 80,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var zoom = d3.zoom()
.scaleExtent([1, 5])
.translateExtent([[0, -100], [width + 90, height + 100]])
.on("zoom", zoomed);
var svg = d3.select(this.htmlElement).append("svg")
.attr("class", "line-graph")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.attr("pointer-events", "all")
.call(zoom);
var view = svg.append("rect")
.attr("class", "view")
.attr("x", 0.5)
.attr("y", 0.5)
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("fill", "#EEEEEE")
.style("stroke", "#000")
.style("stroke-width", "0px");
// parse the date / time
var parseDate = d3.timeParse("%Y-%m-%d");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var z = d3.scaleOrdinal(d3.schemeCategory10);
// define the line
var line = d3.line()
.x( (d) => {
return x(d.date);
})
.y( (d) => {
return y(d.lookbookcount);
});
z.domain(d3.keys(data[0]).filter(function (key) {
return key !== "date";
}));
// format the data
data.forEach( (d)=> {
d.date = parseDate(d.date);
});
var lookBookData = z.domain().map(function (name) {
return {
name: name,
values: data.map( (d) => {
return {date: d.date, lookbookcount: d[name], name: name};
})
};
});
x.domain(d3.extent(data, (d) => {
return d.date;
}));
y.domain([
d3.min([0]),
d3.max(lookBookData, (c) => {
return d3.max(c.values,
(d) => {
return d.lookbookcount;
});
})
]);
z.domain(lookBookData.map( (c) => {
return c.name;
}));
var xAxis = d3.axisBottom(x)
.ticks(d3.timeDay.every(1))
.tickFormat(d3.timeFormat("%d/%m"));
var yAxis = d3.axisLeft(y)
.ticks(10);
// Add the X Axis
var gX = svg.append("g")
.style("font", "14px open-sans")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
var gY = svg.append("g")
.style("font", "14px open-sans")
.attr("class", "axis axis--x")
.call(yAxis)
.style("cursor", "ns-resize");
// Add Axis labels
svg.append("text")
.style("font", "14px open-sans")
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.text("Sales / Searches");
svg.append("text")
.style("font", "14px open-sans")
.attr("text-anchor", "end")
.attr("dx", ".71em")
.attr("transform", "translate(" + width + "," + (height +
(margin.bottom)) + ")")
.text("Departure Date");
var chartdata = svg.selectAll(".chartdata")
.data(lookBookData)
.enter().append("g")
.attr("class", "chartdata");
chartdata.append("path")
.classed("line", true)
.attr("class", "line")
.attr("d", function (d) {
return line(d.values);
})
.style("fill", "none")
.style("stroke", function (d) {
return z(d.name);
})
.style("stroke-width", "2px");
chartdata.append("text")
.datum(function (d) {
return {
name: d.name, value: d.values[d.values.length - 1]
};
})
.attr("transform", function (d) {
return "translate(" +
x(d.value.date) + "," + y(d.value.lookbookcount) + ")";
})
.attr("x", 3)
.attr("dy", "0.35em")
.style("font", "14px open-sans")
.text(function (d) {
return d.name;
});
// add the dots with tooltips
chartdata.selectAll(".circle")
.data(function (d) {
return d.values;
})
.enter().append("circle")
.attr("class", "circle")
.attr("r", 4)
.attr("cx", function (d) {
console.log(d);
return x(d.date);
})
.attr("cy", function (d) {
return y(d.lookbookcount);
})
.style("fill", function (d) { // Add the colours dynamically
return z(d.name);
});
function zoomed() {
view.attr("transform", d3.event.transform);
gX.call(xAxis.scale(d3.event.transform.rescaleX(x)));
}
function resetted() {
svg.transition()
.duration(750)
.call(zoom.transform, d3.zoomIdentity);
}
Any suggestions would be highly appreciated.
Thank you

D3.js horizontal histogram

I'm trying to design a horizontal histogram and I've only encountered the vertical histogram chart by Mike Bostock. As mentioned here, the slightly hacky solution is to do a transform rotate on the element containing the histogram. Either that or don't use d3.layout.histogram() and write out the code manually. Is there a way in D3 to do something along the lines of
d3.layout.histogram().orient("left")
You can simply take care of it at render time without any transforms or recalculating. Simply treat d.x as y-position, d.dy as width instead of height.
Swapping between x and y might seem inappropriate, but it's totally reasonable. There are even examples of radial charts drawn this way too, using the x values to derive the angle of the bar and the y value as distance from the center. That's the neat thing about d3 layouts; they don't commit you to a representation or coordinate system —— they just calculate relationships.
For both verti & hori, you can use those 2 "well-rounded" instances i use pretty much all the time with a sexy transition.
But there is nonetheless a transform method mobilized there.
Vertical:
example
<svg width="550" height="250"></svg>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 60},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.tsv("data.txt", function(d) {
d.value = +d.value;
return d;
}, function(error, data) {
if (error) throw error;
x.domain(data.map(function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "rotate(-45)")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("x", x(data[0].date))
.style("text-anchor", "end")
.attr("dx", "-1.2em")
.attr("dy", ".01em")
.attr("transform", "rotate(-45)" );
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).ticks(10, "r"))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Frequency");
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
//.attr("x", function(d) { return x(d.date); })
//.attr("y", function(d) { return y(d.value); })
.attr('x', function(d) { return getX(d);})
.attr('y', height) /* function(d) { return height; }}) */
.attr("width", x.bandwidth())
.transition()
.duration(500)
.delay(function(d, i) { return i * 35;})
.ease(d3.easeElasticOut)
.attr('y', function(d) { return getY(d); })
.attr('height', function(d) { return height - getY(d);});
//.attr("height", function(d) { return height - y(d.value); });
g.selectAll(".ba")
.data(data)
.enter().append("text")
.attr("x", function(d) { return x(d.date); })
.attr("y", function(d) { return y(d.value); })
.attr("dy", ".90em")
.attr("dx", ".35em")
.attr("class","label_barre")
.text(function(d) { return d.value;});
function type(d) {
d.value = +d.value;
return d;
}
function getName(d) {
return d.date;
}
function getValue(d) {
return d.value;
}
function getX(d) {
return x(d.date);
}
function getY(d) {
return y(d.value);
}
});
</script>
Horizontal:example
<svg width="560" height="400"></svg>
<script>
var width = 560,
height = 400;
var margin = {top: 20, right: 15, bottom: 30, left: 80},
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
var x = d3.scaleLinear().rangeRound([0, height], .05);
var y = d3.scaleBand().rangeRound([height, 0]);
var q = d3.select("svg").append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.tsv("Data.txt", function(error, data) {
data.sort(function(a, b) { return a.value - b.value; });
//data.sort(function(a, b) { return a.date - b.date; });
data.forEach(function(d) {
d.date = d.date;
d.value = +d.value;
});
x.domain([0, d3.max(data, function(d) { return d.value; })]);
y.domain(data.map(function(d) { return d.date; })).padding(0.1);
q.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(y));
q.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(10))
.append("text")
.attr("transform", "rotate(0)")
.attr("y", -12)
.attr("x", +211)
.attr("dy", "0.71em")
.attr("text-anchor", "middle")
.text("Familles");
q.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
//.attr("x", function(d) { return x(d.date); })
//.attr("y", function(d) { return y(d.value); })
.attr('y', function(d) {return getX(d);})
.attr('x', 0) /* function(d) { return height;}) */
.attr("height", y.bandwidth())
.transition()
.duration(500)
.delay(function(d, i) { return i * 40;})
.ease(d3.easeElasticOut)
.attr('y', function(d) { return getX(d);})
// .attr('width', function(d) { return width - getY(d);});
.attr("width", function(d) { return x(d.value); });
q.selectAll(".ba")
.data(data)
.enter().append("text")
.attr("x", function(d) { return x(d.value); })
.attr("y", function(d) { return y(d.date); })
.attr("dy", "1.4em")
.attr("dx", "-1.1em")
.attr("class","label")
.text(function(d) { return d.value;});
//function type(d) {
//d.value = +d.value;
//return d;
//}
//function getName(d) {
//return d.date;
//}
function getValue(d) {
return d.value;
}
function getX(d) {
return y(d.date);
}
//function getY(d) {
//return x(d.value);
//}
});

d3 stacked bar chart values not showing up on chart

So I have created a D3 Stacked Bar Chart, but I can't seem to figure out how to make the values of the bars show up on the chart. I can display Text "Sample" to each bar, but I can't figure out how to retrieve the data. I tried using this... .text(function(d) {return d.total; }) but with no luck.
jfiddle here.... http://jsfiddle.net/rasweat/D3ErQ/1/
<script src="http://d3js.org/d3.v3.js"></script>
<script type="text/javascript">
var margin = {top: 60, right: 20, bottom: 100, left: 100},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width-100], .1); //width-100 to make room for the legend.
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
//.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
.range(["#1f77b4", "#ff7f0e","d62728"]); //blue, orange, red
//color code for Progress Report
//.range(["#00FFFF","#00FF00","#990099","#FF0000","#FFFF00"]);
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("#area_progress_report").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Get the data
//var data = [{"Commodity":"Base","num_complete_print":"3","num_incomplete_print":15},{"Commodity":"Blade","num_complete_print":"1","num_incomplete_print":53},{"Commodity":"DTE","num_complete_print":"1","num_incomplete_print":17},{"Commodity":"HUB","num_complete_print":"0","num_incomplete_print":"18"},{"Commodity":"MH","num_complete_print":"0","num_incomplete_print":"18"},{"Commodity":"Mid","num_complete_print":"0","num_incomplete_print":18},{"Commodity":"Top","num_complete_print":"0","num_incomplete_print":18}];
var data = <?php echo json_encode($dataset_progress001); ?>;
//alert(data);
//d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Commodity"; }));
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;
});
//use this to sort the bars from largest to smallest
//data.sort(function(a, b) { return b.total - a.total; });
x.domain(data.map(function(d) { return d.Commodity; }));
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)
.selectAll("text") //added this line through rotate to change orientation of x axis
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-1em")
.attr("transform", function(d) {
return "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("Population");
//grid lines y.ticks controls the number of lines
svg.selectAll("line.horizontalGrid").data(y.ticks(10)).enter()
.append("line")
.attr(
{
"class":"horizontalGrid",
"x1" : 0,
"x2" : width-60,
"y1" : function(d){ return y(d);},
"y2" : function(d){ return y(d);},
"fill" : "none",
"shape-rendering" : "crispEdges",
"stroke" : "grey",
"stroke-width" : "1px"
});
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.Commodity) + ",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; });
//Added y label 10/28
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("y", -60)
.attr("x",-70)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("Number Of Components");
//Add Title
svg.append("text")
.attr("x", (width/2) )//(width / 2))
.attr("y", -20) //0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "20px")
.style("text-decoration", "underline")
.text("Inspection Progress Report");
state.selectAll("text")
.data(function(d) { return d.ages; })
.enter()
.append("text")
.attr("x", x.rangeBand()/2)
.attr("y", function(d, i) { return y(d.y1) + (y(d.y0) - y(d.y1))/2; })
.style("text-anchor", "middle")
//.text(function(d) {return d.total; })
.text("sample")
</script>
You have to change this line
.data(function(d) { return d.ages; })
to actually give data() your data. If you have an array with all the ages named ages, then it would be:
.data(ages)
The d argument in function(d) references nothing since data() is actually the method where you input your data.

Categories

Resources