scaling problem with d3j.js geo map visualisation with topojson file - d3.js

I use d3 version 4.0.0. and topojson.min.js to produce a map using german topo json data. I achieved to get the map on the browser however map appears very small.
I tried many ways to scale it but could not achieve to enlarge the size of the map.
I tried scaling with 1)command line tool, 2)in code and 3)in json data but none of them worked for me.
I tried command line tool as below but it produces file with null
geoproject 'd3.geoAlbers().center([0, 54.4]).rotate([4.4, 0]).parallels([50, 60]).scale(1200 * 3).translate([960 / 2, 600 / 2])' < germany.json > germany_scaled1.json
I tried same thing directly in the code with many ways but didnt work. For example below code gives undefined error for geo
var projection = d3.geoAlbers().parallels([50, 60]).translate([960 / 2, 600 / 2]).center([0, 54.4]).scale(1200 * 200)
var path = d3.geo.path().projection(projection);
// this is for render the map
var update = svg.selectAll('path')
.data(topoData)
var enter = update.enter()
.append('path')
update.merge(enter)
.attr('d', path) //d3.geoPath())
.attr('fill', function(d) {
return d3.interpolateBuGn(d.matchesPercent / maxMatch + 0.2);
});
I also tried same thing directly in json file with Transform but it did not work either
added this
"transform":{"scale":[5.0,5.00],"translate":[80.0,30.00],"center":[0.0,54.4]}
I hope someone will help me to scale my map

Related

d3 multiple different graticules

I am trying to create a "proper" version of the logo at IFMMS Logo
using the graticule feature of d3.js.
At https://gist.run/?id=22361573b05b541ac9799037116aea8d you'll find the current state of the code - specifically version https://gist.run/?id=22361573b05b541ac9799037116aea8d&sha=dd6aef5c64e3ac4c1c917fd5e3c7bbf4b91c75a8
In a loop i am trying to set the graticule steps for different scales of the logo draft.
var lonsteps=6+col*2;
var latsteps=10;
var title='IFMMS Logo';
createLogo(title,id,cx,cy,scale,15,lonsteps,latsteps,debug);
in the "createLogo" function i am using these steps as outlined in the answer:
https://stackoverflow.com/a/19033063/1497139
I get
instead of
so instead of having 6/8/10 steps for the longitudinal grid lines I get three times 6 steps. It seems as if the first setting "overrides" all others although i assign different values.
What is causing this and how can it be fixed?
If you pass a parameter (svgid) to a function use it and don't use the global variable (id) with the same value.
function createLogo(title,svgid,cx,cy,scale,strokeScaleFactor,lonsteps,latsteps,debug) {
// ...
ggraticule.selectAll("path.feature"+svgid)
.data(graticule.lines)
.enter().append("path")
.attr("class", "feature"+svgid)
.attr("d", path);
// ...
}
One indication of the problem can be that your scale is not working.
The reason a HTML ID should be unique.
fix it by making the graticule defs id unique and use this new id.
var ggraticule=defs.append("g")
.attr("id","graticule-"+svgid)
.attr("class", "graticule")
.attr("stroke-width",scale/strokeScaleFactor);
// ...
use(svg,"graticule-"+svgid);
You still have a problem with the background, choose a color and see the effect.
In D3 v5+ you can use the step method on your geoGraticules like so:
var graticules = d3.geoGraticule().step([15, 15])
The default step is 10° and 10° for longitude and latitude.

TopoJSON map not rendering properly using D3

I've downloaded this map of Great Britain and Ireland from Highcharts and converted from GeoJSON to TopoJSON format (topojson -o input output) but it just renders as a black box. I'm following the famous 'Let's make a map' tutorial:
var container = d3.select( "#container" );
var margin = 20,
width = parseInt(container.style( "width" )),
height = parseInt(container.style( "height" ));
var projection = d3.geo.mercator()
.scale(50);
var path = d3.geo.path()
.projection(projection);
var svg = container.append("svg")
.attr("width", width)
.attr("height", height);
d3.json("http://www.lenart.pl/assets/codepen/gb_all_ireland_topo.json", function(error, gb) {
svg.append("path")
.datum(topojson.feature(gb, gb.objects.gb_all_ireland_geo))
.attr("d", path);
});
http://codepen.io/znak/pen/rVYbNB
I've previewed my TopoJSON file with http://jsoneditoronline.org and found the relevant object containing geometries (I think) but it doesn't work.
My ultimate goal is to visualise an interactive (administrative) map of GB & I. Thanks.
I believe the first spot of bother is the download from Highcharts--it seems to be in a projection that is not wgs84. So the coordinates given are not latitudes and longitudes. If you look at the beginning of highcharts.com/mapdata/custom/gb-all-ireland.geo.json you'll see a few "crs" keys, and mention of "EPSG:7405".
You can convert to wgs84 several ways, including:
ogr2ogr -f geojson eire_4326.geojson gb-all-ireland.geo.json -t_srs epsg:4326 -s_srs epsg:7405
You could then convert to topojson and pick up where you left off.
It's also important to realize that small changes in the scale and center values of the d3 projections can have big impacts.
If you're not tied to Highcharts, it's probably better to get data that's already in wgs84, like http://www.naturalearthdata.com/ or even use a more comprehensive library and data like mapsense https://developer.mapsense.co/tileViewer/. (Disclosure: I work at mapsense.)

Creating a whole new world with shapefile format of different layers in one file

I want to create a new world map and using D3.js with topojson and if possible QGIS. So at the end I need one shapefile that contains countrys, rivers, and so on. After creating all these layers I want that file converted by mapshaper so that the outcome is a topojson. So far so good.
I tried it with a simple polygon, so it was just one layer. I created the shapefile and than converted it to topojson. Now I wanted to use that file with d3:
{"type":"Topology","transform":{"scale":[0.8423423423423423,0.808252427184466],"translate":[1491.6423611111095,-3184.7916666666715]},"objects":{"country":{"type":"GeometryCollection","geometries":[{"type":"LineString","arcs":[0]}]}},"arcs":[[[437,17],[-7,87],[69,64],[23,74],[-31,80],[-14,54],[19,69],[-9,18],[-45,-35],[-53,-32],[-33,-12],[-26,-38],[-26,-27],[-29,-15],[-54,-12],[-29,22],[-40,27],[-31,10],[-36,35],[-2,30],[-17,57],[-14,19],[-19,28],[-31,62],[-2,47],[7,39],[17,40],[28,57],[119,37],[180,22],[247,-2],[105,-109],[78,-122],[52,-96],[55,-176],[-12,-109],[-47,-69],[-60,-77],[-104,-57],[-181,-7],[-49,30]]]}
This is just one polygon, that's right. This is my d3 code:
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("file.json", function(error, topology) {
console.clear();
var featureCollection = topojson.feature(topology, topology.objects.country);
var bounds = d3.geo.bounds(featureCollection);
var centerX = d3.sum(bounds, function(d) {return d[0];}) / 2,
centerY = d3.sum(bounds, function(d) {return d[1];}) / 2;
var projection = d3.geo.mercator()
.scale(3000)
.center([centerX, centerY]);
path.projection(projection);
svg.selectAll("path")
.data(featureCollection.features)
.enter().append("path")
.attr("d", path);
});
But I always get "TypeError: t is undefined". But if I use a json file from someone else it's working. So how can I get this small example running? Is my QGIS bugging or maybe am I using it wrong? Thanks.
Or even do you know a better workaround for this?
Simply remove
.scale(3000)
.center([centerX, centerY])
and it should work. Or edit it to correct values.

Venue/Indoor Map using D3.js and Geojson

I have created geojson file which contains all the features of 1st floor of a shopping mall. I got that venue map projected using d3.js with different colors but only some parts not the complete map. Below is the script code and link to the geojson file. Also please note that i have not converted this geojson into topojson and used Qgis to draw the maps and c#.net to convert the geometry data to geojson objects. Can anyone please check my json and my d3.js code? Do I need to use any other projections?
https://www.dropbox.com/s/8pu2s0yamfkd89p/JSONfromDB_8Feb2014.json
$(document).ready(function () {
parseResultShopDetails();
});
function parseResultShopDetails() {
var width = 600, height = 300;
var svg = d3.select("#map").append("svg")
.attr("width", width)
.attr("height", height);
var projection = d3.geo.mercator()
.scale(30)
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
d3.json("http://localhost:1209/data/JSONfromDB_8Feb2014.json", function (error, jsonData) {
var color1 = d3.scale.category10();
svg.selectAll("path")
.data(jsonData.features)
.enter()
.append("path")
.attr("d", path)
.attr("text", function (d, i) { return "js"; })
.attr("fill", function (d, i) { return color1(i); });
});
}
It looks like the d3 mapping tools really fall apart if you try to use coordinates other than longitude and latitude.
I tried creating a "null" projection that just returns the input values, but the negative numbers and numbers greater than 360 were still getting wrapped by d3 before passing to the projection function. That avoids the trig errors from the Mercator projection, and it creates interesting art, but not the floor plan you were hoping for:
var projection = d3.geo.projection(function(λ, φ) {
return [ λ, φ ];
});
http://fiddle.jshell.net/rR2hG/1/
However, all is not lost. The second image in that example is created by just passing the array of coordinates as the points of <polygon> elements. I think that's closer to what you wanted. So you'll need to do a little more work to grab the points from the data file but you can definitely visualize them just as an array of coordinates.
svg2.selectAll("polygon")
.data(jsonData.features)
.enter()
.append("polygon")
.attr("points", function(d){ return d3.merge(d.geometry.coordinates);})
.attr("fill", function (d, i) {
return color1(i);
});
The only other suggestion is to write a script to convert your geoJSON file to geographic units. They don't have to be actual latitude and longitude of a particular place (you could still have the map centered on a reference point of your choice), but the scale has to be in degrees not feet or meters or whatever you are using.
D3's mapping projections are designed to transform 3D earth coordinates into 2D browser coordinates, so they are not that great at transforming local coordinates like the ones you've got. And as Amelia outlines your putting in coordinates that are outside of what's expected.
You'd be better off doing one of two things; creating a geometry stream based on 2 linear scales as outlined in this google groups discussion; or using d3's path generators.
To creating a 2D path generator is straightforward in d3 something like this will work:
var shops = d3.svg.line()
.interpolate("linear")
.x(function(d) {
return xScale(d.x);
})
.y(function(d) {
return yScale(d.y);
})
The real trick here is accessing the 'right' part of your json object. If you look into the geojson structure you see that there is a geometry part as well as an properties part. You need to dig through to pull out the coordinates and then pass them to the pavement generator. In this case it would be:
d.geometry.coordinates
which would obviously need to be referenced correctly.
Note that the method outlined here isn't going to work if you have complex geometries such as multi-polygons, you'll need to do quite a bit more work. If that's what you've got you'll want to create a custom geometry stream.
Now putting all of that together here's a working example of you're json.

Is there a malformation in my GeoJSON or a bug in my D3 code?

I am new to d3 and GeoJson. I have this GeoJSON which displays on geojson lint. I am trying to display the GeoJSON as a map with the following code:
var width = 960,
height = 1160;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var projection = d3.geo.transverseMercator().translate([width / 2, height / 2]).scale(150).center(-90.088, 29.957);
var path = d3.geo.path().projection(projection);
d3.json("orleans.json", function(json) {
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path);
});
The second to last line .attr("d", path) is throwing the following error deep in the d3 stack trace:
Error: Problem parsing d="MNaN,NaNLNaN,NaNL8.76110196153104,1051.238898038469L8.76110196153104,108.76110196153104L951.238898038469,108.76110196153104L951.238898038469,1051.238898038469LNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNZMNaN,NaNLNaN,NaNLNaN,NaNZMNaN,NaNLNaN,NaNLNaN,NaNZMNaN
Is there a problem with my GeoJSON? Or a problem with how I am using the GeoJSON with D3? It seems like this error comes from malformed input to D3 -- but my GeoJSON lints. So maybe this is a problem with my D3 syntax and not my GeoJSON?
The GeoJSON does seem like it is getting loaded properly. When I console.log(json) right after the call
to d3.json("orleans.json", function(json) it shows the following:
There are two problems with your code:
The .center() function takes a single array argument and not two.
The transverse mercator projection doesn't support antimeridian cutting.
To fix, pass an array instead of two numbers and restrict the center to -90 degrees or less. Complete demo here.

Resources