Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map with d3.js and TopoJSON, Albers Siberia projection

I'm trying to make a Choropleth with d3.js but I got stucked just at the beginning. I found a Shapefile and generated GeoJSON and TopoJson files from it just like here. The map uses Albers-Siberia projection. What I found about this projection:

Projection: Albers Equal-Area Conic

  • Units: Meters
  • Spheroid: Krasovsky
  • Central meridian: 105
  • Standard Parallel 1: 52
  • Standard Parallel 2: 64
  • Reference Latitude: 0
  • False Easting: 18500000
  • False Northing: 0

PROJ.4: +proj=aea +lat_1=52 +lat_2=64 +lat_0=0 +lon_0=105 +x_0=18500000 +y_0=0 +ellps=krass +units=m +towgs84=28,-130,-95,0,0,0,0 +no_defs

MapInfo: "Albers-Siberia", 9, 1001, 7, 105, 0, 64, 52, 18500000, 0.

So I got this code finally and it make nothing (and even freez up), what's wrong?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Choropleth</title>
    <script type="text/javascript" src="d3/d3.v3.js"></script>
    <script type="text/javascript" src="d3/queue.v1.min.js"></script>
    <script type="text/javascript" src="d3/topojson.v0.min.js"></script>
</head>
<body>
    <h1>My Choropleth</h1>
    <script type="text/javascript">

        var width = 960,
            height = 500;

        var svg = d3.select("body").append("svg")
                    .attr("width", width)
                    .attr("height", height);

        var pr = d3.geo.albers()
            .center([105,0])
            .parallels([52, 64])
            .scale(1000);


        var path = d3.geo.path().projection(pr);

        d3.json("map_rus_topo.json", function(error, map) {
         svg.append("path")
          .datum(topojson.object(map, map.objects.map_rus))
          .attr("d", path);
        });

    </script>
</body>

You can find all JSON files here.
And one more question: How can I reference to value of region field in my TopoJson file.

like image 807
KoGor Avatar asked Apr 18 '13 13:04

KoGor


1 Answers

The first problem is that your GeoJSON file isn’t in degrees [longitude°, latitude°], otherwise known as EPSG:4326 or WGS 84. To convert your GeoJSON file to WGS 84, you first need to create a projection file, say albers.prj so that you can tell OGR what the source projection is.

+proj=aea +lat_1=52 +lat_2=64 +lat_0=0 +lon_0=105 +x_0=18500000 +y_0=0 +ellps=krass +units=m +towgs84=28,-130,-95,0,0,0,0 +no_defs

Then, “unproject” the GeoJSON file by converting it to WGS 84:

ogr2ogr -f GeoJSON -s_srs albers.prj -t_srs EPSG:4326 map_rus_wgs84_geo.json map_rus_geo.json

Now you can convert to TopoJSON in WGS 84, rather than projected coordinates. I’ve also taken the liberty of doing some simplification:

topojson -o map_rus_wgs84_topo.json -s 1e-7 -- russia=map_rus_wgs84_geo.json

The second problem is that your projection definition in D3 is incorrect. The d3.geo.albers projection has a default rotate and center that’s designed for a U.S.-centered map, so in addition to defining the center you’ll also need to override the default rotation. In fact, the +lon_0 (central meridian) projection parameter maps to the projection’s rotation, not the projection’s center. Giving:

var projection = d3.geo.albers()
    .rotate([-105, 0])
    .center([-10, 65])
    .parallels([52, 64])
    .scale(700)
    .translate([width / 2, height / 2]);

(I fudged with the center parameter to put Russia at the center of the viewport. You can compute this automatically if you prefer.) You should now see something like this:

Albers Siberia

It’s also possible to work with projected (Cartesian) coordinates in TopoJSON, and then define a d3.geo.path with a null (identity) projection, but I’ll leave that for a separate question.

like image 121
mbostock Avatar answered Oct 16 '22 22:10

mbostock