zlukfo@gmail.com
  • Публикации
  • Темы
  • Ключевые слова
  • Архив

Postgresql: хранение и извлечение контурных карт

Контурые карты часто применяются в задачах визуализации, когда нужно отобразить некоторые статистические данные на геопространственных координатах. Для хранения контурных карт наиболее популярными форматами являются форматы shape, geojson и его модификация topojson, позволяющая хранить данные более компактно. Хранить эти форматы можно в базе данных postgtesql, при этом удобно использовать расширение postgis, предоставляющее различные вычислительные функции с географичесими координатами. Для отображения контурных карт в web-приложении используются различные библиотеки, например, d3js.

Карты стран мира в формате shape

Карты очертаний городов России по регионам

Каждый архив содержит 2 типа карт. pop-built-up-a-rostov-gislab более полная, включает следующие полезные поля

  • название на латитице и кирилице
  • тип объекта (хутор, город,...)
  • район
  • код по КЛАДР
  • еще один код?? напоминающий КЛАДР
  • почтовый индекс
  • географические координаты

Карты СНГ, России и регионов (подробные с точностью до зданий)

Каждый архив содержит несколько типов карт

  • административные границы boundary-polygon.shp
  • населенные пункты (в виде точек, не полигонов) settlement-point.shp
  • здания building-polygon.shp
  • автодороги highway-line.shp
  • железные дороги railway-line.shp

может еще копу пригодятся

  • землепользование landuse-polygon.shp
  • растительность vegetation-polygon.shp
  • точки интереса poi-polygon.shp

Карты городов (shape, geojson)

Загрузка карт в базу данных

  1. Установливаем Postgis
sudo apt-get install postgresql-9.6-postgis-2.3
create extension postgis;
  1. Загружаем карты

Существует удобная утилита shp2pgsql, позволяющая конвертировать карты в shape-формате в базу данных. Утилита устанавливается с пакетом postgis. Вот пример экспорта shape-файла в БД

shp2pgsql _shapefile_ _schema_._tablename_ > _sqlfilename_
psql -h localhost -d geo -U postgres -f _sqlfilename_

Если напрямую в БД, то можно так

shp2pgsql pop-built-up-a-rostov-gislab rostov1 | psql -h localhost -d geo -U postgres

Если выдает ошибку, связанную с кодировкой при именах, написанных кирилицей, то попробовать добавить ключ -S -W "utf-8"

Описание ключей команды (на русском) можно посмотреть здесь

Для любителей кодить и более гибкой загрузки shape-файлов в БД существует удобная python-библиотека pyshp. Вот пример рабочего кода выполняющий ту же задачу, что и утилита shp2pgsql - экспорт shape-файла в таблицу БД

# -*- coding: utf-8 -*-
import shapefile
import psycopg2
from psycopg2.extensions import QuotedString
import json

filename="ne_10m_admin_0_countries"
dbname='geo'

myshp = open(filename+".shp", "rb")
mydbf = open(filename+".dbf", "rb")
myshx = open(filename+".shx", "rb")
reader = shapefile.Reader(shp=myshp, dbf=mydbf, shx=myshx)
fields = reader.fields[1:]

# подключаемся к БД
conn = psycopg2.connect("dbname='%s' user='postgres' password='qweasd'" % (dbname,))
conn.autocommit=True
cur = conn.cursor()

# собираем имена полей и их типы для создания таблицы
ff='gid serial NOT NULL, '
for f in fields:
        typ='smallint'
        if f[1]=='C':
                typ='character varying(%d)' % (f[2],)
        if f[1]=='N' and f[3]:
                typ='double precision'
        ff+='"%s" %s, ' % (f[0], typ)

# создаем таблицу в БД
sql= "CREATE TABLE IF NOT EXISTS %s (%s)" % (filename,ff[:-2])
cur.execute(sql)

sql="SELECT AddGeometryColumn('public', '%s','geom','0','MULTIPOLYGON',2);" % (filename,)
cur.execute(sql)

# заполняем таблицу
fields=[field[0] for field in fields]
fields.append('geom')
fields=str(tuple(fields)).replace("'", '"')
for sr in reader.shapeRecords():
        data=','.join([QuotedString(str(i)).getquoted() for i in sr.record])
        geo=sr.shape.__geo_interface__
        if geo["type"]=='Polygon':
                geo["type"]='MultiPolygon'
                geo["coordinates"]=[geo['coordinates']]
        sql='INSERT INTO "%(table)s" %(fields)s VALUES (%(val)s, ST_GeomFromGeoJSON(%(geom)s));' % {'table':filename, 'fields':fields, 'val':data, 'geom':QuotedString(json.dumps(geo)).getquoted()}
        cur.execute(sql)

Получить контурную карту из базы

Наша карта сохраняется в таблице в специальном сжатом формате postgis. Для ее отрисовки в браузере карту нужно прежде всего преобразовать в формат geojson (о спецификации формата можно прочитать по ссылке вконце статьи). Преобразование выполняется с помощью команды ST_AsGeoJSON, например, так:

select ST_AsGeoJSON(geom) from ne_10m_admin_0_countries where "SOVEREIGNT"='Russia'

Если мы ходим объединить полигоны (все или по некоторому признаку), делаем примерно так

SELECT ST_AsGeoJSON(ST_UNION( ARRAY(select geom from rostov1)));

Так можно объединять по различным признакам, например - показать населенные пункты, находящиеся на одной широте, выделить только города - миллионники и т.д.

При необходимости, если выходной объем получается очень большой для передачи клиенту, геометрию карты можно упрощать с помошью команды ST_Simplify

Проверить отрисовку в браузере

Посмотреть корректность отображения контурной карты можно так. С помошью команды выше выгрузить в формате geojson интересующую нас карту в файл. Файл загрузить на один из сервисов

  1. http://geojson.io/#map=2/40.4/45.2
  2. http://mapshaper.org/

Кстати, эти онлайн сервисы позволяют сконвертировать формат geojson в topojson - более компактный и адаптированный для работы с библиотекой d3js на стороне клиента.

Полезные ссылки

  • https://dikmax.name/post/map-tutorial/
  • Спецификация формата GeoJSON
  • Примеры использования shp2pgsql и pgsql2shp
  • http://geojson.io/#map=2/20.0/-0.2

Опубликовано

авг. 11, 2016

Тема

Разработка

Ключевые слова

  • geojson 1
  • postgis 1
  • shape 1
  • zlukfo@gmail.com - Публикации на тему разработки web-приложений
  • Все авторские права защищены
  • Автор и разработчик блога zlukfo. Theme: Elegant by Talha Mansoor