d3 horizontal bar chart with background and max value of 100% - d3.js

I have this single horizontal bar chart and I want to make the following adjustments:
Show the tick value to the right of the bar chart, instead of by the axis.
Show a background for the bar chart scale instead of left and bottom axis.
Current version:
What I'd like to get to:
JS
var data = [
{"yAxis":"score", "xAxis":"72"}
];
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 80},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// set the ranges
var y = d3.scaleBand()
.range([height, 0])
.padding(0.4);
var x = d3.scaleLinear()
.range([0, width]);
var svg = d3.select(".barChartContainer").append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 960 500")
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Scale the range of the data in the domains
x.domain([0, d3.max(data, function(d){ return d.xAxis; })])
y.domain(data.map(function(d) { return d.yAxis; }));
//y.domain([0, d3.max(data, function(d) { return d.prereqs; })]);
// append the rectangles for the bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("y", function(d) { return y(d.yAxis); })
.attr("height", y.bandwidth())
.transition()
.duration(1000)
.delay(function(d, i) {
return i * 100
})
.attr("width", function(d) {return x(d.xAxis); } );
// add the x Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickValues(d3.range(x.domain()[0], x.domain()[1] + 1, 1))
.tickFormat(d3.format("d"))
);
svg.append("g")
.attr("class", "yAxis")
.call(d3.axisLeft(y));
I got this code from a codepen and I've been trying to adapt it, but it has been breaking so I stopped and was hoping you could help.
Thanks.

For showing the background for the bars, just copy your selection and chose a value of 100% for the rectangles, in a light gray fill:
var backgroundBar = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
//etc...
.attr("width", function(d) {
return x(100);
});
Of course, you'll have to change the domain of the x scale:
var x = d3.scaleLinear()
.domain([0, 100]);
Then, drop both axis and print the labels using a text selection.
Finally, use another text selection for the values:
var values = svg.selectAll(null)
.data(data)
.enter()
.append("text")
//etc...
.text(function(d) {
return +d.xAxis
})
If you want, you can tween the text:
.attrTween("text", function(d) {
var self = this
var i = d3.interpolateNumber(0, +d.xAxis);
return function(t) {
return d3.select(self).text(~~i(t));
}
});
This is the result:
var data = [{
"yAxis": "score",
"xAxis": "72"
}];
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 80
},
width = 500 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
var y = d3.scaleBand()
.range([height, 0])
.padding(0.4);
var x = d3.scaleLinear()
.range([0, width])
.domain([0, 100]);
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 200)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
y.domain(data.map(function(d) {
return d.yAxis;
}));
var backgroundBar = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("fill", "lightgray")
.attr("y", function(d) {
return y(d.yAxis);
})
.attr("height", y.bandwidth())
.attr("width", function(d) {
return x(100);
});
var bar = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("y", function(d) {
return y(d.yAxis);
})
.attr("height", y.bandwidth())
.transition()
.duration(2000)
.delay(function(d, i) {
return i * 100
})
.attr("width", function(d) {
return x(d.xAxis);
});
var labels = svg.selectAll(null)
.data(data)
.enter()
.append("text")
.attr("y", function(d) {
return y(d.yAxis) + y.bandwidth() / 2;
})
.attr("x", -10)
.attr("text-anchor", "end")
.text(function(d) {
return d.yAxis
});
var values = svg.selectAll(null)
.data(data)
.enter()
.append("text")
.attr("y", function(d) {
return y(d.yAxis) + y.bandwidth() / 2;
})
.attr("x", 10)
.text(function(d) {
return +d.xAxis
})
.transition()
.duration(2000)
.delay(function(d, i) {
return i * 100
})
.attr("x", function(d) {
return x(d.xAxis) + 10;
})
.attrTween("text", function(d) {
var self = this
var i = d3.interpolateNumber(0, +d.xAxis);
return function(t) {
return d3.select(self).text(~~i(t));
}
});
<script src="https://d3js.org/d3.v4.min.js"></script>

Related

D3 v5 center path line in a bar graph

I am using d3.js v5 to plot a bar graph , Porblem is while creating a bar graph and and appending path along with bars , paths are not making to the center of a bar instead of that it is placed on the start point , is there any way to center the point, Currently the graph showing is like this
But i want the small circles and points to be in the center
sorry for bad image i am just visualizing my concept brown lines are in center and will be connected by path
var margin = {
top: 10,
right: 30,
bottom: 90,
left: 40
},
width = 900 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
this.x_axis = Array(20).fill(0).map((x, i) => (i + 1) * 5);
this.y_axis = [1.1, 2.2, 3.5, 4.9, 5.3, 6.9, 7.3, 8.1, 9.2, 8.2, 1.3, 0.1, 0.1, 0.4, 0.1, 0.4, 0.2, 0.4, 0.1, 0.2];
let data = [];
for (let i = 0; i < this.x_axis.length; i++) {
data.push({
Country: this.x_axis[i],
Value: this.y_axis[i]
})
}
var svg = d3.select("#graph")
.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 + ")");
// Parse the Data
// X axis
var x = d3.scaleBand()
.range([0, width])
.domain(data.map(function(d) {
return d.Country;
}))
.padding(0.3);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 20])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
var x2 = d3.scaleBand()
.range([0, width]);
// Bars
svg.selectAll("mybar")
.data(data)
.enter()
.append("rect")
.attr("x", function(d) {
return x(d.Country);
})
.attr("width", x.bandwidth())
.attr("fill", "#69b3a2")
// no bar at the beginning thus:
.attr("height", function(d) {
return height - y(0);
}) // always equal to 0
.attr("y", function(d) {
return y(0);
})
// Animation
svg.selectAll("rect")
.transition()
.duration(800)
.attr("y", function(d) {
return y(d.Value);
})
.attr("height", function(d) {
return height - y(d.Value);
})
.delay(function(d, i) {
console.log(i);
return (i * 100)
})
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("d", d3.line()
.x(function(d) {
return x(d.Country)
})
.y(function(d) {
return y(d.Value)
}))
svg.selectAll("myCircles")
.data(data)
.enter()
.append("circle")
.attr("fill", "red")
.attr("stroke", "none")
.attr("cx", function(d) {
return x(d.Country)
})
.attr("cy", function(d) {
return y(d.Value)
})
.attr("r", 3)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="graph"></div>
Since you're using a scaleBand, the axis automatically returns not the center, but the top left of the rectangle, by offsetting by about x.bandwidth() / 2. One workaround for this would be to use return x(d.Country) + x.bandwidth() / 2 to find the center of the bars.
var margin = {
top: 10,
right: 30,
bottom: 90,
left: 40
},
width = 900 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
this.x_axis = Array(20).fill(0).map((x, i) => (i + 1) * 5);
this.y_axis = [1.1, 2.2, 3.5, 4.9, 5.3, 6.9, 7.3, 8.1, 9.2, 8.2, 1.3, 0.1, 0.1, 0.4, 0.1, 0.4, 0.2, 0.4, 0.1, 0.2];
let data = [];
for (let i = 0; i < this.x_axis.length; i++) {
data.push({
Country: this.x_axis[i],
Value: this.y_axis[i]
})
}
var svg = d3.select("#graph")
.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 + ")");
// Parse the Data
// X axis
var x = d3.scaleBand()
.range([0, width])
.domain(data.map(function(d) {
return d.Country;
}))
.padding(0.3);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 20])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
var x2 = d3.scaleBand()
.range([0, width]);
// Bars
svg.selectAll("mybar")
.data(data)
.enter()
.append("rect")
.attr("x", function(d) {
return x(d.Country);
})
.attr("width", x.bandwidth())
.attr("fill", "#69b3a2")
// no bar at the beginning thus:
.attr("height", function(d) {
return height - y(0);
}) // always equal to 0
.attr("y", function(d) {
return y(0);
})
// Animation
svg.selectAll("rect")
.transition()
.duration(800)
.attr("y", function(d) {
return y(d.Value);
})
.attr("height", function(d) {
return height - y(d.Value);
})
.delay(function(d, i) {
console.log(i);
return (i * 100)
})
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("d", d3.line()
.x(function(d) {
return x(d.Country) + x.bandwidth() / 2;
})
.y(function(d) {
return y(d.Value)
}))
svg.selectAll("myCircles")
.data(data)
.enter()
.append("circle")
.attr("fill", "red")
.attr("stroke", "none")
.attr("cx", function(d) {
return x(d.Country) + x.bandwidth() / 2
})
.attr("cy", function(d) {
return y(d.Value)
})
.attr("r", 3)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="graph"></div>

How can I highlight a part of a grouped chart when filter d3

I start with d3 using version 3.
I created a grouped bar chart that looks like this:
I added a drop-down list that contains all the genders (Woman (femme), Couple...).
I'm blocked because I can't highlight the bars that correspond to a certain gender when I choose from the drop-down list.
I found on the internet that I could use this code:
d3.select('#inds')
.on("change", function () {
var sect = document.getElementById("inds");
var section = sect.options[sect.selectedIndex].value;
//some code here
});
the "Section" part contains my selected gender
I would like that when I select, for example torque, that the bars corresponding to the torque remain in color and the others are in gray.
This is the all code :
source : https://bl.ocks.org/hydrosquall/7966e9c8e8414ffcd8b5
Highlight : https://bl.ocks.org/bricedev/0d95074b6d83a77dc3ad
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 600,
height = 250 ;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#54E868", "#54CCE8", "#6395FF", "#50FFC5"]);
var xAxis = d3.svg.axis()
.scale(x0)
.tickSize(0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
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("../CSV/GenreOrigine.csv", function(error, data) {
if (error) throw error;
//Couples, Famille...
var genreNames = d3.keys(data[0]).filter(function(key) { return key !== "Origine"; });
data.forEach(function(d) {
//Valeur pour chacune des origines par rapport au genre
d.genres = genreNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.Origine; }));
x1.domain(genreNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.genres, 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")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0.3)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Nombre de personnes");
svg.select('.y').transition().duration(500).delay(1300).style('opacity','1');
var Origine = svg.selectAll(".Origine")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.Origine) + ",0)"; });
Origine.selectAll("rect")
.data(function(d) { return d.genres; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.style("fill", function(d) { return color(d.name) })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.on("mouseover", function(d) {
d3.select(this).style("fill", d3.rgb(color(d.name)).darker(2));
})
.on("mouseout", function(d) {
d3.select(this).style("fill", color(d.name));
});
Origine.selectAll("rect")
.transition()
.delay(function (d) {return Math.random()*1000;})
.duration(1000)
var legend = svg.selectAll(".legend")
.data(genreNames.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; });
d3.select('#inds')
.on("change", function () {
var sect = document.getElementById("inds");
var section = sect.options[sect.selectedIndex].value;
//some code here
});
});
You can select all the rect in the SVG and filter them in the function, so the code would look like:
var sect = document.getElementById('inds');
var section = sect.options[sect.selectedIndex].value;
if(section !== '') {
d3.selectAll("rect")
.attr('opacity', function(d) {
if(d.name !== section) {
return 0.2;
} else {
return 1;
}
})
} else {
d3.selectAll('rect')
.attr('opacity', 1)
}
In the example above, I changed the opacity attribute, but you can change fill with the same approach.

d3 v4 - have value on left side of single horizontal bar chart

below is the code for a horizontal bar chart in its current form. I would like to move the value to the left side of the bar chart. I tried .attr("text-anchor", "start") but it didn't work. Any help is appreciated, and hopefully you can provide some comments to help explain some of the principles in formatting labels/values. Thanks!
var data = [{
"xAxis": "72.1"
}];
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 80
},
width = 500 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
var y = d3.scaleBand()
.range([height, 0])
.padding(0.4);
var x = d3.scaleLinear()
.range([0, width])
.domain([0, 100]);
var svg = d3.select(".barChartContainer").append("svg")
.attr("width", 500)
.attr("height", 200)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
y.domain(data.map(function(d) {
return d.yAxis;
}));
var backgroundBar = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("class", "barBackground")
.attr("y", function(d) {
return y(d.yAxis);
})
.attr("height", y.bandwidth())
.attr("width", function(d) {
return x(100);
});
var bar = svg.selectAll(null)
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("y", function(d) {
return y(d.yAxis);
})
.attr("width", function(d) {
return x(d.xAxis);
});
var labels = svg.selectAll(null)
.data(data)
.enter()
.append("text")
var values = svg.selectAll(null)
.data(data)
.enter()
.append("text")
.attr("y", function(d) {
return y(d.yAxis) + y.bandwidth() / 2;
})
.attr("x", 10)
.text(function(d) {
return +d.xAxis
})
.attr("x", function(d) {
return x(d.xAxis) + 10;
});
Current bar chart
What I would like
Change the last line:
.attr("x", function(d) {
return x(d.xAxis) + 10;
});
And replace with:
.attr("x", x(-10));

Formatting bar graph for integers developed using d3.js

I have developed bar graph using d3.js. The developed bar graph is included in fiddle. I am new to d3.js .So I am in difficulty for formatting graph. I desire to format graph more than the graph shown below.
The main problem I have experienced is ,the graph do not show -ve integer next to the -ve to be plotted in the y axis. ex) The value plotted is -490 , my current graph do not show -500 in y -axis. This issue is also exiting +ve values
The code is given below
var mainApp = angular.module('mainApp', []);
mainApp.controller('FIItradingController',
['$scope', function($scope) {
var data = [
{name: "01-12-2014", value: 4984.6},
{name: "02-12-2014", value: -109.45},
{name: "03-12-2014", value: 474},
{name: "04-12-2014", value: 391.07},
{name: "05-12-2014", value: 106.82},
{name: "06-12-2014", value: -12.36},
{name: "07-12-2014", value: 10},
{name: "08-12-2014", value: 20}
];
var data1 = [4, 8, 15, 16, 23, 42];
var margin = {top: 20, right: 30, 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()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
/*var x = d3.scale.linear()
.range([0, width]);*/
/*var chart = d3.select(".chart")
.attr("width", width);*/
/*var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, width]);*/
var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
$scope.render = function(data) {
/*var chart = d3.select(".chart")
.attr("width", width)
.attr("height", barHeight * data.length);*/
/*bar.append("rect")
.attr("width", x)
.attr("height", barHeight - 1);
bar.append("rect")
.attr("width", function(d) { return x(d.value); })
.attr("height", barHeight - 1);
bar.append("text")
.attr("x", function(d) { return x(d.value) - 3; })
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) { return d.value; });
x.domain([0, d3.max(data, function(d) { return d.value; })]);
chart.attr("height", barHeight * data.length);
*/
x.domain(data.map(function(d) { return d.name; }));
//y.domain([0, d3.max(data, function(d) { return d.value; })]);
y.domain([d3.min(data,function(d){return d.value}), d3.max(data, function(d) { return d.value; })]);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis);
chart.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("Frequency");
/*chart.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.attr("width", x.rangeBand());*/
chart.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", function(d) { return d.value < 0 ? "bar negative" : "bar positive"; })
.attr("y", function(d) {return y(Math.max(0, d.value)); })
.attr("x", function(d) { return x(d.name); })
.attr("height", function(d) {return Math.abs(y(d.value) - y(0)); })
.attr("width", x.rangeBand());
}
function type(d) {
d.value = +d.value; // coerce to number
return d;
}
$scope.render(data);
}]);
If any one know please help me. The fiddle is given below
http://jsfiddle.net/HB7LU/8960/
So, your plot is showing the negative value—it's just that it looks like it drops off below the chart area because the lowest point on the y-axis is where your chart ends.
There are a several ways you get around this (like multiplying the output of d3.min() by 1.1 to give a little extra room), but probably the easiest and most elegant is just to add .nice() to your y-scale, like so:
y.domain([d3.min(data,function(d){return d.value}), d3.max(data, function(d) { return d.value; })])
.nice();
You might also consider using d3.extent() instead of d3.min() and d3.max(). It returns a two-value array of the minimum and maximum values in an array. And I'd also put chain .domain() and .nice() onto y right after its definition; nothing necessitates it being declared 40 lines later. Now we have this:
var y = d3.scale.linear()
.range([height, 0])
.domain(d3.extent(data, function(d) { return d.value; }))
.nice();
Forked fiddle.

d3 bar chart transition from csv

I'm a d3 novice trying to create a simple, two-series bar chart that transitions when different buttons are clicked. The original chart is constructed:
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.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#d4d4d4", "#58bd5b",]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svg = d3.select("div.d3space").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("/assets/data/data3.csv", function(error, data) {
var hourBuckets = d3.keys(data[0]).filter(function(key) { return key !== "Client"; });
data.forEach(function(d) {
d.hours = hourBuckets.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.Client; }));
x1.domain(hourBuckets).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.hours, 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")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Hours");
var client = svg.selectAll(".client")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.Client) + ",0)"; });
client.selectAll("rect")
.data(function(d) { return d.hours; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(hourBuckets.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; });
});
The csv being accessed is in the following format:
Client,Planned,Actual
ICC,25,50
RNR,50,47.5
MB,10,2.5
This chart renders as desired. The piece I am struggling with is getting this graph to transition to reflect different data when a link is clicked (link has id="fourweeks"). I have tried this onclick function:
window.onload = function() {
var a = document.getElementById("fourweeks");
var b = document.getElementById("eightweeks");
var c = document.getElementById("twelveweeks");
a.onclick = function() {
d3.csv("/assets/data/data1.csv", function(error, data) {
var hourBuckets = d3.keys(data[0]).filter(function(key) { return key !== "Client"; });
data.forEach(function(d) {
d.hours = hourBuckets.map(function(name) { return {name: name, value: +d[name]}; });
});
var client = svg.selectAll(".client")
client.selectAll("rect")
.data(function(d) { return d.hours; })
.transition()
.duration(1000)
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
});
}
}
...no dice. I can get this to work when creating / transitioning simple one-series bar charts that use list inputs, but not the multi-series csv ones. data2.csv is the exact same file as data1.csv, with the values adjusted slightly.
Thanks for your time reading - any advice?
First svg.selectAll(".client") returns an empty selection, because you gave these elements the class 'g' instead of 'client'.
Secondly you need to update the data of the .client-elements:
var client = svg.selectAll(".client")
.data(data);
btw. you should use selection.classed() instead of selection.attr('class')

Resources