The following code in d3js is supposed to draw a bar chart. It draws the axis and adds the labels to them. But it doesn't draw the bars. My guess is it can't find the svg.selectAll(".bar") but I don't know how I should fix it.
P.S. I was following this tutorial: https://github.com/colorfest/d3js/blob/master/js/bargraph/bargraph.js
function drawBarchart(geography){
var x_labels = ["Very Good", "Good", "Fair", "Poor", "Mentioned", "Not Mentioned"];
var margin = {top: 20, right: 20, bottom: 100, left: 60},
width = 800 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
x = d3.scale.ordinal().rangeRoundBands([0,width], 0.5),
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(5)
var svg = d3.select("#barchart")
.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("data.json", function (data)
{
x.domain(x_labels.map(function (l)
{
return l;
}));
y.domain([0,300]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-0.5em")
.attr("dy", "-.55em")
.attr("y", 30)
.attr("transform", "rotate(-45)" );
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 5)
.attr("dy", "0.8em")
.attr("text-anchor", "end")
.text("Score");
svg.selectAll(".bar")
.data(data[6][geography.id])
.enter()
.append("rect")
.style("fill", "orange")
.attr("x", function(d)
{
return x(d.name);
})
.attr("width", x.rangeBand())
.attr("y", function (d)
{
return y(d["Health"][0]);
})
.attr("height", function (d)
{
return height;
});
}
I updated part of you code block. You were correct with it no finding .bar as the rects were not given the bar class.
svg.selectAll(".bar")
.data(data[6][geography.id])
.enter()
.append("rect")
.attr("class", "bar")
.style("fill", "orange")
.attr("x", function(d)
{
return x(d.name);
})
.attr("width", x.rangeBand())
.attr("y", function (d)
{
return y(d["Health"][0]);
})
.attr("height", function (d)
{
return height;
});
}
Related
So I'm trying to create a bar chart using d3 and here's my code, for some reason, the bar chart won't show up and I'm getting an error saying:
remote-work.js:14 Uncaught (in promise) TypeError: Cannot read property 'linear' of undefined
at drawBars (remote-work.js:14)
Can anyone advise me on where I'm going wrong it would be greatly appreciated.
async function drawBars() {
// 1. Access data
const data = await d3.csv("./../remote_work.csv")
console.log(data);
//chart = {
const margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom
const x = d => d.Benefits
const y = d3.scale.linear()
.range(height, 0);
const xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
const yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
const 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 + ")");
x.domain(data.map(function(d) { return d.Benefits; }));
y.domain([0, d3.max(data, function(d) { return d.Percentage; })]);
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("Percentage ($)");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.Benefits); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.Percentage); })
.attr("height", function(d) { return height - y(d.Percentage); });
}
drawBars()
I have this JSON data
{"1960":"133.55501327769","1961":"134.159118941963","1962":"134.857912280869","1963":"134.504575565342","1964":"134.105211273476","1965":"133.569625896451","1966":"132.675635192775","1967":"131.665502129354","1968":"129.190980115918","1969":"126.736756382819","1970":"124.382808900193","1971":"122.133431342027","1972":"120.020185557559","1973":"118.087531093609","1974":"116.132988067096","1975":"114.100918174437","1976":"111.980005447216","1977":"109.783821762662","1978":"106.033489239906","1979":"102.341720681455","1980":"98.7390023274647","1981":"95.2412508672801","1982":"91.7911923993222","1983":"88.0011769487606","1984":"84.2072557839419","1985":"80.3593225600132","1986":"76.4415956498419","1987":"72.5145803648751","1988":"71.1706639452677","1989":"69.8887679924858","1990":"69.0044133814268","1991":"67.7559924352118","1992":"66.9284506867798","1993":"64.9489678572737","1994":"62.9227777228154","1995":"60.7070695260477","1996":"58.5966308804751","1997":"56.4401276304142","1998":"55.5315395528949","1999":"54.6587808352011","2000":"53.8314102398679","2001":"52.9015276443892","2002":"51.9907926813042","2003":"51.5228563035101","2004":"51.1032496482833","2005":"50.7325902239383","2006":"50.3291352282938","2007":"49.9998514069402","2008":"49.8870459355469","2009":"49.7812066054555","2010":"49.6729747116906","2011":"49.5360469363113","2012":"49.3837446924523","2013":"48.7965576984378","2014":"48.1964180547578","2015":"47.5501940499984","Country Name":"Arab World","Country Code":"ARB","Indicator Name":"Adolescent fertility rate (births per 1,000 women ages 15-19)","Indicator Code":"SP.ADO.TFRT","":""}
which I convert from CSV to JS object.
How do I build a bar chart with d3.js where the key is the X axis and the values are the Y axis?
here's what I came up with
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// 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 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.queue()
.defer(d3.csv, "http://localhost:8000/HNP_Data.csv")
.defer(d3.csv, "http://localhost:8000/HNP_Series.csv")
.await(analyze);
var dataToVis;
var array = []
function analyze(error,data,series) {
dataToVis = data[2];
console.log(JSON.stringify(dataToVis));
for (var key in dataToVis) {
if(!isNaN(key) && key.length >0) {
var p = new Object;
p.year = key;
p.frequency = p(dataToVis[key]);
array.push(p);
}
}
array.forEach(function(d){
d.year = d.year;
d.frequency = +d.frequency;
});
x.domain(data.map(function(d) { return d.year; }));
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
// add 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)" );
svg.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
svg.selectAll("bar")
.data(array)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.year); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); });
}
but I end up with this error.
Error: <rect> attribute y: Expected length, "NaN".
Error: <rect> attribute height: Expected length, "NaN".
I have been trying to add labels to my bar chart as described in this question:
Adding label on a D3 bar chart
However, I can get the labels to display, but not over the appropriate bar (they are all lined up over/ on the first bar). Any help would be greatly appreciated. Here is my code:
var cdata = { title: "Sample Chart", Pod: 10, WOSNF : 201.57, SNFW: 8.89, YTDTarget: 15.14, AnnualTarget: 22.10, Max: 250 }
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 500 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// Parse the categories
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 30]);
y.domain([0, 30]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
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 + ")");
d3.csv("data2.csv", function(error, data) {
data.forEach(function(d) {
d.value = +d.value;
console.log(d.value);
});
x.domain(data.map(function(d) { return d.Category; }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.style("text-anchor", "end")
.attr("x", width/2)
.attr("y", 30)
.attr("dx", ".71em")
.attr("transform", "translate(40,20)" )
;
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "translate(" + (width / 2) + ",-25)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "middle")
.style("font-size", "14pt")
.text("Sample Chart");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.style("fill-opacity", "0.5")
.attr("x", function(d) { return x(d.Category); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value) - 1;})
.attr("height", function(d) { return height - y(d.value);})
var yTextPadding = 20;
svg.selectAll("bartext")
.data(data)
.enter().append("text")
.attr("class", "bartext")
.attr("text-anchor", "middle")
.attr("fill", "black")
.attr("x", function(d, i) {
return x.rangeBand()/2;
})
.attr("y", function(d) {
return y(d.value);
})
.text(function(d){
return d.value;
});
});
var G3 = svg.append("g")
G3.append("line")
.attr("y1", y(cdata["YTDTarget"])-1)
.attr("y2", y(cdata["YTDTarget"])-1)
.attr("x1", 0)
.attr("x2", 500)
.attr("stroke-width", 2)
.attr("stroke", "black");
G3.append("text")
.attr("x",10)
.attr("y", y(cdata["YTDTarget"])+10)
.style("fill", "black")
.style("text-anchor", "start")
.text("RU YTD Target - " + cdata["YTDTarget"]);
var G4 = svg.append("g")
G4.append("line")
.attr("y1", y(cdata["AnnualTarget"])-1)
.attr("y2", y(cdata["AnnualTarget"])-1)
.attr("x1", 0)
.attr("x2", 500)
.attr("stroke-width", 2)
.attr("stroke", "black");
G4.append("text")
.attr("x", 10)
.attr("y", y(cdata["AnnualTarget"])+10)
.style("fill", "black")
.style("text-anchor", "start")
.text("RU Annual Target - " + cdata["AnnualTarget"]);
And here is the data:
Category,value
"Group1",27.2
"Group2",24.6
"Group3",27.1
The elements following the parsing of the data are to draw lines across the graph for reference.
Thanks!
You're currently setting the x position of the labels to half the width of the first bar (so they all end up on the left.
You want the x position of the bartext to start at the same spot as the current bar and add half the width of the bar:
.attr("x", function(d, i) {
return x(d.Category) + (x.rangeBand() / 2);
})
I have built a barchart with D3 but I'm running into these 2 minor issues which I am not be able to fix.
1) The first bar of the barchart overlaps the y axis
2) The labels of the y axis ticks are disappearing on the left side when the number(Volume) exceeds 1 million.
Here is a snapshot of what is happening:
Here's my D3 code:
function drawGraph(dataGraph){
if (dataGraph.length == 0){
$('#graph-container').append('<h3>No Data Match</h3>');
return;
}
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 900 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom,
padding = 15;
var max = d3.max(dataGraph, function(d) { return +d.VOLUME;} );
var maxDate = d3.max(dataGraph, function(d) { return +d.AS_OF_DATE;} );
var x = d3.scale.ordinal()
.domain(dataGraph.map(function(d) {return d.AS_OF_DATE;}))
.rangeRoundBands([0, (width- padding )], .1);
var y = d3.scale.linear()
.domain([0,max])
.range([height,0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient('bottom');
var yAxis = d3.svg.axis()
.scale(y)
.orient('left')
.ticks(10);
var svg = d3.select("#graph-container")
.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)
.selectAll("text")
.style("text-anchor", "end")
.style("color", "#333")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style("color", "#333")
.text("Volume");
svg.selectAll('.bar')
.data(dataGraph)
.enter().append('rect')
.attr('class', 'bar')
.attr("x", function(d) { return x(d.AS_OF_DATE); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.VOLUME); })
.attr("height", function(d) { return height - y(d.VOLUME); });
}
Problem:
I've got a D3.js scatter plot that has 16 different data sets, but it seems like D3 has only 10 different colours built-in before it repeats. You can see what I mean by clicking that link.
Code:
function updatePlot() {
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
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 + ")");
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.sepalLength = +d.sepalLength;
d.sepalWidth = +d.sepalWidth;
});
x.domain(d3.extent(data, function(d) { return d.sepalWidth; })).nice();
y.domain(d3.extent(data, function(d) { return d.sepalLength; })).nice();
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("HPF/LPF Intensity Ratio");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("HPF Intensity (relative units)")
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.sepalWidth); })
.attr("cy", function(d) { return y(d.sepalLength); })
.style("fill", function(d) { return color(d.species); });
var legend = svg.selectAll(".legend")
.data(color.domain())
.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 code is pretty much copy/paste from here with a little customisation in the areas of D3 that I understand)
Thanks!
This part of the docs has the answer: Ordinal-Scales#categorical-colors. Thanks to user and Lars Kotthoff!
Simply replaced category10 with category20.