D3.js does not display anything on the screen - javascript

I'm trying to use D3.js but I can not. I have the code below, but it does not print the map of Brazil. The screen does not show any errors, what could it be? My file "meso.json" is in topojSON format but it transforms the topojSON into GeoJson already in the d3.js code:
<html>
<head>
<title>D3.js</title>
<meta charset="utf-8" />
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/queue.v1.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
var width = 900,
height = 650;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var projection = d3.geo.mercator()
.center([55,10])
.scale(750);
var path = d3.geo.path()
.projection(projection);
queue()
.defer(d3.json, "topo/meso.json")
.await(ready);
function ready(error, br_mesos){
if(error) return console.error(error);
var mesos = topojson.feature(br_mesos, br_mesos.objects.meso);
svg.append("path")
.datum(mesos)
.attr('d', path)
.attr('class', 'mesos');
}
</script>
</head>
<body>
</body>
</html>

Please change all your imports from http to https as some browsers block http.
for eg: change <script src="http://d3js.org/topojson.v1.min.js"></script>
to <script src="https://d3js.org/topojson.v1.min.js"></script> and similarly for all.

Related

How do I create axes from categorical and numerical data using d3.js (version 7.0.0)?

Context: I am a beginner in d3.js and have been at this problem for a few days; I have gone through many solutions pertaining to similar problems on here but even though I've replicated the solutions as closely as possible, the issue persists.
I'm trying to create a bar chart with both axes using this simple CSV file:
Food,Yummy
Apples,6
Green Beans,10
Egg Salad Sandwich, 8
Cookies, 2
Liver,1
Burrito,5
I've tried using the following code to create the axes of a bar chart (x-axis: Food, y-axis: Yummy):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Loading data from a CSV file</title>
<script type="text/javascript" src="../d3.js"></script>
</head>
<body>
<script type="text/javascript">
//Defining svg dimensions
width = 250;
height = 600;
margin = 20;
//Creating svg element
var svg = d3.select("body")
.append("svg")
.attr("height", height)
.attr("width", width);
//Loading csv data
rowConverter = function(d) {
return {
Food: d.Food,
Yummy: +d.Yummy
};
}
data = d3.csv("food.csv", rowConverter).then(function(data) {
console.log(data);
});
//Creating scales for x and y axis
var xSxale = d3.scaleBand()
.domain(data.map(function(d) {return d.Food;}))
.range([0, w-margin]);
var maxYummy = d3.max(data, function(d) {return +d.Yummy;});
var yScale = d3.scaleLinear()
.domain([0, maxYummy])
.range([h-margin, 0]);
</script>
</body>
</html>
For the x-axis, I'm getting the following error: "data.map is not a function". I can't find any other way to get the different Food labels onto the x-axis.
For the y-axis, I'm getting the following error: "Uncaught TypeError: values is not iterable
at Object.max$3 [as max] (d3.js:641)
at (index):39" which seems to be pertaining to the d3.max() function.
I'm unclear as to why both errors are existing since I've seen them accepted as solutions on other questions. Any help would be much appreciated by this beginner developer. Thanks so much in advance.

D3 and Leaflet - svg circles not showing

I am trying to draw SVG circles on a map background, but while they are showing up in the elements (using Chrome Dev tools) they are not shown on the page. What am I missing here, why are they hidden?
I have tried to change the fill, opacity of the map and of the circle but I can't figure out why it isn't rendering?
My code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Leaflet and D3 map</title>
<link rel="stylesheet" href="../leaflet.css" />
<script type="text/javascript" src="../leaflet.js"></script>
<script type="text/javascript" src="../d3.js"></script>
<style type="text/css">
#map{
width: 700px;
height: 600px;
}
</style>
</head>
<body>
<div id="map"></div>
<script type="text/javascript">
//
// LOAD THE MAP FROM MAPBOX & LEAFLET
//
var map = L.map("map").setView([50.0755,14.4378], 12);
mapLink = 'Mapbox';
L.tileLayer (
"link to mapbox",{
attribution:"© " + mapLink + " Contributors",
maxZoom:20,
}).addTo(map);
//
// Create the SVG layer on top of the map
//
L.svg().addTo(map);
// Create the standard variables selecting the SVG in the map element
var svg = d3.select("#map").append("svg");
var g = svg.append("g");
//Load the coordinate for the circle
var objects = [ {"circle":{"coordinates":[50.0755,14.4378]}}];
//Loop through to create a LatLng element that can be projected onto Leaflet map
for(var i = 0;i<objects.length;i++){
objects[i].LatLng = new L.LatLng(objects[i].circle.coordinates[0], objects[i].circle.coordinates[1])
};
//Create the circle object and store it in features
var feature = g.selectAll("circle")
.data(objects)
.enter()
.append("circle")
.style("fill", "red")
.attr("r", 20);
//Make the circle dynamic, by calling the update function whenever view is view is reset
map.on("viewreset", update)
//Call the update also on first load of the web page
update();
//Updates the position of the circle every time the map is updated
function update(){
feature.attr("transform",
function(d){
return "translate("+
map.latLngToLayerPoint(d.LatLng).x+","+
map.latLngToLayerPoint(d.LatLng).y+")";
})
};
</script>
</body>
</html>
As you note, your circle is appended:
But, it is invisible not because of opacity or color, but because you don't set the dimensions of the svg. With default dimensions of the svg, your circle is beyond its border and consequently hidden (it resides in the middle of the map, at [350,300], while the default size of an svg is 300x150 likely browser dependent). Try:
var svg = d3.select("#map")
.append("svg")
.attr("width",700)
.attr("height",600)
As your map is 700 pixels across and 600 pixels high.

Unexpected lines/polygons when converting JSON to topoJSON

I want to display the topoJSON on a leaflet map with d3. Doing that, I follow this example hosted on GitHub.
That is the code I derived from the gitHub example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css">
<script type="text/javascript" src="https://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="http://d3js.org/topojson.v1.min.js"></script>
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
</head>
<body>
<div id="map" style="width:600px; height:600px;"></div>
<script>
var map = new L.Map("map", {
center: [37.8, -96.9],
zoom: 4
})
.addLayer(new L.TileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"));
var svg = d3.select(map.getPanes().overlayPane).append('svg');
var g = svg.append('g').attr('class', 'leaflet-zoom-hide');
d3.json("pathToTopotJson", function(error, collection) {
if (error) throw error;
console.log(collection)
var bounds = d3.geo.bounds(topojson.feature(collection, collection.objects.collection));
var path = d3.geo.path().projection(projectPoint);
var feature = g.selectAll('path')
.data(topojson.feature(collection, collection.objects.collection).features)
.enter()
.append('path');
map.on('viewreset', reset);
reset();
// Reposition the SVG to cover the features.
function reset() {
var bottomLeft = projectPoint(bounds[0]),
topRight = projectPoint(bounds[1]);
svg.attr('width', topRight[0] - bottomLeft[0])
.attr('height', bottomLeft[1] - topRight[1])
.style('margin-left', bottomLeft[0] + 'px')
.style('margin-top', topRight[1] + 'px');
var translation = -bottomLeft[0] + ',' + -topRight[1];
g.attr('transform', 'translate(' + -bottomLeft[0] + ',' + -topRight[1] + ')');
feature.attr('d', path);
}
// Use Leaflet to implement a D3 geographic projection.
function projectPoint(x) {
var point = map.latLngToLayerPoint(new L.LatLng(x[1], x[0]));
return [point.x, point.y];
}
})
</script>
The topoJSON gets displayed. But, with unexpected Polygons/Lines:
When I display the JSON the polygons/lines are not there:
Whats going wrong with topoJSON? Is it something in my code or did the converting go wrong?
Whats going wrong with topoJSON? Is it something in my code or did the converting go wrong?
There's nothing wrong, that is a common artifact when a polygon crosses the antimeridian.
Reproject your data to a different map projection to avoid the antimeridian altogether, or use the --spherical and --cartesian topojson command-line options to work around the problem.
You should do a bit of research into antimeridian crossings. Also, try isolating the problematic geometries (i.e. russia), and seeing if that geometry alone gets transformed to TopoJSON and displayed in a proper manner. Isolating problematic geometries will make your life easier, and will make bugs more apparent.

Why does a <h2> Header clip the succeeding SVG element?

I tried a basic visualization with d3.js and dimple from udacity, however, I observe an effect I can't explain:
I run a simple dimple.js visualization which is embedded in an svg element which works fine.
When I preceed the svg element with a header, ... - see line 27
d3.select("body").append("h2").text("World Cup Attendance");
...the chart within the svg element seems to get translated and clipped at the bottom.
Why does adding this line alter the chart?
To my understanding the SVG element is an independent element which has its own relative coordinate system - not affected by preceding html elements...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://dimplejs.org/dist/dimple.v2.1.2.min.js"></script>
<style>
circle.dimple-series-1 {
fill: red;
}
</style>
<script type="text/javascript">
function draw(data) {
/*
D3.js setup code
*/
"use strict";
var margin = 75,
width = 1400 - margin,
height = 600 - margin;
// this line moves the labels of the x axis
d3.select("body").append("h2").text("World Cup Attendance");
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin)
.attr("height", height + margin)
.append('g')
//.attr("transform", "translate(0,-30)")
.attr('class','chart');
var data = [
{ "year":"1980", "attendance":245000 },
{ "year":"1984", "attendance":245000 },
{ "year":"1988", "attendance":304400 }
];
/*
Dimple.js Chart construction code
*/
var myChart = new dimple.chart(svg, data);
var x = myChart.addTimeAxis("x", "year");
myChart.addMeasureAxis("y", "attendance");
x.dateParseFormat = "%Y";
x.tickFormat = "%Y";
// x.timeInterval = 4;
myChart.addSeries(null, dimple.plot.line);
myChart.addSeries(null, dimple.plot.scatter);
myChart.draw();
};
</script>
</head>
<body>
<script type="text/javascript">
/*
Use D3 (not dimple.js) to load the TSV file
and pass the contents of it to the draw function
*/
draw();
// d3.tsv("world_cup.tsv", draw);
</script>
</body>
</html>
I am going to guess it's because of this dimple method, "dimple._parentHeight". It calculates the height of the parent element of the svg and has a workaround for a firefox issue, so you could see a difference based on the container of the svg (body, in this instance) having or not having another element in it.
Your best bet (and what I've done for a similar reason) is to wrap the svg inside a div which will compute the height correctly :
var svg = d3.select("body")
.append("div")
.append("svg")

Path not showing in d3.js topoJson graph

I am trying to draw a map using topoJson so I followed this example
http://bl.ocks.org/mbostock/4122298
but I am not getting anything drawn.
here's what i wrote
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<style>
path {
fill: #ccc;
stroke: #fff;
stroke-width: .5px;
}
path:hover {
fill: red;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 500;
var path = d3.geo.path();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("tunisia.json", function(error, topology) {
console.log(topology);
svg.selectAll("path")
.data(topojson.feature(topology, topology.objects.governorates).features)
.enter().append("path")
.attr("d", path);
});
</script>
</body>
</html>
After some debugging it turns out that the path in my case is added as follows:
<svg width="960" height="500">
<path></path>
<path></path>
</svg>
whereas it should normally be like this:
<svg width="960" height="500">
<path d="M183.85631949544694,17.16574961388676L184.64695256075555,18.261986556132797L184.24437929962187,21.436416964644536L184.9109502450185,22.72190753660925L183.42733139583214,23.600229178621248L181.43637647772152,23.38526266060535L162.4858998398068,18.04698631290296L162.95134674943927,16.322885588815097L161.24381018256219,15.20848145955324L160.04585728433227,11.701769628478132L161.0879861841512,10.793553936506555L172.9773901748378,14.256236175137701Z"></path>
</svg>
here is the data I am using:
https://raw.githubusercontent.com/mtimet/tnacmaps/master/topojson/tunisia.json
could you please check what I am doing wrong
There is no problem with your json file.
The issue you are having is that you are not defining a projection for your d3.geo.path() which means it falls back to the default. According to the documentation linked above:
#d3.geo.path()
Creates a new geographic path generator with the default settings: the albersUsa projection and a point radius of 4.5 pixels.
Your geo data is for a map of Tunisia, so an albersUsa projection won't contain any of the coordinates in your dataset. That is why the path data is empty in your output.
To fix this, you need to define a projection. You can do this when you load your data, and you can use d3.geo.bounds(), passing in your featureCollection to find the geographic boundaries of your data.
var featureCollection = topojson.feature(topology, topology.objects.governorates);
var bounds = d3.geo.bounds(featureCollection);
Then from these boundaries, you can calculate the center of your featureCollection:
var centerX = d3.sum(bounds, function(d) {return d[0];}) / 2,
centerY = d3.sum(bounds, function(d) {return d[1];}) / 2;
Then you can use this to center your projection. For example, if you're using a mercator projection, you could do the following:
var projection = d3.geo.mercator()
.scale(3000)
.center([centerX, centerY]);
The choice of a scale of 3000 is arbitrary, it just seemed to work well in this case, tweak it to whatever works for you.
Finally, you need to set the .projection() of your path to the projection you made, before actually creating the svg paths.
path.projection(projection);
svg.selectAll("path")
.data(featureCollection.features)
.enter().append("path")
.attr("d", path);
HERE is a working example using your data.

Categories

Resources