bar height issue in bar chart of d3 js - javascript

I am trying to draw a Bar Chart using D3.js but its not working successfully. I am trying the following:
var margin = {top:40, right: 40, bottom: 70, left: 40},
width = 500 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width],.5);
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 tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) {
return "<strong>Value:</strong> <span style='color:red'>" + d.ActiveCount + "</span>";
})
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.call(tip);
var data = [{"CreateMonth":"5","ActiveCount":"6"},
{"CreateMonth":"6","ActiveCount":"20"},
{"CreateMonth":"7","ActiveCount":"43"},
{"CreateMonth":"8","ActiveCount":"125"},
{"CreateMonth":"9","ActiveCount":"356"},
{"CreateMonth":"10","ActiveCount":"557"}];
x.domain(data.map(function(d) { return d.CreateMonth; }));
y.domain([0, d3.max(data, function(d) { return d.ActiveCount; })]);
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", ".15em")
.attr("transform", "rotate(-65)");
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("Active");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.CreateMonth); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.ActiveCount); })
.attr("height", function(d) { return height - y(d.ActiveCount); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
I have done this bar graph by using this tutorial http://bl.ocks.org/d3noob/8952219, but I am facing the bar(rect) height problem with uneven ActiveCount data in array object. Is some other problem that I am unable to identify?
Also, why it taking y axis as like this as shown below
and also can't determine the height of tooltip position because I think due to some un-ordered data point or some other issue..
Any suggestion should be appreciated

The problem here is that ActiveCount in your data is a string, not a number.
You have to convert it to number. For instance, using the unary plus operator:
data.forEach(function(d) {
d.ActiveCount = +d.ActiveCount;
});
Regarding the axis, you have to remove the default fill. The easiest way is using the CSS (let's also change the ticks):
line, path {
fill: none;
shape-rendering: crispEdges;
stroke: black;
}
Here is your code with those changes (without d3.tip):
var margin = {
top: 40,
right: 40,
bottom: 70,
left: 40
},
width = 500 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
var format = d3.time.format("%b");
var parser = d3.time.format("%m").parse;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .5);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(function(d){
return format(parser(d))
});
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 + ")");
var data = [{
"CreateMonth": "5",
"ActiveCount": "6"
}, {
"CreateMonth": "6",
"ActiveCount": "20"
}, {
"CreateMonth": "7",
"ActiveCount": "43"
}, {
"CreateMonth": "8",
"ActiveCount": "125"
}, {
"CreateMonth": "9",
"ActiveCount": "356"
}, {
"CreateMonth": "10",
"ActiveCount": "557"
}];
data.forEach(function(d) {
d.ActiveCount = +d.ActiveCount;
});
x.domain(data.map(function(d) {
return d.CreateMonth;
}));
y.domain([0, d3.max(data, function(d) {
return d.ActiveCount;
})]);
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", ".15em")
.attr("transform", "rotate(-65)");
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("Active");
svg.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.style("fill", "darkorange")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.CreateMonth);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.ActiveCount);
})
.attr("height", function(d) {
return height - y(d.ActiveCount);
})
line,
path {
fill: none;
shape-rendering: crispEdges;
stroke: black;
}
<script src="https://d3js.org/d3.v3.min.js"></script>

Related

How do you change the width of a Y-axis in a D3 chart?

I have a simple, working bar chart in D3, configured as follows:
<script>
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m").parse;
//var format = d3.timeFormat("%Y-%m");
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format("%Y-%m"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
var svg = d3.select("#arrChart").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("/chart-arr", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
x.domain(data.map(function(d) { return d.date; }));
y.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)
.attr("width", "150")
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".91em")
.attr("width", "150")
.style("text-anchor", "end")
.text("Value ($)");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.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); });
});
</script>
Right now the Y-axis is not wide enough to accommodate the text labels. My question is, how can I make the Y-axis wider to accommodate longer text labels on the Y-axis?
I tried attr("width") and various other tweaks but nothing is working.
Any help is greatly appreciated!
Simply by changing your margin left:
var margin = {top: 20, right: 20, bottom: 70, left: 70},
NOTE: Please try to always state which version of d3 you are using because v3 and v5 are very different in their APIs etc.
Also, always try to include some dummy data, so that the question is a minimal verifiable example - https://stackoverflow.com/help/minimal-reproducible-example
var margin = {top: 20, right: 20, bottom: 70, left: 70},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m").parse;
//var format = d3.timeFormat("%Y-%m");
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format("%Y-%m"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
var svg = d3.select("#arrChart").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("/chart-arr", function(error, data) {
const data = [
{date: '2020-01', value: '15000'},
{date: '2020-02', value: '17000'},
{date: '2020-03', value: '10000'},
{date: '2020-04', value: '9000'}
];
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
//console.log(data)
x.domain(data.map(function(d) { return d.date; }));
y.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)
.attr("width", "150")
.append("text")
.attr("transform", "rotate(0) translate(60,-20)")
.attr("y", 6)
.attr("dy", ".91em")
.attr("width", "150")
.style("text-anchor", "end")
.text("Value ($)");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.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); });
//});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div id="arrChart"></div>
Output:

How to make d3-diagram visualization from json-array working?

I have a problem with a d3 visualization (bar chart) that doesn't work.
Instead of loading the data from a CSV file like in the tutorials on the d3 page (https://bl.ocks.org/mbostock/3885304), I want it to load from a JSON-array.
Though I'm not sure why it doesn't seem like it loads at all. Can be something when I added the time parse, or placed the x.domain(data.map(function(d) { return d.date; })); outside a CSV load data snippet.
Thank you for your help!
<script type="text/javascript">
var data = [{date:"1999-06-23" ,value:1},{date:"1999-06-24" ,value:2},{date:"1999-06-28" ,value:3},{date:"1999-06-29" ,value:4},{date:"1999-06-30" ,value:5}];
var parseDate = d3.timeParse("%Y-%m-%d");
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m-%d"));
var yAxis = d3.axisLeft(y)
.ticks(10);
var svg = d3.select("#graph").append("svg")
.attr("width", 956)
.attr("height", 360)
margin = {top: 50, right: 100, bottom: 50, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand().rangeRound([0, width]).paddingInner(0.05);
var y = d3.scaleLinear().range([height, 0]);
x.domain(data.map(function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
g.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function (d) { return x(d.date); })
.attr("y", function (d) { return y(d.value); })
.attr("width", x.bandwidth())
.attr("height", function(d) { return height - y(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("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value ($)");
</script>
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<script src="script.js"></script>
</body>
</html>
The list of the problems:
Your reference to D3 is v3. However, your code uses v4.
You are defining the axes generators before defining the scales.
You are not translating the axes.
Besides that, there is no such a thing as "JSON array". That's just an array. You probably meant hardcoded data
Here is the working code:
var data = [{
date: "1999-06-23",
value: 1
}, {
date: "1999-06-24",
value: 2
}, {
date: "1999-06-28",
value: 3
}, {
date: "1999-06-29",
value: 4
}, {
date: "1999-06-30",
value: 5
}];
var parseDate = d3.timeParse("%Y-%m-%d");
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
var svg = d3.select("body").append("svg")
.attr("width", 956)
.attr("height", 360);
var margin = {
top: 50,
right: 100,
bottom: 50,
left: 50
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand().rangeRound([0, width]).paddingInner(0.05);
var y = d3.scaleLinear().range([height, 0]);
x.domain(data.map(function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
return d.value;
})]);
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m-%d"));
var yAxis = d3.axisLeft(y)
.ticks(10);
g.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) {
return x(d.date);
})
.attr("y", function(d) {
return y(d.value);
})
.attr("width", x.bandwidth())
.attr("height", function(d) {
return height - y(d.value);
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + margin.left + "," + (height + margin.bottom) + ")")
.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")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value ($)");
<script src="https://d3js.org/d3.v4.min.js"></script>

D3.js: Changing the tick values on x-axis based on the screen width

I am making a responsive D3.js Bar Chart, by setting the height to clientWidth. Though the chart resizes after reloading in a new size, when the size is small the x-axis values overlap. I need to avoid this, how can i do it?
Script:
clientw = document.body.clientWidth;
var margin = {top: 40, right: 20, bottom: 30, left: 40},
width = clientw - 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")
.ticks(10)
.tickFormat(d3.format("s"));
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Hola:</strong> <span style='color:red'>" + d.hola+ "°C"+"</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.tsv("data.tsv", type, function(error, data) {
x.domain(data.map(function(d) { return d.hermanos; }));
y.domain([0, 45]);
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("Hola");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("width", x)
.attr("fill","grey")
.attr("class", "bar")
.attr("x", function(d) { return x(d.hermanos); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.hola); })
.attr("height", function(d) { return height- y(d.hola); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
});
function type(d) {
d.hola= +d.hola;
return d;
}

D3 - To add Data Labels to a simple bar chart

I know this is easy and I saw some examples in this forum as well as other websites as well, but I simple can't figure it out.
I'm new in using D3 library to generate the charts. I'm trying to learn by creating bar chart.
My question is how to add the Data Labels into the chart?
Below is the codes I have.
then I have my JS:
var chartwidth = 800;
var chartheight = 600;
var data = [
{"Start_Dt":"Jan 15","UnitName":"Unit 1","ProgramName":"ProgramName 1","AttendCnt":159,"NewcomerCnt":10}
, {"Start_Dt":"Jan 22","UnitName":"Unit 2","ProgramName":"ProgramName 2","AttendCnt":178,"NewcomerCnt":5}
, {"Start_Dt":"Feb 14","UnitName":"Unit 2","ProgramName":"ProgramName 3","AttendCnt":240,"NewcomerCnt":46}
, {"Start_Dt":"Feb 19","UnitName":"Unit 1","ProgramName":"ProgramName 4","AttendCnt":201,"NewcomerCnt":10}
, {"Start_Dt":"Feb 26","UnitName":"Unit 2","ProgramName":"ProgramName 5","AttendCnt":177,"NewcomerCnt":7}
, {"Start_Dt":"Mar 12","UnitName":"Unit N","ProgramName":"ProgramName N","AttendCnt":184,"NewcomerCnt":3}
];
var margin = {top: 20, right: 20, bottom: 300, left: 40},
width = chartwidth - margin.left - margin.right,
height = chartheight - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var formatTime = d3.time.format("%e %B");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x2 = d3.scale.ordinal()
.rangeBands([0, width], 0);
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(".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 + ")");
data.forEach(function(d) {
d.AttendCnt = +d.AttendCnt;
});
x.domain(data.map(function(d) { return d.Start_Dt + " " + d.ProgramName; }));
y.domain([0, d3.max(data, function(d) { return d.AttendCnt; })]);
//Create 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", ".15em")
.attr("transform", "rotate(-65)" )
.append("text")
.attr("y", 25)
.attr("x",x.rangeBand()/2 )
.style("text-anchor", "middle")
.style("font-size", "20px")
.style("color", "black")
.text(function(d,i) { return "xxx"; });
//Create Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Attendance");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.Start_Dt + " " + d.ProgramName); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.AttendCnt); })
.attr("height", function(d) { return height - y(d.AttendCnt); });
Before
After
How to modify the codes to get the result I wanted? Tks
i haven't tested the code but it could be something like this :
svg.selectAll(".barText")
.data(data)
.enter().append("text")
.attr("class", "barText")
.attr("x", function(d) { return x(d.Start_Dt + " " + d.ProgramName); })
.attr("y", function(d) { return height - y(d.AttendCnt); })
.text(function(d) { return d.AttendCnt; })
;
Hope it helps

Add text on top of bar in d3js chart -- no <text> elements added

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")

Categories

Resources