D3 Map Showing up as Irregular Shape - javascript

I am trying to read a .json file into an HTML file using d3.
When I use one .json file -- for the entire US -- the map shows up fine. However, when I tried switching out the US file for a state of Wisconsin .json file it shows up like this...
Anyone know what the issue could be?
Here's the code:
<script>
var margin = {top: 20, left: 20, bottom: 20, right: 20}
height = 600-margin.top - margin.bottom,
width = 960 - margin.left - margin.right;
var svg2 = d3.select("#map2").append("svg")
.attr("height", height)
.attr("width", width)
.append("g")
.attr("transform", "translate(" + margin.left + "," +
margin.right + ")");
d3.queue()
.defer(d3.json, "wiscCountiesGeneralized.json")
.await(ready);
var projection2 = d3.geoAlbers()
.translate([width/2, height/1.5])
.scale(75)
var path2 = d3.geoPath()
.projection(projection2)
function ready (error, data) {
console.log(data)
var counties = topojson.feature(data,
data.objects.counties).features
console.log(counties)
svg2.selectAll(".counties")
.data(counties)
.enter().append("path")
.attr("class", "counties")
.attr("d", path2)
}
</script>

Related

states feature with topojson in d3js

I am really new into d3 and js. I wanted to make a choropleth map of the Us showing the different states. However something is not working since i don't get any path appended to my g object. Also the console.log(states) doesn't work. I'm pretty sure this is a newbie error and due to my lacks in js/d3. However i think i must use Promise.all since i want to add another csv file later on.
Thank you in advance!
Developer Tool
Below is the Code
//Standard Method to start our d3 visualization. For Maps the margin is not that important,but we make best practices
(margin = { top: 0, left: 0, right: 0, right: 0, bottom: 0 }),
(height = 400 - margin.top - margin.bottom),
(width = 800 - margin.left - margin.right);
var svg = d3
.select("#map")
.append("svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
//Read in our us Data
Promise.all([d3.json("us.json")]).then(([data]) => {
console.log(data)
});
var projection = d3
.geoAlbersUsa()
.translate([width / 2, height / 2])
.scale(100);
//create path of projection so that we can work with latidudes and longitudes
var path = d3.geoPath().projection(projection);
function ready(error, data) {
console.log(data)
var states = topojson.feature(data, data.objects.states).features;
console.log(states);
svg
.selectAll(".state")
.data(states)
.enter()
.append("path")
.attr("class", "state")
.attr("d", path);
}

How to add "source" caption and a small logo image under a chart in D3.js?

I'm making a chart in D3.js, but I need an expert help how to put a data "source" caption under the chart and a small image/logo.
This is the code:
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var margin = {top: 20, right: 30, bottom: 40, left: 90},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
// csv data
d3.csv("XYZ.csv", function(data) {
// Add X axis
var x = d3.scaleLinear()
.domain([0, 100])
.range([ 0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickFormat(function(d){
return "$" + d;
}).ticks(10))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Y axis
var y = d3.scaleBand()
.range([ 0, height ])
.domain(data.map(function(d) { return d.country; }))
.padding(.1);
svg.append("g")
.call(d3.axisLeft(y))
//Bars
svg.selectAll("myRect")
.data(data)
.enter()
.append("rect")
.attr("x", x(0) )
.attr("y", function(d) { return y(d.country); })
.attr("width", function(d) { return x(d.price); })
.attr("height", y.bandwidth() )
.attr("fill", "red")
})
</script>
the data points from the csv file are as follows: csv file data points with two columns "country" and "price"
Would you be able to help me?
Thanks!
Just add the image and caption as regular HTML. Your HTML will look like this:
<div id="my-dataviz">
<img src="imagefile.jpg">
<svg/>
<p class="caption">Your caption</p>
</div>
And then your d3 selection will look like this:
var svg = d3.select("#my_dataviz svg")

TopoJSON drawing solid rectangle despite using turf to rewind

I am currently trying to draw a map of the US with the counties-albers-10m.json file found on the topojson repo. I initially got a solid rectangle and, after changing fill to none, I am getting specks here and there. Going through stack, I found that the winding order may be wrong so I incorporated turf.js, but nothing is really changing. Here is the code:
var margin = {top: 0, left: 0, right: 0, bottom: 0},
height = 600 - margin.top - margin.bottom,
width = 1200 - margin.left - margin.right;
var svg = d3.select("#map")
.append("svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top +")");
d3.json("counties-albers-10m.json").then(function(data) {
console.log(data);
var projection = d3.geoAlbersUsa();
var path = d3.geoPath()
.projection(projection);
var counties = topojson.feature(data, data.objects.counties).features
console.log(counties)
counties.forEach(function(feature) {
feature.geometry = turf.rewind(feature.geometry, {reverse:true});
})
svg.selectAll(".county")
.data(counties)
.enter().append("path")
.attr("class", "county")
.attr("fill", "none")
.attr("stroke", "black")
.attr("d", path);
})
The dreaded black box

creating multi-line charts as a reusable component

I think I'm almost there. I have a working version for a single line that updates dynamically, but am having trouble getting to the multi-line part. I believe it has something to do with the way the data is being filtered at _selection.each. Not sure the best way to proceed from here though. The example found here (Drawing Multiple Lines in D3.js) seems to deal with this without much work.
Here is the jsfiddle for this, but the code is represented below as well:
http://jsfiddle.net/seoulbrother/NhK43/
Thanks in advance. Also, would love to hear best practices regarding this as well.
So if I have a page with a matrix where each row represents a time-series:
<html>
<body>
<div id="container"><div id="viz"></div></div>
</body>
</html>
<script type="text/javascript">
var matrix = [
[23,12,44,22,12,33,14,76,45,55,66,55],
[33,22,11,88,32,63,13,36,35,51,26,25]
];
</script>
I call this using:
mult_line = d3.graph.line(500, 250, "#viz");
d3.select("#container").datum(matrix).call(mult_line);
where d3.graph.line is:
d3.graph.line = function module(w, h, id) {
var svg;
var margin = {top: 10, right: 20, bottom: 20, left: 40},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
function chart(_selection) {
_selection.each(function(_data) {
console.log(_data);
var x = d3.scale.linear().domain([1, _data.length]).range([0, width]);
var y = d3.scale.linear().domain([0, 100]).range([height, 0]);
var xAxis = d3.svg.axis().scale(x).ticks(5).orient("bottom");
var yAxis = d3.svg.axis().scale(y).ticks(5).orient("left");
var line = d3.svg.line()
.x(function(d,i) { return x(i+1); })
.y(function(d) { return y(d); });
if (!svg){
svg = d3.select(id).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("path")
.attr("class","line")
.attr("d", line(_data));
svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y-axis")
.call(yAxis);
}
var line_m = d3.selectAll("path.line")
.data(_data);
line_m.transition()
.duration(1000)
.attr('d', line(_data));
line_m.enter().append("path")
.attr("d",line(_data));
update_axis();
function update_axis() {
d3.select(".x-axis").call(xAxis);
}
});
}
return chart;
}
I think there may be varying opinions about this, but I wouldn't use selection.datum() as the mechanism of passing data into the chart component. Instead, I would add a .data() setter method as a property of the multiline component. I would do the same for width, height, etc. This is the way d3's components are implemented (for example, check out the source code for the d3.svg.axis). Then your chart creation would look like this:
mult_line = d3.graph.line()
.width(500)
.height(250)
.id("#viz")
.data(matrix);
d3.select("#container").call(mult_line);
You can refine this so that there are 2 data-setting methods of multiline: .data() and .multilineData(). The first would expect data for a single line (an array) and the 2nd would expect an array of arrays (multiline). Internally, they'd always be represented as an array of arrays. That way, the chart drawing code always expects to draw multiline data, except sometimes the data has just one line.

Removing line elements in D3

I'm creating a line chart based on https://github.com/mbostock/d3/blob/master/examples/line/line.html .
var data = [
{x: 0, y: 3},
{x: 1, y: 4},
{x: 2, y: 5}
];
var margin = {top: 10, right: 10, bottom: 20, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var line = d3.svg.line()
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y); });
line.interpolate('monotone');
var svg = d3.select("#chart").append("svg")
.datum(data)
.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("path")
.attr("class", "line")
.attr("d", line);
How do I remove the last element from the path (i.e. delete a line segment)? Similar examples for removing elements involve changing the data array, and re-initializing via exit. In the case of 'circles' this looks something like:
data.shift();
var circles = svg.selectAll(".dot").data(data);
circles.exit().remove();
However this approach doesn't work with path. Any ideas?
Replace data.shift() with data = data.splice(0, data.length - 1)
array.splice(index , howMany[, element1[, ...[, elementN]]])
You could remove the last data element before passing it to d3. Your code would be clearer if you moved the call to .data() further down to where the paths are appended, as it is used only there, i.e. something like
data.shift();
svg.selectAll("path").data(data).enter()
.append("path")
.attr("class", "line")
.attr("d", line);

Categories

Resources