I was trying to make a grid of rectangles for a heatmap. But for some reason, my rectangles are obstructed by an unknown element:
I thought I accidentally created a rectangle but failed to find it. Where does this white block come from?
Below is a simplified code snippet that demonstrates the same issue.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Graph</title>
<script src="https://d3js.org/d3.v4.js" charset='utf-8'></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js" charset='utf-8'></script>
<script src="https://d3js.org/d3.v4.min.js" charset='utf-8'></script>
</head>
<body>
<svg width="700" height="700" class="Q2">
</svg>
<script type='text/javascript'>
d3.csv("https://91063e21-7b3e-460b-9992-db5d8294e143.filesusr.com/ugd/00e35d_3ff25a705bf649108058b5fd0f8a0506.csv?dn=monthStateGen.csv", DrawGrid);
function DrawGrid(error, data) {
var maxValue = 65000000;
var squareSize = 50;
var squareGap = 5;
var squareBevel = 5;
var monthNum = 12;
var stateNum = 5;
var offsetX = 30;
var height = stateNum * (squareSize + squareGap)
var width = monthNum * (squareSize + squareGap)
var svg = d3.select(".Q2")
.append("svg")
.attr("width", squareSize)
.attr("height", height);
var states = d3.map(data, function(d){return d.STATE;}).keys();
var month = d3.map(data, function(d){return d.MONTH;}).keys();
var x = d3.scaleBand()
.range([ 0, width ])
.domain(month);
var y = d3.scaleBand()
.range([ 0, height])
.domain(states);
svg.selectAll()
.data(data)
.enter()
.append("rect")
.attr("x", function(d) { return x(d.MONTH)+offsetX })
.attr("y", function(d) { return y(d.STATE) })
.attr("rx", 4)
.attr("ry", 4)
.attr("width", squareSize )
.attr("height", squareSize )
.attr('opacity', '0.8')
.style("fill", '#333' );
}
</script>
</body>
</html>
I've been changing a few things for you.
doctype
multiple d3 lib referencing
non-composing svg
the width of the svg, which should not only be the square size
<!DOCTYPE html>
<html>
<head>
<title>Graph</title>
<script src="https://d3js.org/d3.v4.min.js" charset='utf-8'></script>
</head>
<body>
<div class="Q2">
</div>
<script type='text/javascript'>
d3.csv("https://91063e21-7b3e-460b-9992-db5d8294e143.filesusr.com/ugd/00e35d_3ff25a705bf649108058b5fd0f8a0506.csv?dn=monthStateGen.csv", DrawGrid);
function DrawGrid(error, data) {
var squareSize = 50;
var squareGap = 5;
var squareBevel = 5;
var monthNum = 12;
var stateNum = 5;
var offsetX = 30;
var height = stateNum * (squareSize + squareGap)
var width = monthNum * (squareSize + squareGap)
var svg = d3.select(".Q2")
.append("svg")
.attr("width", width + (2 * offsetX))
.attr("height", height);
var states = d3.map(data, function(d){return d.STATE;}).keys();
var month = d3.map(data, function(d){return d.MONTH;}).keys();
var x = d3.scaleBand()
.range([ 0, width ])
.domain(month);
var y = d3.scaleBand()
.range([ 0, height])
.domain(states);
svg.selectAll()
.data(data)
.enter()
.append("rect")
.attr("x", function(d) { return x(d.MONTH) +offsetX })
.attr("y", function(d) { return y(d.STATE) })
.attr("rx", 4)
.attr("ry", 4)
.attr("width", squareSize )
.attr("height", squareSize )
.attr('opacity', '0.8')
.style("fill", '#333' );
}
</script>
</body>
</html>
I am new to D3 and I am trying to make a simple bar chart following an example in the "Interactive Data Visualization for the Web".
My data in csv format looks like this:
category,number
one,20
two,60
three,5
I am doing the following:
<script type="text/javascript">
//Width and height
var w = 500;
var h = 100;
var barPadding = 1;
var rowConverter = function(d) {
return {
category: d.category,
number: parseFloat(d.number)
};
}
var dataset;
d3.csv("barcharttest.csv", rowConverter).then (function(data) {
console.log(data);
dataset=data;
});
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return i * (w / dataset.number.length);
})
.attr("y", function(d) {
return h - (d.number * 4);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d.number * 4;
})
.attr("fill", "teal");
</script>
</body>
</html>
However, this fails to produce a bar chart.
Error on the console: bookcode.html:41 Uncaught TypeError: svg.selectAll(...).data(...).enter is not a function
I would greatly appreciate any suggestions.
I'm trying to get the rates data "JSON" from an API to be able to use the data in a graph. The graph itself functions once it gets the data right.
Is there a stage where I need to take the rates labels separately?
I am able to print out the rate in a test, but this means I had to define the currency:
//alert(data.rates.AUD);
This is how the JSON data looks:
// base "EUR"<br>
// date "2017-10-30"<br>
// rates <br>
// AUD 1.5148 <br>
// BGN 1.9558<br>
// BRL 3.779<br>
// CAD 1.4918<br
// CHF 1.1603
src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"
src ="https://d3js.org/d3.v4.min.js"
width = 600;
height = 450;
$.get(" http://api.fixer.io/latest ", function(data)
{
var width = 500;
var height = 500;
var ratesD = [];
for(var i = 0; i < data.length; i++)
{
ratesD.push(data[i].rates);
}
var widthScales = d3.scaleLinear()
.domain([0, d3.max(ratesD)])
.range([ 0, width]);
var canvas = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
canvas.selectAll("rectangels")
.data(data)
.enter()
.append("rect")
.attr("width", function(data) {return widthScales(data.rates);})
.attr("height", 20)
.attr("x", 0)
.attr("y", function(data, i){ return i*100;});
});
I am trying to create a bar chart with the dataset below. I am stuck on the part where the height[score] of the bar[country] is determined. How do I loop through the dataset to pull each score for a different country?
Any help would be greatly appreciated :)
var w = 500;
var h = 100;
var barPadding = 1;
var dataset = [
{"country":"Hong Kong","score":8.98},
{"country":"Singapore","score":8.54},
{"country":"New Zealand","score":8.19},
{"country":"Switzerland","score":8.09},
{"country":"Mauritius","score":8.98},
{"country":"United Arab Emirates","score":8.05},
{"country":"Canada","score":8.00},
{"country":"Australia","score":7.87},
{"country":"Jordan","score":7.86},
{"country":"Chile","score":7.84},
];
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("y", function(d) {
return h - (d * 4);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d * 4;
});
In D3, once you load the data through the .data(dataset) command, you can now access each record of the data by inserting the anonymous function function(d, i) { } as you have done in a few of your attributes.
Since your dataset is:
var dataset = [
{"country":"Hong Kong","score":8.98},
{"country":"Singapore","score":8.54},
{"country":"New Zealand","score":8.19},
{"country":"Switzerland","score":8.09},
{"country":"Mauritius","score":8.98},
{"country":"United Arab Emirates","score":8.05},
{"country":"Canada","score":8.00},
{"country":"Australia","score":7.87},
{"country":"Jordan","score":7.86},
{"country":"Chile","score":7.84},
];
each d is a object record e.g. {"country":"Singapore","score":8.54}, while i refers to the index of the object d returned e.g. 1 for our example of d used above.
To access the score of the object record d, this becomes simple Javscript object notation i.e. d.score.
Hence your .attr call should look like:
.attr("height", function(d) {
return d.score * 4;
});
Similarly, you can extract the other fields e.g. country with d.country if you intend to use it in .attr("text", function(d) { return d.country; });
This is the real beauty and power of D3. If you ever want to expand your visualization with more features that is obtained through your data, then all you have to make sure is that your dataset data contains more data attributes, and you can call them later as you iterate through the anonymous functions. And D3 is in the spirit of its name, truly being "data-driven"! :)
You will need to fix d to d.score.
If you want to show country text, write svg.selectAll("text") after svg.selectAll("rect").
Like this:
var w = 500;
var h = 100;
var barPadding = 1;
var dataset = [
{"country":"Hong Kong","score":8.98},
{"country":"Singapore","score":8.54},
{"country":"New Zealand","score":8.19},
{"country":"Switzerland","score":8.09},
{"country":"Mauritius","score":8.98},
{"country":"United Arab Emirates","score":8.05},
{"country":"Canada","score":8.00},
{"country":"Australia","score":7.87},
{"country":"Jordan","score":7.86},
{"country":"Chile","score":7.84},
];
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("y", function(d) {
return h - (d.score * 4);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d.score * 4;
});
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d.country;
})
.attr("transform", function(d, i) {
var barW = w / dataset.length;
return "translate(" +
( barW * i + barW / 2 + barPadding ) + "," +
( h - 5 ) +
")rotate(-90)";
})
.attr("font-size", "8pt")
.attr("fill", "white");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Something like
For( var i =0; i<dataset.length; i++){
// Dataset[i].country
// dataset[i].score
}
You have an array of objects
I updated my code to use the scale method in D3. However, since then my bar chart won't display. What is the cause of this issue?
var dataset = [ ];
for (var i = 0; i < 14; i++) {var newNumber = Math.round(Math.random() * 70);
dataset.push(newNumber);}
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var widthScale = d3.scale.linear()
.domain([0,d3.max(dataset)])
.range([0,w]);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", 3)
.attr("y", function (d,i) {return i* 36;})
.attr("width", function(d) {return widthScale;})
.attr("height", h / dataset.length - barPadding)
.attr("fill", function(d) {return "rgb(0, 0, " + (d * 10) + ")";});
A D3 scale is just a function translates values from a given input domain (your data values, 0 to max) to a specified output range (the width of your chart). Thus you have to apply the scale to your data, e.g. widthScale( d ). Right now you are assigning the widthScale function to the width attribute of your rect instead of the output value.
See the working fiddle: http://jsfiddle.net/S92u4/