I am new to D3.js and got one issue.
I tried to create bar using some sample data.
var data = [{"date":"Chennai","value":"53"},
{"date":"Banglore","value":"165"},
{"date":"Pune","value":"269"},
{"date":"Ban","value":"344"},
{"date":"Hyderabad","value":"376"},
{"date":"HYd","value":"410"},
{"date":"Gurugram","value":"421"},
{"date":"Che","value":"376"}];
Able to display Strings(Ex: "Bangalore" on X-axis and values on Y-axis but I need to display Strings on Y-axis and values on X-axis.
var margin = {top: 20, right: 20, bottom: 70, left: 60},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var y = d3.scale.ordinal().rangeRoundBands([height,0]);
var x = d3.scale.linear().range([0, width]);
var data = [{"date":"Chennai","value":"53"},
{"date":"Banglore","value":"165"},
{"date":"Pune","value":"269"},
{"date":"Ban","value":"344"},
{"date":"Hyderabad","value":"376"},
{"date":"HYd","value":"410"},
{"date":"Gurugram","value":"421"},
{"date":"Kadapa","value":"405"},
{"date":"Che","value":"376"}]
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(12);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
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 + ")");
data.forEach(function(d) {
d.value = +d.value;
});
y.domain(data.map(function(d) { return d.date; }));
x.domain([0, d3.max(data, function(d) { return d.value; })]);
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("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.value); })
.attr("width", function(d) { return width - x(d.value); })
.attr("y", function(d) { return y(d.date); })
.attr("height", y.rangeBand())
.attr("title",function(d) { return y(d.value); });
svg.selectAll("bar")
.data(data)
.enter()
.append("text")
.attr("class","label")
.attr("y", (function(d) { return y(d.date) + y.rangeBand()/2 ; } ))
.attr("x", function(d) { return x(d.value) + 1; })
.attr("dx", ".75em")
.text(function(d) { return d.date; });
When I tried with the above code bars are coming as Horizontal but need as vertical.
Please help me on this.
Thanks in Advance.
You should be more accurate with your "height/x/y" manipulations :)
D3 uses coordinate space where x=0 and y=0 coordinates fall on the bottom left.
I've changed some of your code:
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x",function(d) { return x(d.value); })
.attr("width", y.rangeBand())
.attr("y", function(d) { return height - y(d.date); })
.attr("height", function(d) { return y(d.date); })
.attr("title",function(d) { return y(d.value); });
and I've got the result
Bars are in the right places.
I believe you can figure out with titles by your own, if no - you know what to do
ps: http://jsfiddle.net/om42ts61/
Since the values are dynamically appended it is better to use y-axis for the values.
Related
I'm following a long Mike Bostocks' Let's make a Bar Chart tutorial and I'm stuck after I decided, that my bars need some text.
As far as I understood it, rect cannot contain text elements, so I need to create a grouping and wrap both, text and rect in it. The problem is, that my code refuses to render the groupings (and the bars for that matter).
In fact, it does not even execute the section to append a <g> element. If I throw in a console.log or alert into the callback it does never get called.
Full code for reference below. The part in question is:
var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) {
return "translate(" + x(d.letter) + "," + y(d.value) + ")";
});
Full code:
var margin = { top: 20, right: 30, bottom: 30, left: 40 }, width = 960, height = 500;
var x = d3.scaleBand()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y)
.ticks(10, "%").tickPadding(11);
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 + ")");
d3.tsv("../data.tsv", type, function (err, data) {
x.domain(data.map(function (d) {
return d.letter;
}));
//set domain of scale, it is now known
y.domain([0, d3.max(data, function (d) {
return d.value;
})]);
//append the xAis
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");
var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) {
return "translate(" + x(d.letter) + "," + y(d.value) + ")";
});
bar.append("rect")
.attr("height", function(d) { return height - y(d.value); })
.attr("width", x.bandwidth());
});
function type(d) {
//coerce property to be number ->
//find out what the difference between + and Number() is.
d.value = +d.frequency;
return d;
}
So, where did I go wrong and why?
You have two problems, the first one being a simple selection order and the second one being conceptual.
The first problem is this: when you write
var bar = chart.selectAll("g")
for creating your groups, you're selecting groups that already exist in your SVG, which are the axes and an initial group added to the SVG.
So, select something else, something that doesn't exist:
var bar = chart.selectAll(".foo")
Your second problem is conceptual: although you're correct about being impossible to append a text to a rect, you don't need g elements to achieve what you want. Just create a rect selection and a text selection, and append both to the SVG.
But if you want to add the groups, this is what you have to do.
First, in the data binding, select something that doesn't exist:
var groups = chart.selectAll(".groups")
.data(data)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + x(d.letter) + ",0)";
});
Translate only the x position of the groups, the y position of their elements will be set individually.
Then, create the bars:
var bar = groups.append("rect")
.attr("y", function(d) {
return y(d.value);
})
.attr("width", x.bandwidth())
.attr("height", function(d) {
return height - y(d.value);
});
And finally your texts:
var text = groups.append("text")
.attr("y", function(d) {
return y(d.value) - 6;
})
.attr("x", x.bandwidth() / 2)
.attr("text-anchor", "middle")
.text(function(d) {
return d.value
});
This is a demo using your code and fake data:
var data = d3.csvParse(d3.select("#csv").text());
data.forEach(function(d) {
d.value = +d.value
});
var margin = {
top: 20,
right: 30,
bottom: 30,
left: 40
},
width = 960,
height = 500;
var x = d3.scaleBand()
.rangeRound([0, width])
.padding(0.3);
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom(x),
yAxis = d3.axisLeft(y)
.ticks(10, "%").tickPadding(11);
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 + ")");
x.domain(data.map(function(d) {
return d.letter;
}));
//set domain of scale, it is now known
y.domain([0, d3.max(data, function(d) {
return d.value;
})]);
var groups = chart.selectAll(".groups")
.data(data)
.enter()
.append("g")
.attr("transform", function(d) {
return "translate(" + x(d.letter) + ",0)";
})
var bar = groups.append("rect").attr("y", function(d) {
return y(d.value);
})
.attr("width", x.bandwidth())
.attr("height", function(d) {
return height - y(d.value);
});
var text = groups.append("text")
.attr("y", function(d) {
return y(d.value) - 6;
})
.attr("x", x.bandwidth() / 2)
.attr("text-anchor", "middle")
.text(function(d) {
return d.value
});
//append the xAis
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");
pre {
display: none;
}
rect {
fill: teal;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg class="chart"></svg>
<pre id="csv">letter,value
A,.08167
B,.01492
C,.02782
D,.04253
E,.12702
F,.02288
G,.02015</pre>
I am trying to dynamically update my bar chart from a json data set.
Data look like this :
[{x=a,y=1},{x=b,y=2},{x=c,y=4}],
[{x=d,y=0.1},{x=a,y=1}],{x=b,y=4}]
I used the code to set the dimensions of the canvas (y-axis and x-axis):
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
The whole code :
// set the ranges
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
// add the SVG element
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 + ")");
// load the data
data=mydata
data.forEach(function(d) {
d.x = d.x;
d.y = +d.y;
});
// scale the range of the data
x.domain(data.map(function(d) { return d.x; }));
y.domain([0, d3.max(data, function(d) { return d.y; })]);
// add axis
chart.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)" );
chart.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
// Add bar chart
chart.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.x); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y); })
.attr("height", function(d) { return height - y(d.y); });
//Call function to update barchart
function redraw(data){
x.domain(data.map(function(d) { return d.x; }));
y.domain([0, d3.max(data, function(d) { return d.y; })]);
chart.select(".x.axis").remove();
chart.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)" );
// y-axis
chart.select(".y.axis").remove();
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");
var bar = chart.selectAll(".bar")
.data(data, function(d) {
return d.x; });
// new data:
bar.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); })
.attr("height", function(d) { return height - y(d.y); })
.attr("width", x.rangeBand());
// removed data:
// bar.exit().remove();
chart.select(".y.axis").transition().delay(750).call(yAxis)
// updated data:
bar
.transition()
.duration(750)
.attr("y", function(d) { return y(d.y); })
.attr("height", function(d) { return height - y(d.y); });
}
In this case you will have to redefine the xAxis and yAxis to use the new scale values you define in the function, by pretty much copying the declaration into the function scope.
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
The primary reason you're getting the old values on the axis is because when you call ".call(xAxis)" inside the function the x scale associated with that axis declaration is the original one.
Hope this helps..
i have following code
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.value = +d.value;
});
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var y1 = 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 svg = d3.select("#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 yAxisRight = d3.svg.axis().scale(y1)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y1(d.avg_return); });
x.domain(data.map(function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
y1.domain([0, d3.max(data, function(d) {
return d.avg_return; })]);
/*for x axis*/
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)" );
/*for y axis*/
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("Value ($)");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill",function(d) { if (d.value >= 400) {return "green"} else if (d.value<=300) { return "red" } else { return 'yellow'} })
.attr("x", function(d) { return x(d.date); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
svg.append('path')
.datum(data)
.attr('class', 'sparkline')
.attr('d', line);
svg.append('circle')
.attr('class', 'sparkcircle')
.attr('cx', x(data[0].date))
.attr('cy', y1(data[0].avg_return))
.attr('r', 2.5);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + " ,0)")
.style("fill", "red")
.call(yAxisRight);
});
my csv file contains following data
date,value,avg_return
a,530,70
b,490,91
c,450,92
d,400,78
e,370,50
f,340,56
D,300,32
h,250,96
a9,200,73
i have use color gradient for this colors(#D73027,#FFFFBF,#1A9850).
how to use color gradient in bar chart..i have to sett colors based on the (value column)
From here : How to customize the color scale in a D3 line chart?
I have created your custom color scale :
var color = d3.scale.ordinal()
.range(["#D73027", "#FFFFBF" , "#1A9850"]);
And edited how you fill your bars :
.style("fill", function(d,i){
return color(i); //pass i to scale
})
Notice I pass i to the color scale. If there aren't enough colors in the scale it will wrap round and start again.
Working fiddle : https://jsfiddle.net/thatOneGuy/snjb4q92/2/
Edit
You say you want 'boundaries'. So what I have done, if its between 0 and 300, take first color, 300 and 400 takes second and 400 and 600 takes third.
Logic :
.style("fill", function(d, i) {
if (d.value >= 0 && d.value < 300) {
return color(0);
} else if (d.value >= 300 && d.value < 400) {
return color(1);
} else if (d.value >= 400 && d.value < 600) {
return color(2);
}
})
Updated fiddle : https://jsfiddle.net/thatOneGuy/snjb4q92/6/
I am creating a bar chart with d3.js from data stored in tsv file. I want to insert a text in each bar. How I can do?
I have tried even this solution, but doesn't work.
Here is the code of my function:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.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");
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 + ")");
function visualize(file){
d3.tsv(file, function(error, data) {
data.forEach(function(d) {
d.weight = +d.weight;
});
x.domain(data.map(function(d) { return d.concept; }));
y.domain([0, d3.max(data, function(d) { return d.weight; })]);
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("weight");
svg.selectAll(".bar")
.data(data)
.enter().append("rect").style("fill", function (d){return d.color;})
.attr("class", "bar")
.attr("x", function(d) { return x(d.concept); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.weight); })
.attr("height", function(d) { return height - y(d.weight); });
svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(function(d) {
return d.concept;
})
.attr("text-anchor", "middle")
.attr("x", x)
.attr("y",y)
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
});
}
All my code with the files tsv are here: full code
AmeliaBR is right as usual, and I am only putting this answer because while I was working on it, I saw myself changing the code so that it really makes use of the Enter, Update, Exit selection paradigm. I have made quite a few changes in that regard. Here is the code, FWIW:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.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");
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.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("weight");
var g = svg.append("g");
function update(file){
d3.tsv(file, function(error, data) {
data.forEach(function(d) {
d.weight = +d.weight;
});
x.domain(data.map(function(d) { return d.concept; }));
y.domain([0, d3.max(data, function(d) { return d.weight; })]);
var bar = g.selectAll(".bar")
.data(data);
bar.enter()
.append("rect")
.attr("class","bar");
bar
.style("fill", function (d){return d.color;})
.attr("class", "bar")
.attr("x", function(d) { return x(d.concept); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.weight); })
.attr("height", function(d) { return height - y(d.weight); });
bar.exit().remove();
var text = g.selectAll(".text")
.data(data);
text.enter()
.append("text")
.attr("class","text");
text
.attr("text-anchor", "right")
.attr("x", function(d) { return x(d.concept); })
.attr("y", function(d) { return y(d.weight) + 22;})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.text(function(d) {
return d.concept;
});
text.exit().remove();
});
}
And you call it like by doing update("data16.tsv") and then update("data15.tsv").
When you draw an axis, it creates separate <text> elements for each label inside the axis group inside the SVG. So if you then try to select all the <text> elements in the SVG, you're going to select all your axis labels. If you have more axis labels than data for text elements, your enter() selection will be empty and nothing will happen.
To be sure you're only selecting the correct <text> elements, give your text labels a class to distinguish them from the axis labels. And then use that class to narrow-down your selector:
svg.selectAll("text.bar-label")
.data(data)
.enter()
.append("text")
.attr("class", "bar-label")
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.