Карта с d3.js и TopoJSON, проекция Albers Siberia

Я пытаюсь сделать Choropleth с d3.js, но я застрял в самом начале. Я нашел Shapefile и сгенерировал из него файлы GeoJSON и TopoJson, как здесь. Карта использует проекцию Альберс-Сибирь. Что я нашел об этой проекции:

Проекция: равновеликая коническая Альберса

  • Единицы: метры
  • Сфероид: Красовский
  • Центральный меридиан: 105
  • Стандартная параллельная 1:52
  • Стандартная параллель 2: 64
  • Справочная широта: 0
  • Ложный восток: 18500000
  • Ложный север: 0

PROJ.4: +proj=aea +lat_1=52 +lat_2=64 +lat_0=0 +lon_0=105 +x_0=18500000 +y_0=0 +ellps=крас +единицы=m +towgs84=28,-130,-95 ,0,0,0,0 +no_defs

MapInfo: "Альберс-Сибирь", 9, 1001, 7, 105, 0, 64, 52, 18500000, 0.

Итак, я наконец получил этот код, и он ничего не делает (и даже зависает), что не так?

<!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>

Все JSON-файлы вы можете найти здесь.
И еще один вопрос: Как я могу ссылаться на значение < strong>region в файле my TopoJson.


person KoGor    schedule 18.04.2013    source источник
comment
Что именно происходит, когда вы запускаете код? Вы получаете какое-либо сообщение об ошибке, вывод?   -  person Lars Kotthoff    schedule 18.04.2013
comment
Нет, ошибок в консоли нет.   -  person KoGor    schedule 18.04.2013
comment
Размер файлов JSON может быть проблемой. Пробовали ли вы упростить их или просто подождать немного дольше?   -  person Lars Kotthoff    schedule 18.04.2013
comment
Да, я пробовал с упрощенным файлом (337 КБ), все равно не работает.   -  person KoGor    schedule 18.04.2013


Ответы (1)


Первая проблема заключается в том, что ваш файл GeoJSON не указан в градусах [долгота°, широта°], иначе известный как EPSG:4326 или WGS 84. Чтобы преобразовать файл GeoJSON в WGS 84, вам сначала нужно создать файл проекции, скажем, albers.prj, чтобы вы могли указать OGR, что такое исходная проекция.

+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

Затем «отмените проект» файла GeoJSON, преобразовав его в WGS 84:

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

Теперь вы можете конвертировать в TopoJSON в WGS 84, а не в координаты проекции. Я также позволил себе некоторое упрощение:

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

Вторая проблема заключается в том, что ваше определение проекции в D3 неверно. Проекция d3.geo.albers имеет поворот и центр по умолчанию, которые предназначены для карты с центром в США, поэтому в дополнение к определению центра вам также потребуется переопределить поворот по умолчанию. На самом деле параметр проекции +lon_0 (центральный меридиан) соответствует вращению проекции, а не центру проекции. Предоставление:

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

(Я схитрил с параметром center, чтобы поместить Россию в центр области просмотра. Вы можете вычислить это автоматически если хотите.) Теперь вы должны увидеть что-то вроде этого:

Альберс  Сибирь

Также можно работать с проекционными (декартовыми) координатами в TopoJSON, а затем определить d3.geo.path с нулевой (тождественной) проекцией, но я оставлю это для отдельного вопроса.

person mbostock    schedule 18.04.2013
comment
Это просто здорово! Спасибо, за столь быстрый и полный ответ. Я новичок во всем этом, впервые работаю с картами. - person KoGor; 18.04.2013
comment
Кроме того, объясните, пожалуйста, что такое make --russia= в этом коде: › topojson -o map_rus_wgs84_topo.json -s 1e-7 -- russia=map_rus_wgs84_geo.json. И я не понимаю координат центра, ссылка, которую дал U, касается автоматического масштабирования и перевода параметров, или я что-то пропустил. - person KoGor; 18.04.2013
comment
Полное объяснение см. в справочнике по командной строке TopoJSON. Выше я использую -o для указания имени выходного файла, -s для указания порога упрощения в стерадианах, а затем входные файлы следуют за разделителем --. Есть только один входной файл (map_rus_wgs84_geo.json), и, добавив префикс с russia=, я могу установить имя объекта в сгенерированной топологии. Вот почему в связанном примере я ссылаюсь на russia.objects.russia. - person mbostock; 19.04.2013
comment
Что касается координат центра проекции, [-10°, 65°], я просто придумал их, основываясь на том, что выглядело хорошо. Координаты центра поворачиваются вместе со всем остальным, поэтому обычно долгота центра (здесь -10 °) будет близка к нулю с конической проекцией. Точно так же центральная широта будет примерно в том же диапазоне, что и ваши параллели (52 ° и 64 °), чтобы минимизировать искажение от конической проекции. - person mbostock; 19.04.2013
comment
Спасибо еще раз, теперь все ясно. А по поводу префиксации нет описания (примеров) такой возможности в TopoJSON Command-line ссылка, поэтому я думаю, было бы неплохо добавить его. - person KoGor; 19.04.2013
comment
Спасибо; добавил описание. - person mbostock; 20.04.2013
comment
Я пытаюсь углубиться и обнаружил проблему с кодировкой. Когда я пытаюсь выполнить команду topojson -o output_topo.json -p -s 1e-7 -- name=input_geo.json, я получаю файл TopoJSON со всеми неопределенными символами вместо неанглийских. Как я могу контролировать кодировку во время создания файла TopoJSON или это невозможно? - person KoGor; 21.04.2013
comment
Инструмент командной строки topojson предполагает, что ввод GeoJSON — это UTF-8, а ввод шейп-файла — Windows1252, и всегда генерирует вывод UTF-8. Вы можете использовать --shapefile-encoding, если ваш шейп-файл находится в другой кодировке, но это случается крайне редко. Если ваш ввод GeoJSON не в UTF-8, используйте ogr2ogr -lco ENCODING=UTF-8, чтобы исправить это. - person mbostock; 22.04.2013
comment
Я попытался пересохранить свой файл GeoJSON с кодировкой UTF-8 просто в блокноте, но после выполнения topojson -o output_topo.json -p -s 1e-7 -- name=input_geo.json получил синтаксическую ошибку при разборе. Пишет, что у меня есть пара хреновых символов только в начале файла, но файл начинается правильно (как я вижу в блокноте) с {"type": "FeatureCollection",… Я просто не понимаю, что происходит, темная магия? =) Я полагаю, дело не в TopoJSON, а в неправильной кодировке в шейп-файле, но почему он все равно не работает, если я исправил вручную в блокноте… - person KoGor; 23.04.2013
comment
Майк, снова нужна твоя помощь =). Я получил файл TopoJSON: …"objects":{"russia":{"type":"GeometryCollection","geometries":[{"type":"Polygon","arcs":[[0]],"properties":{"AREA":29809500,"PERIMETER":21822.4,"region":"XYZ"}}… Теперь мне нужно добраться до полей в свойствах. Пробовал так: .datum(topojson.object(map, map.objects.russia).geometries) … .style("fill", function(d) { if (d.properties.region == "XYZ") {return "red"} else {return "gray"} }) Но не работает, что не так делаю? (А почему 4 пробела здесь не делают блок кода?) - person KoGor; 29.04.2013
comment
Пожалуйста, задайте отдельный вопрос, а не отвечайте несвязанными вопросами в этой теме. - person mbostock; 30.04.2013