D3 bar chart uncaught TypeError - javascript

I'm trying to make a d3 bar chart using d3 version 4 and it gives me the following error: Uncaught TypeError: d3.scaleOrdinal(...).domain(...).rangeBands is not a function, i added my code snippet, can anybody fix it for me?
var bardata = [20, 30, 95,15];
var height = 400,
width = 600,
barWidth = 50,
barOffset = 5;
var yScale = d3.scaleLinear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var xScale = d3.scaleOrdinal()
.domain(d3.range(0, bardata.length))
.rangeBands([0, width])
d3.select('#chart').append('svg')
.attr('width', width)
.attr('height', height)
.style('background', '#C9D7D6')
.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', '#C61C6F')
.attr('width', xScale.rangeBand())
.attr('height', function(d){
return yScale(d);
})
.attr('x', function(d,i){
return xScale(i);
})
.attr('y', function(d){
return height - yScale(d);
})
<!DOCTYPE html>
<html>
<head>
<title>Line Chart</title>
<meta charset="8-UTF">
<link rel="stylesheet" src="css/style.css"> </head>
<body>
<div class="container">
<h2>D3 Graphic</h2>
<div id="chart"></div>
</div>
<script src="js/d3.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>

In the (not so) new D3 v4:
The ordinal.rangeBands and ordinal.rangeRoundBands methods have been replaced with a new subclass of ordinal scale: band scales. (source)
Thus, you have to do three changes here:
scaleBand instead of scaleOrdinal
xScale.bandwidth() instead of xScale.rangeBands()
setting the padding in the scale
With those changes, this is your code:
var bardata = [20, 30, 95, 15];
var height = 400,
width = 600,
barWidth = 50,
barOffset = 5;
var yScale = d3.scaleLinear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var xScale = d3.scaleBand()
.domain(d3.range(0, bardata.length))
.padding(0.1)
.range([0, width])
d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
.style('background', '#C9D7D6')
.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', '#C61C6F')
.attr('width', xScale.bandwidth())
.attr('height', function(d) {
return yScale(d);
})
.attr('x', function(d, i) {
return xScale(i);
})
.attr('y', function(d) {
return height - yScale(d);
})
<script src="https://d3js.org/d3.v4.min.js"></script>

Related

bar chart not coinciding with axes in d3.js

I am trying to create a bar chart in d3.js and unfortunately, the bars are not on the axes. They are appearing somewhere else. Can you please point out what I am doing wrong here.
I think it has do with the placing of axes and all but I am unable to figure it out.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="rer"></div>
<script>
var width = 400, height = 400;
var data1 = { 2011: 9, 2012: 12, 2013: 10, 2014: 8, 2015: 12, 2016: 20 }
data_ready = d3.entries(data1);
var barColor = '#50740a';
var svg = d3.select("#rer")
.append("svg")
.attr("width", width)
.attr("height", height);
var xscale = d3.scaleBand()
.domain(data_ready.map((function (d) { return d.key; })))
.range([0, width - 100]);
var yscale = d3.scaleLinear()
.domain([0, d3.max(data_ready, function (d) { return d.value; })])
.range([height / 2, 0]);
var x_axis = d3.axisBottom().scale(xscale);
var y_axis = d3.axisLeft().scale(yscale);
svg.append("g")
.attr("transform", "translate(100, 20)")
.call(y_axis);
var xAxisTranslate = height / 2 + 10;
svg.append("g")
.attr("transform", "translate(100, " + xAxisTranslate + ")")
.call(x_axis);
svg.selectAll(".bar")
.data(data_ready)
.enter().append("rect")
.attr('class', 'bar')
.attr("x", function (d) { return xscale(d.key); })
.attr("y", function (d) { return yscale(d.value); })
.attr("width", xscale.bandwidth())
.attr("height", function (d) { return height - yscale(d.value); })
.attr("fill", barColor)
</script>
</body>
</html>
I tried to correct it and got the graph as below. Can someone please explain the attr ( transform, translate ) thing. This seems to be the issue. I did a trial and error method to place the position of the graph. Is there a better way to do this ?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="rer"></div>
<script>
var width = 400,
height = 400;
var data1 = {
2011: 9,
2012: 12,
2013: 10,
2014: 8,
2015: 12,
2016: 20
}
data_ready = d3.entries(data1);
var barColor = '#50740a';
var svg = d3.select("#rer")
.append("svg")
.attr("width", width)
.attr("height", height);
var xscale = d3.scaleBand()
.domain(data_ready.map((function(d) {
return d.key;
})))
.range([0, width - 100])
.padding(0.1);
var yscale = d3.scaleLinear()
.domain([0, d3.max(data_ready, function(d) {
return d.value;
})])
.range([height / 2, 0]);
var x_axis = d3.axisBottom().scale(xscale);
var y_axis = d3.axisLeft().scale(yscale);
svg.append("g")
.attr("transform", "translate(100, 10)")
.call(y_axis);
var xAxisTranslate = height / 2 + 10;
svg.append("g")
.attr("transform", "translate(100, " + xAxisTranslate + ")")
.call(x_axis);
svg.selectAll(".bar")
.data(data_ready)
.enter().append("rect")
.attr('class', 'bar')
.attr("x", function(d) {
return xscale(d.key);
})
.attr("y", function(d) {
return yscale(d.value);
})
.attr("width", xscale.bandwidth())
.attr("height", function(d) {
return height / 2 - yscale(d.value);
})
.attr("fill", barColor)
.attr("transform", "translate(100, 10)")
</script>
</body>
</html>

How to use rangeRound in scaleTime in d3 v4?

I am trying to create a divergent bar chart which uses time scale(date) as x-axis. I am having trouble using ScaleBands with date, the date labels are overlapping.
This is what I got so far. https://jsfiddle.net/14ch7yeo/ when I use scaleTime, Unfortunately, the graph does not load.
I need to use zoom and brush on this graph.
<!DOCTYPE html>
<meta charset="utf-8">
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var data = [{"Date":"2015-01-02T00:00:00.000Z","Buy":554646.5,"Sell":-406301.3547},{"Date":"2015-02-02T00:00:00.000Z","Buy":565499.5,"Sell":-673692.5697},{"Date":"2015-03-02T00:00:00.000Z","Buy":421954.5,"Sell":-571685.4629},{"Date":"2015-04-02T00:00:00.000Z","Buy":466242.0,"Sell":-457477.7121},{"Date":"2015-05-02T00:00:00.000Z","Buy":350199.7,"Sell":-579682.8772},{"Date":"2015-06-02T00:00:00.000Z","Buy":391035.1,"Sell":-338816.6205},{"Date":"2015-07-02T00:00:00.000Z","Buy":437644.6,"Sell":-502329.557},{"Date":"2015-08-02T00:00:00.000Z","Buy":291978.9,"Sell":-504067.0329},{"Date":"2015-09-02T00:00:00.000Z","Buy":360913.8,"Sell":-489519.6652},{"Date":"2015-10-02T00:00:00.000Z","Buy":505799.1,"Sell":-723353.7089},{"Date":"2015-11-02T00:00:00.000Z","Buy":510691.0,"Sell":-374061.8139},{"Date":"2015-12-02T00:00:00.000Z","Buy":527757.1,"Sell":-597800.0116},{"Date":"2016-01-02T00:00:00.000Z","Buy":564799.1,"Sell":-451779.1593},{"Date":"2016-02-02T00:00:00.000Z","Buy":336533.7,"Sell":-522601.1707},{"Date":"2016-03-02T00:00:00.000Z","Buy":460684.6,"Sell":-643556.0079999999},{"Date":"2016-04-02T00:00:00.000Z","Buy":428388.1,"Sell":-349216.2376},{"Date":"2016-05-02T00:00:00.000Z","Buy":525459.5,"Sell":-597258.4075},{"Date":"2016-06-02T00:00:00.000Z","Buy":677659.1,"Sell":-513192.107},{"Date":"2016-07-02T00:00:00.000Z","Buy":365612.8,"Sell":-287845.8089},{"Date":"2016-07-03T00:00:00.000Z","Buy":358775.2,"Sell":-414573.209}]
var parseTime = d3.utcParse("%Y-%m-%dT%H:%M:%S.%LZ");
data.forEach(d => {
d["Date"] = parseTime(d["Date"]);
})
var series = d3.stack()
.keys(["Buy", "Sell"])
.offset(d3.stackOffsetDiverging)
(data);
var svg = d3.select("svg"),
margin = {top: 20, right: 30, bottom: 30, left: 60},
width = +svg.attr("width"),
height = +svg.attr("height");
var x = d3.scaleBand()
.domain(data.map(function(d) { return d['Date']; }))
.rangeRound([margin.left, width - margin.right])
.padding(0.1);
var y = d3.scaleLinear()
.domain([d3.min(series, stackMin), d3.max(series, stackMax)])
.rangeRound([height - margin.bottom, margin.top]);
var z = d3.scaleOrdinal()
.range(["green","red"]);
svg.append("g")
.selectAll("g")
.data(series)
.enter().append("g")
.attr("fill", function(d) { return z(d.key); })
.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr("width", x.bandwidth)
.attr("x", function(d) { return x(d.data["Date"]); })
.attr("y", function(d) { return y(d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[1]); })
svg.append("g")
.attr("transform", "translate(0,"+ (height-margin.top) + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
function stackMin(serie) {
return d3.min(serie, function(d) { return d[0]; });
}
function stackMax(serie) {
return d3.max(serie, function(d) { return d[1]; });
}
</script>
d3.scaleTime has to be treated differently on a number of fronts.
The scale doesn't take padding as an argument:
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.Date; }))
.rangeRound([margin.left, width - margin.right]);
Time is continuous rather than discrete, so the widths of the bars need to be calculated manually, as a ratio of rect and series.length. I got this to work, but maybe you want something more elegant:
.attr("width", width/series.length - 450)

D3 bar chart vertical axis

I'm trying to do a bar chart using d3.js version 4, I'm trying to make the vertical axis and it gives me the following error: Uncaught Error at Bn (d3.min.js:2) at Kn.vp [as ease] (d3.min.js:5) at main.js:88
here is my code:
var bardata = [];
for (var i=0; i < 20; i++){
bardata.push(Math.random())
}
bardata.sort(function compareNumbers(a,b){
return a -b;
})
var height = 400,
width = 600,
barWidth = 50,
barOffset = 5;
var tempColor;
var yScale = d3.scaleLinear()
.domain([0, d3.max(bardata)])
.range([0, height]);
var xScale = d3.scaleBand()
.domain(d3.range(0, bardata.length))
.padding(0.1)
.range([0, width]);
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('padding', '0 10px')
.style('background', 'white')
.style('opacity', 0)
var myChart = d3.select('#chart').append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.style('background', '#C9D7D6')
.selectAll('rect').data(bardata)
.enter().append('rect')
.style('fill', '#C61C6F')
.attr('width', xScale.bandwidth())
.attr('x', function(d, i) {
return xScale(i);
})
.attr('height', 0)
.attr('y', height)
.on('mouseover', function(d){
d3.select(this)
.style('opacity', 0.5)
})
.on('mouseleave', function(d){
d3.select(this)
.style('opacity', 1)
})
.on('mouseover', function(d){
tooltip.transition()
.style('opacity', 0.9)
tooltip.html(d)
.style('left', (d3.event.pageX - 35) + 'px')
.style('top', (d3.event.pageY - 30) + 'px')
tempColor = this.style.fill;
d3.select(this)
.style('opacity', 0.5)
.style('fill', 'yellow')
})
.on('mouseleave', function(d){
tempColor = this.style.fill;
d3.select(this)
.style('opacity', 1)
.style('fill', '#C61C6F')
})
myChart.transition()
.attr('height', function(d){
return yScale(d);
})
.attr('y', function(d){
return height - yScale(d);
})
.delay(function(d, i){
return i * 20;
})
.duration(1000)
.ease('elastic')
var vAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.ticks(10)
var vGuide = d3.select('svg').append('g')
vAxis(vGuide)
vGuide.attr('transform', 'translate(35,0)')
<!DOCTYPE html>
<html>
<head>
<title>Line Chart</title>
<meta charset="8-UTF">
<link rel="stylesheet" src="css/style.css"> </head>
<body>
<div class="container">
<h2>Bar Chart</h2>
<div id="chart"></div>
</div>
<script src="js/d3.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
Instead of
myChart.transition()
.attr('height', function(d){
return yScale(d);
})
.attr('y', function(d){
return height - yScale(d);
})
.delay(function(d, i){
return i * 20;
})
.duration(1000)
.ease('elastic')//INCORRECT
It should have been
myChart.transition()
.attr('height', function(d){
return yScale(d);
})
.attr('y', function(d){
return height - yScale(d);
})
.delay(function(d, i){
return i * 20;
})
.duration(1000)
.ease(d3.easeElastic)
working code here

Y Axis not displaying for scatter plot with d3 v4

I am trying to create a scatter plot with d3.js (v4). I am a newbie in d3, and thanks to the limited documentation of examples with v4, am struggling to create the plot (already have asked here once before). My code is given below:
const margin = { top: 100, right: 50, left: 50, bottom: 50};
const width = 1300 - margin.right - margin.left;
const height = 1250 - margin.top - margin.bottom;
d3.csv("http://localhost:9000/data.csv", (error, data) => {
if (error) throw error;
const x = (d) => d["Category"];
const xScale = d3.scalePoint()
.domain(data.map((d) => d["Category"]))
.range([0, width]);
const xMap = (d) => xScale(x(d));
const xAxis = d3.axisBottom().scale(xScale);
// Plotting Score 1 for now
const y = (d) => d["Score 1"];
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, y)])
.range([height, 0]);
const yMap = (d) => yScale(y(d))
const yAxis = d3.axisLeft().scale(yScale);
const svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.append('g')
.attr('class', 'axis axis--x')
.call(xAxis)
.attr('transform', 'translate(0, 800)')
.append('text')
.attr('class', 'label')
.attr('x', width)
.attr('y', -6)
.style('text-anchor', 'middle')
.text('Category');
svg.append('g')
.attr('class', 'axis axis--y')
.call(yAxis)
.attr('transform', 'rotate(-90)')
.attr('y', 0 - margin.left)
.attr('x', 0 - (height/2))
.attr("dy", "1em")
.style('text-anchor', 'middle')
.text('Score');
svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('class', 'dot')
.attr('cx', xMap)
.attr('cy', yMap)
.attr('r', 3.5)
.attr('fill', 'red');
});
A few lines of data.csv are given:
Name,Category,Score 1,Score 2,Score 3,Average score
A1_P1,A01,2.3,2.4,4.1,2.4
A2_P1,A02,1.4,1.5,2.4,1.5
A3_P1,A03,0.9,0.9,0.9,0.9
A4_P1,B01,1.5,1.5,1,1.5
A5_P1,B02,1.2,1.2,1.4,1.2
A6_P1,B03,1,1,1.1,1
A7_P1,C01,1.6,1.2,1,1.2
A8_P1,C02,1.2,1.2,0.9,1.2
A9_P1,C03,1.1,1.1,1,1.1
A10_P1,D01,1.5,1.6,1.1,1.5
The x-axis is showing (but not the 'Category' label), and even more importantly, the y-axis is not showing at all. The points themselves are being shown correctly, though. Does anyone know what is wrong with my y-axis setting and axis labels? Thanks in advance!
When I start a new chart with d3, I find it best to start with a known simple set-up example to place my drawing g, axis, etc... This is my usual starting point.
That said, here's list of issues I see in your chart:
Not placing x-axis dynamically.
svg container is sized wrong and ends up on top of axis.
Attempting to append a text axis label to y axis but you never actually append the text (and then apply attributes and styling to the axis itself instead of that missing text element).
Cleaning this all up looks like this:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
const margin = {
top: 100,
right: 50,
left: 50,
bottom: 50
};
const width = 500 - margin.right - margin.left;
const height = 500 - margin.top - margin.bottom;
//d3.csv("data.csv", (error, data) => {
// if (error) throw error;
var data = [{"Name":"A1_P1","Category":"A01","Score 1":"2.3","Score 2":"2.4","Score 3":"4.1","Average score":"2.4"},{"Name":"A2_P1","Category":"A02","Score 1":"1.4","Score 2":"1.5","Score 3":"2.4","Average score":"1.5"},{"Name":"A3_P1","Category":"A03","Score 1":"0.9","Score 2":"0.9","Score 3":"0.9","Average score":"0.9"},{"Name":"A4_P1","Category":"B01","Score 1":"1.5","Score 2":"1.5","Score 3":"1","Average score":"1.5"},{"Name":"A5_P1","Category":"B02","Score 1":"1.2","Score 2":"1.2","Score 3":"1.4","Average score":"1.2"},{"Name":"A6_P1","Category":"B03","Score 1":"1","Score 2":"1","Score 3":"1.1","Average score":"1"},{"Name":"A7_P1","Category":"C01","Score 1":"1.6","Score 2":"1.2","Score 3":"1","Average score":"1.2"},{"Name":"A8_P1","Category":"C02","Score 1":"1.2","Score 2":"1.2","Score 3":"0.9","Average score":"1.2"},{"Name":"A9_P1","Category":"C03","Score 1":"1.1","Score 2":"1.1","Score 3":"1","Average score":"1.1"},{"Name":"A10_P1","Category":"D01","Score 1":"1.5","Score 2":"1.6","Score 3":"1.1","Average score":"1.5"}];
const x = (d) => d["Category"];
const xScale = d3.scalePoint()
.domain(data.map((d) => d["Category"]))
.range([0, width]);
const xMap = (d) => xScale(x(d));
const xAxis = d3.axisBottom().scale(xScale);
// Plotting Score 1 for now
const y = (d) => d["Score 1"];
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, y)])
.range([height, 0]);
const yMap = (d) => yScale(y(d))
const yAxis = d3.axisLeft().scale(yScale);
const svg = d3.select('body')
.append('svg')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
svg.append('g')
.attr('class', 'axis axis--x')
.call(xAxis)
.attr('transform', 'translate(0,' + height + ')')
.append('text')
.attr('class', 'label')
.attr('x', width)
.attr('y', -6)
.style('text-anchor', 'middle')
.text('Category');
svg.append('g')
.attr('class', 'axis axis--y')
.call(yAxis)
.append("text")
.attr('transform', 'rotate(-90)')
.attr('y', 0 - margin.left)
.attr('x', 0 - (height / 2))
.attr("dy", "1em")
.style('text-anchor', 'middle')
.text('Score')
.style('fill', 'black')
svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('class', 'dot')
.attr('cx', xMap)
.attr('cy', yMap)
.attr('r', 3.5)
.attr('fill', 'red');
//});
</script>
</body>
</html>

D3.js: Elements don't have any width

I'm trying to append four rectto my svg. I can see them appended in chrome's dev tools. However, they're never rendered because it seems I have an issue with passing on the width value.
Besides, in version 3 of D3 I receive the following error message in the browser:
d3.v3.min.js:1 Error: attribute width: Expected length, "NaN".
There's no error message in version 4.
Here's my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test</title>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script type="text/javascript">
var data = [20,3,60,800];
var width = 500,
height = 500;
var widthScale = d3.scale.linear()
.domain([0, 80])
.range(0, width);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var bars = svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function (d) { return widthScale(d); } )
.attr("height", 50)
.attr("fill", "steelblue")
.attr("y", function (d, i) { return i * 100});
</script>
</body>
</html>
The only difference between v3 and v4 is this line (scaleLinear):
var widthScale = d3.scaleLinear().domain([0, 80]).range(0, width);
Any help highly appreciated.
range has to be an array. The documentation is clear:
linear.range([values]):
If values is specified, sets the scale's output range to the specified array of values
So, instead of:
.range(0, width);
It should be:
.range([0, width]);
If you use .range(0, width) D3 v3.x returns a NaN, and you see in the console:
Error: attribute width: Expected length, "NaN".
However, D3 v4.x returns undefined, and you see no error message in the console.
Here is your working code:
var data = [20,3,60,800];
var width = 500,
height = 500;
var widthScale = d3.scale.linear()
.domain([0, 80])
.range([0, width]);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var bars = svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function (d) { return widthScale(d); } )
.attr("height", 50)
.attr("fill", "steelblue")
.attr("y", function (d, i) { return i * 100});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Categories