Поскольку я в настоящее время изучаю все тонкости D3 v4, я изо всех сил пытался найти хороший ресурс для преобразования шейп-файлов ESRI Natural Earth в TopoJSON. В этом кратком посте будет рассказано, как это сделать с помощью текущих версий утилит географии D3.

Скачать Natural Earth

Natural Earth - это набор глобальной географической геометрии, созданный сообществом, который можно загрузить с веб-сайта Natural Earth. Вы хотите получить ZIP-архив размером 279 МБ, содержащий данные в формате SHP / GeoDB. Вы также можете просто получить его, используя следующую команду оболочки¹, хотя, пожалуйста, прочтите Natural Earth Условия использования, прежде чем делать это.

$ curl -LOk http://naciscdn.org/naturalearth/packages/natural_earth_vector.zip

(Вышеупомянутое вводится как одна строка - средние обертывают фрагменты кода. Однако вы сможете без проблем копировать и вставлять его. Обратите внимание, что вы можете поставить обратную косую черту перед символом новой строки, чтобы записать несколько строк в большинстве оболочек. , как я это делаю в следующих примерах.)

Затем вы можете разархивировать его в подкаталог с именем ne /, используя следующее:

$ unzip natural_earth_vector.zip -d ne

Это должно работать в OS X и большинстве дистрибутивов Linux. Делайте все, что делают люди для распаковки архивов в Windows, если вы используете эту ОС (хотя оставшаяся часть этого руководства может показаться вам сложной, так как она предполагает наличие оболочки, такой как Bash или Zsh).

Установить инструменты

Все инструменты сообщества D3 для TopoJSON расположены в следующих пакетах:

  • topojson: Основная библиотека, необходимая для использования TopoJSON в D3. Также содержит geo2topo, который мы используем для преобразования GeoJSON в TopoJSON.
  • шейп-файл: содержит shp2json, который преобразует шейп-файл в GeoJSON.
  • d3-geo-projection: содержит геоститч, используемый для нормализации форм перед преобразованием в TopoJSON. Если бы мы перепроецировали наши координаты, мы бы использовали геопроект из этого пакета.
  • topojson-client: содержит topomerge для объединения полигонов и линий сетки в один объект коллекции TopoJSON.
  • ndjson-cli: мы манипулируем внутренними данными JSON с помощью ndjson-map.
  • topojson-simpleify: мы можем уменьшить размер нашего файла с помощью toposimplify.

Используя npm, установите их все глобально за один раз:

$ npm install --global topojson shapefile d3-geo-projection \
topojson-client ndjson-cli topojson-simplify

Если вы получаете ошибку разрешений при выполнении вышеуказанного, возможно, вам нужны привилегии суперпользователя, прежде чем вы сможете устанавливать пакеты NodeJS глобально. Попробуйте вставить sudo перед npm в приведенном выше фрагменте, при необходимости введите пароль пользователя.

Обратите внимание, что существует пакет npm под названием shp2json,, который полностью отличается от пакета mbostock / shapefile. В этом руководстве, когда я упоминаю shp2json, я говорю о версии Майка Бостока - версия Джеймса Халлидея великолепна, но для нее требуется node-gdal , который мне чрезвычайно сложно правильно скомпилировать в OS X. Также обратите внимание, что topojson / topojson больше не является инструментом командной строки для манипулирование TopoJSON - все это помещено в репозиторий topojson / topojson-client .

Вам нужно настроить своего рода конвейер для перемещения данных между различными инструментами, о которых я упоминал выше. Я собираюсь проделать каждый шаг отдельно с одним файлом, создавая новый файл на каждом шаге, а затем дам вам несколько однострочников, чтобы сделать все сразу. Вы можете сделать все это в сценарии Bash, если сочтете это более удобным; или, если вы настроены амбициозно, все вышеперечисленные пакеты предоставляют API-интерфейс NodeJS, который можно использовать с чем-то вроде Gulp.

Большая часть этого адаптирована из сценария предварительной публикации topojson / world-atlas; если вы застряли, попробуйте поискать в нем подсказки.

Преобразование из шейп-файла ESRI в GeoJSON

Большая часть геометрии мира, которую вы найдете в Интернете, имеет формат шейп-файл Esri (.shp). Это двоичный формат, который на самом деле не оптимизирован для использования в онлайн-веб-графике, и его сложно манипулировать с помощью JavaScript. Сначала мы собираемся преобразовать его в GeoJSON, формат геоинформатики на основе JSON с открытым исходным кодом, а затем преобразовать его в TopoJSON. , который похож на значительно более оптимизированную версию GeoJSON.

Файл, который мы собираемся преобразовать в этом примере, находится по адресу ne / 50m_cultural / ne_50m_admin_0_countries.shp.

В такой коллекции, как Natural Earth, вам часто требуется несколько шейп-файлов в одном файле TopoJSON. Позже мы рассмотрим объединение нескольких файлов.

Но сначала давайте создадим выходной каталог с именем build /:

$ mkdir ./build

Преобразовать шейп-файл в GeoJSON

Следующим шагом будет передача вашего шейп-файла через shp2json, в результате чего будет получен файл GeoJSON, который можно будет оптимизировать в дальнейшем.

$ shp2json ne/50m_cultural/ne_50m_admin_0_countries.shp > \
build/ne_50m_admin_0_countries.geojson

Это создаст файл GeoJSON с именем ne_50m_admin_0_countries.geojson в вашем каталоге build /. Затем вы можете просто запустить:

$ geo2topo build/ne_50m_admin_0_countries.geojson > \
build/ne_50m_admin_0_countries.topojson

… Чтобы получить работоспособный файл TopoJSON. Это вообще не будет оптимизировано и в основном представляет собой прямое преобразование, которое вы можете получить из шейп-файла. Далее мы поговорим о том, как оптимизировать и улучшить метаданные.

Упростите метаданные GeoJSON

Это в некоторой степени необязательно, но вы еще больше уменьшите размер файла вывода, если правильно управляете внутренними данными GeoJSON. В этом случае мы хотим сопоставить код страны ISO с атрибутом идентификатора формы. Однако сначала нам нужно преобразовать наш файл .shp в JSON с разделителями новой строки или ndjson, что позволяет нам использовать фантастический ndjson-cli инструменты. Мы делаем это, передавая shp2geo флаг -n:

$ shp2json -n ne/50m_cultural/ne_50m_admin_0_countries.shp > \
build/ne_50m_admin_0_countries-ndjson.geojson

Затем мы используем ndjson-map для выполнения нескольких операций со свойствами JSON:

$ ndjson-map '(d.id = d.properties.iso_a2, delete d.properties, d)'\
< build/ne_50m_admin_0_countries-ndjson.geojson \
> build/ne_50m_admin_0_countries_country_codes.json

Здесь много всего происходит, поэтому давайте разделим это на три части:

$ ndjson-map '(d.id = d.properties.iso_a2, delete d.properties, d)'

1. Это указывает инструменту командной строки ndjson-map выполнить следующее выражение и вернуть массив JSON из любого заданного входного потока. В этом случае мы назначаем код ISO 3166–1 alpha-2 (то есть стандартный двухбуквенный код страны) из свойства properties каждого объекта для каждого географического объекта свойство верхнего уровня ID. Затем мы удаляем свойство properties, поскольку оно содержит много лишних данных, которые нам не нужны (что, в свою очередь, увеличивает размер файла). Другие полезные свойства, включенные в Natural Earth, - это свойство iso_n3 (для сопоставления числовых кодов ISO 3166–1), name (для общего названия географического объекта) и несколько других, перечисленных в файле Excel, доступном здесь. Мы делаем это просто, используя только код страны, но Natural Earth также включает такие вещи, как данные о населении и ВВП.

< build/ne_50m_admin_0_countries-ndjson.geojson \

2. Здесь мы направляем содержимое только что созданного файла в ndjson-map с помощью оператора ввода. . Мы также могли бы сделать что-то вроде:

cat <filename> | ndjson-map <expression>

… Вместо этого с аналогичным эффектом.

> build/ne_50m_admin_0_countries_country_codes.json

3. Наконец, мы используем ›оператор вывода, чтобы направить вывод ndjson-map в новый файл build / ne_50m_admin_0_countries_country_codes. json.

Теперь у нас есть новый файл в каталоге build / с именем ne_50m_admin_0_countries_country_codes.json с гораздо меньшим количеством прикрепленных метаданных.

Геометрия геостежка

Прежде чем мы превратим наш GeoJSON в TopoJSON, мы должны исправить его сшивание с помощью geostitch. Это удаляет антимеридиональные и полярные разрезы, метод географической визуализации, предназначенный для решения трудностей визуализации сферического объекта на 2D-плоскости. Давайте сделаем это сейчас, используя формат, аналогичный последней команде:

$ geostitch -n \
< build/ne_50m_admin_0_countries_country_codes.json \
> build/ne_50m_admin_0_countries_geostitched.json

Конвертировать GeoJSON в TopoJSON

Наконец, мы готовы перейти на TopoJSON:

$ geo2topo -q 1e5 -n countries=\
build/ne_50m_admin_0_countries_geostitched.json \
> build/ne_50m_admin_0_countries.topojson

Что мы делаем здесь, так это квантуем результаты на 10⁵ и настраиваем geo2topo на использование формата с разделителями новой строки, который мы использовали на протяжении всего этого. Во второй строке мы берем наш файл GeoJSON с привязкой к географии и используем cat, чтобы превратить его в поток. Затем мы превращаем все регионы в топологию TopoJSON, используя свойство «countries» в нашем файле GeoJSON, выводя данные в build / ne_50m_admin_0_countries.topojson.

Наконец, мы объединяем все участки суши в единую топологию с помощью topomerge:

$ topomerge land=countries \
< build/ne_50m_admin_0_countries.topojson \
> build/ne_50m_admin_0_countries_merged.topojson

Здесь мы создаем новую топологию под названием land, которую мы создаем из топологии стран, которую мы только что сгенерировали.

Это упрощает работу с функциями, если вы хотите каким-то образом управлять группой из них одновременно. Еще одно хорошее применение topomerge - это что-то вроде объединения всех функций для всего региона в единую топографию - в конечном итоге то, как вы ее используете, в значительной степени зависит от вашего варианта использования.

Все сразу, сейчас!

Сделаем это одним махом:

$ env INPUT_FILE=ne/50m_cultural/ne_50m_admin_0_countries.shp \
OUTPUT_FILE=build/ne_50m_admin_0_countries.topojson \
bash -c 'geo2topo -q 1e5 -n countries=<(shp2json -n $INPUT_FILE \
| ndjson-map "(d.id = d.properties.iso_a2,delete d.properties,d)" \
| geostitch -n) \
| topomerge land=countries > $OUTPUT_FILE'

Похоже, что происходит много всего, но это всего лишь несколько последних шагов, связанных вместе. Мы устанавливаем $ INPUT_FILE и $ OUTPUT_FILE в качестве переменных среды в начале, чтобы упростить использование (или, возможно, поместить в сценарий оболочки). Затем мы запускаем ту же цепочку команд, указанную выше, выполняя потоковую передачу между ними вместо сохранения в файл, как мы это делали раньше. Мы оборачиваем всю команду в строку и передаем ее Bash, что в основном помогает обеспечить кроссплатформенную работу.

Объединение нескольких шейп-файлов

Если вы хотите объединить несколько файлов .shp в один файл TopoJSON, вам нужно добавить шаг в описанный выше рабочий процесс. На этот раз мы собираемся объединить ne_50m_rivers_lake_centerlines.shp и ne_50m_ocean.shp в один файл water.json TopoJSON.

$ env OUTPUT_FILE=build/water.topojson \
bash -c 'geo2topo -q 1e5 -n water=\
<(\
shp2json -n ne/50m_physical/ne_50m_rivers_lake_centerlines.shp
shp2json -n ne/50m_physical/ne_50m_ocean.shp
) \
| geostitch -n \
> $OUTPUT_FILE'

Если вы посмотрите выше, есть две команды shp2json, разделенные новой строкой и выделенные полужирным шрифтом. Думайте о каждой строке как о отдельном рабочем процессе shp-to-GeoJSON - если вы хотите сделать что-то вроде запуска ndjson-map для одного или обоих шейп-файлов, вы просто перенаправляете вывод каждого в вот так:

$ env OUTPUT_FILE=build/water_no_metadata.topojson \
bash -c 'geo2topo -q 1e5 -n water=\
<(\
shp2json -n ne/50m_physical/ne_50m_rivers_lake_centerlines.shp \
  | ndjson-map "(d.id = d.properties.name,delete d.properties,d)";
shp2json -n ne/50m_physical/ne_50m_ocean.shp \
  | ndjson-map "(d.id = d.properties.name,delete d.properties,d)"
) \
| geostitch -n \
> $OUTPUT_FILE'

Обратите внимание, что я поставил точку с запятой после первого рабочего процесса; Я сделал это просто для того, чтобы указать, где заканчивается первая команда и начинается вторая (хотя вы можете скопировать и вставить приведенное выше ad-verbatim, и это не будет иметь значения - полу- двоеточие в этом случае не является обязательным).

Упростите свой TopoJSON

Наконец, стоит упростить вашу геометрию, чтобы она не была такой большой загружаемой при доставке в веб-браузеры. Запустите новый TopoJSON через toposimplify, чтобы уменьшить его размер. Мы собираемся использовать наш исходный файл build / water.topojson, созданный до того, как мы удалили его свойство properties:

$ toposimplify -f -p 0.01 \
< build/water_no_metadata.topojson \
> build/water_no_metadata_simplified.topojson

Просто благодаря этому размер файла увеличился с ~ 782 кбайт до ~ 398 кбайт без какой-либо очевидной разницы в качестве, когда геометрия масштабируется до размеров экрана. Это очень хорошо!

Я даже не собираюсь пытаться объяснять, что делает каждый параметр toposimplify, потому что я буквально понятия не имею - из моих очень кратких специальных экспериментов, передавая значение 0,01 на -p дает примерно половину размера файла 0,001.
¯ \ _ (ツ) _ / ¯

Дополнительные сведения см. В topojson-simpleify docs. Или - если вы, как и я, не знаете, что такое планарный квантиль, попробуйте веб-инструмент, подобный одному из приведенных ниже, чтобы визуально упростить вашу геометрию до необходимого уровня качества.

Что теперь?

Прежде чем делать что-либо серьезное с полученным TopoJSON, рекомендуется загрузить его в какой-нибудь визуальный инструмент для проверки полученной геометрии. Возможно, вам потребуется перепроецировать результат или добавить какой-либо подобный дополнительный этап обработки в рабочий процесс.

Хорошим сайтом для этого является Mapshaper.org, который вы также можете использовать для преобразования шейп-файлов в TopoJSON, если все указанные выше Command-Line-Fu вызывают у вас проблемы. Вы также можете визуально упростить свою геометрию здесь, что намного меньше утомляет, чем угадывать, какие значения параметров командной строки использовать с toposimplify:

Еще один хороший инструмент, который может быть полезен, если вам также нужно проверить полученные свойства, - Mapstarter.com:

В заключение, я надеюсь, что вы найдете это полезным и сэкономите ваше время на выяснение того, как добавить новую геометрию в D3. Я что-то упустил или получил чаевые? Пожалуйста, оставьте отзыв, и я постараюсь ответить!

Эндрю Рининсленд - автор книги Визуализация данных с помощью D3.js, 2-е издание от Packt Books и разработчик отдела новостей в Financial Times.
Он пишет в Твиттере как @aendrew.

Большое спасибо Мартину Гонсалесу, Мика Стаббсу, Майку Бостоку, Тому Пирсону и Кшитию Аранке за отзывы на этот пост! Спасибо также Майку Бостоку за создание всех этих инструментов! 😄