Comments 8
Ох, у меня прямо вьетнамские флэшбеки от склеивания Чукотки, страдал как-то с этим в PostGIS
Добрый день!
Да, пришлось с ней повозиться)
Ой не говори кума... Как счас помню, куча геоданных и не указано в какой системе координат ни представлены, а часть вообще в локальных. И надо свести их воедино, а потом прыгать с проекцией, а знаний в геодезии - ноль. А потом ещё аэроснимки привязать. Я тогда в QGis в связке с PostGIS просто влюбился. Да, лихие 2000-е. Пошёл лечить ПТСР. :)
Что-то у вас карта и от международно признаваемых границ отличается, и от фантазийных границ, обозначенных в конституции нынешней.
Оффлайн карта и не лагает - я о таком давно мечтал!
Предложения по улучшению такие:
Меня смущает избыточная точность координат в геоданных. Произведём несложный расчёт:
L = 40000000
print('Длина экватора: ',L, 'м')
rho = 10**-15
print('Точность геоданных (размер пикселя в градусах): ',rho, '°')
print('Тогда размер пикселя в метрах: ',rho*L/360, 'м')
Если мы хотим рисовать карту даже с точностью до метра (а здесь ведь ещё simplify поработал!), хватило бы 6 десятичных знаков после запятой.
Отображаемый размер города лучше привязать к логарифму населения. А то Москва пузатая слишком :)
Спасибо за статью! Мне давно было интересно посмотреть на отрисовку интерактивной карты похожим образом, чтобы сравнить производительность и удобство со способами "из коробки". Поигрался локально с вашим кодом, получил представление. На мой взгляд, есть несколько важных тезисов, не привести которые в комментарии было бы большим упущением.
1. Вам точно не подходят готовые решения?
Вы пишете, что вам не подходят "коробочные" решения, потому что они требуют внешних подключений и не работают с "красивыми" системами координат. Однако это не так. Практически все они позволяют отрисовывать произвольные наборы векторных данных, а "basemap" можно отключить. Набор проекций у layout.Geo
вполне адекватный для вашей цели, т.к. там есть разные конические проекции (об этом потом).
То же самое после подготовки данных можно сделать встроенными методами
fig = px.choropleth(regs, geojson=rgshape, locations=regs.fid, color='region', featureidkey='properties.fid')
fig.update_geos(projection_type="conic conformal",
fitbounds='locations',
visible=False)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
С вашими данными что-то не так — видимо, Plotly умеет рисовать только полигоны, описанные в определённую сторону обхода. Я использовал регионы России из natural earth
У geopandas есть встроенные методы для создания интерактивных карт при помощи folium. Да и сам folium несложно использовать. Да, там будут некоторые проблемы с проекциями, но их можно обходить, если вам не нужны внешние тайлы.
2. Недостатки у готовых решений связаны с производительностью и удобством
Основная проблема здесь в том, что уже даже в вашем примере карта достаточно сильно лагает. А в моём ещё сильнее. Как только нужно будет изобразить много данных, этим совсем нельзя будет пользоваться. Не знаю, почему так тупит Plotly, но у решений, основанных на leaflet.js (folium, например) корень проблемы кроется в том, что при изображении векторных объектов, каждый из них добавляется как объект в DOM. После нескольких тысяч точек пользоваться этим становится нереально. Решение — использовать Mapbox/maplibre, у которые работают на WebGL. Однако и тут всё не особо радужно в случае с Plotly — несколько тысяч линий и он не справится даже с этим бэкендом отрисовки.
И при этом API совершенно неудобен для аналитических задач — в Plotly мне надо отдельно хранить geojson с геометрией и отдельно таблицу с атрибутами. Это может быть удобно в случае разработки дашбордов — с одного сервера получили запросом геометрию (или вообще локально её храним), с другого сервера получили данные и что-то точно нарисуем, пустой картинки не будет. Для случая быстрой отрисовки результатов вычислений создавать отдельный json с геометрией — это как-то так себе подход. В folium с этим немного попроще (хотя там наверняка geojson создаётся самой библиотекой, что тоже плохо сказывается на производительности).
Гораздо лучше (на порядки) с удобством API в экосистеме R. Но проблемы с производительностью те же, так как интерактивность реализована через leaflet.
3. Если у вас достаточно много данных, geopandas — это боль,
потому что загружает весь датасет в память сразу. Можно этого избежать, использовав обычный для таких случаев и pandas подход с написанием генераторов и отложенным чтением по чанкам. Но так получается гораздо больше кода, чем если использовать osgeo.ogr, который может весьма эффективно читать объекты с диска по одному. Плюс, тут у вас есть всякие подводные камни в том, как geopandas использует fiona и rtree, которые могут проявиться достаточно быстро при росте объёма данных.
4. Что с этим делать?
Когда данных мало, я использую R. Потому что удобный API. Когда данных много, я использую QGIS. Потому что его тоже относительно просто запрограммировать. И интерактивность в нём весьма хороша. А так, на вкус и цвет все фломастеры различаются.
P.S. про проекции.
EPSG:326XX не подходят для мелкомасштабного картографирования. Это зональная проекция с зонами, вытянутыми вдоль меридианов, и нет смысла использовать её для России, которая вытянута с запада на восток. У вас искажения величин получаются сильные: Кольский полуостров сопоставим с Таймыром, хотя на самом деле он в 4 раза меньше. Если у вас ассоциации с "контурной картой" вызывает равноугольная проекция, то вам здесь лучше подойдёт коническая равноугольная проекция. Можно proj-строкой описать необходимые для России параметры. Но в б.д. кодов есть проекция, названная там "Asia North Lambert Conformal Conic" или ESRI:102027, которая вполне подходит для России.
Широка, необъятна, интерактивна: оффлайн карта России с Plotly