Анализируем данные с помощью визуализации: рисуем поверх Google Maps

Привет, я Катя, системный аналитик в Ozon. Одна из первых задач, которую мне поручили здесь — проверить качество географических данных. Формально эта задача больше относится к анализу данных, чем к системному анализу. Но меня она очень заинтересовала, ведь требовался не только анализ, но и исследование и, по возможности, реализация решения, а для меня это самое интересное в работе.

Впереди меня ждала RnD-задача с исследованием картографических форматов, рисованием поверх Google Maps и реализацией скрипта на Python. Как я боролась с визуализацией картографических данных, расскажу в этой статье.

Как работает определение населённого пункта

У нас в Ozon есть сервис, который по переданной координате определяет населённый пункт. Это своего рода обратное геокодирование.

Время от времени от коллег из поддержки нам прилетали сообщения о том, что сервис некорректно определяет населённый пункт. Например, на картах Яндекса координаты соответствуют Алматы, а наш сервис считает, что это Баганашыл. Забегая вперед, покажу, как выглядели данные по Алматы в нашем сервисе.

Пришло время проверить корректность географических данных, хранящихся в нашей системе.

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

Населённый пункт мы определяем по вхождению переданной координаты в геометрию. Если не нашли, то ищем ближайшую координату центра.

Определение населённого пункта по вхождению точки в геометрию является самым точным методом, но есть важная деталь: данные должны быть корректными. В нашем случае именно корректность данных по полигонам стала проблемой. Эти данные копились в системе в течение всей её жизни. Что-то вносили вручную, что-то унаследовано из других систем,

Раз речь о картах — наглядной информации, то для проверки корректности данных мы решили их визуализировать. Задачей было нанести полигоны и координаты центров городов поверх реальной карты и визуально оценить, насколько всё хорошо или плохо.

Как импортировать географические данные

У нашего сервиса нет пользовательского интерфейса, поэтому для визуализации географических данных нам нужен был сторонний инструмент с возможностью импорта данных.

Такая возможность есть у обоих «главных» картографических сервисов — Google Maps и Яндекс.Карт.

К слову, лично мне больше понравился импорт Google Maps: интуитивно понятнее, подробнее сообщает об ошибках, штатно позволяет загружать координаты точек без формирования CSV-файла по жёсткому шаблону.

И Google Maps, и Яндекс.Карты позволяют с помощью CSV-файла отобразить на карте объекты по их координатам. Однако, чтобы загрузить более сложную геометрию (полигоны, мультиполигоны, линии), нужно иметь файл специфического картографического формата.

Google Maps поддерживает импорт в следующих форматах:

  • CSV и XLSX — для отображения координат точек,

  • GPX — для маршрутов,

  • KML — для любых географических объектов.

У Яндекс.Карт похожий список. Разница лишь в том, что нет GPX, но есть GeoJSON, который по назначению аналогичен KML.

Мой выбор пал на формат KML.

Keyhole Markup Language

Основная причина, по которой я выбрала KML для импорта данных на карты, заключалась в том, что этот формат поддерживают и Google, и Яндекс. Правда, как позже показала практика, бывают файлы с полигонами, которые отображаются на Google Maps, но не видны на Яндекс.Картах (но тогда мне ещё только предстояло это выяснить).

Ещё KML — это язык разметки на основе XML, так что я подумала, что сформировать такой файл будет не очень сложно.

У KML много возможностей — он даже позволяет отрисовывать 3D-объекты. Для решения моей задачи оказалось достаточно пяти элементов:

  1. Placemark — объект, позволяющий задавать геометрию (от координаты точки до мультиполигонов).

  2. Multigeometry — контейнер для нескольких геометрических примитивов, связанных с одним и тем же географическим объектом (например, для координаты центра и полигона).

  3. Polygon — многоугольник области; может дополнительно содержать внутреннюю вырезанную область. Мультиполигоны для отображения разбиваются на полигоны.

  4. Point — географическое местоположение, определяемое долготой и широтой. Координаты следуют в таком порядке: сначала долгота, потом широта.

  5. Style — стиль представления геометрии (например, цвет).

Пример структуры файла для отображения одного объекта, состоящего из точки и полигона:

<Placemark> <description>Описание объекта</description> <name>Название объекта</name> <!-- Задаём стиль для полигона --> <Style> <PolyStyle> <!-- Первые два символа цвета отвечают за прозрачность, последующие шесть — за цвет в формате RGB --> <color>4DA0753A</color> <fill>1</fill> <outline>1</outline> </PolyStyle> </Style> <MultiGeometry> <Point> <!-- Первым следует значение долготы, вторым — широты --> <coordinates>80.786232, 45.748985</coordinates> </Point> <Polygon> <!-- Задаём внешнюю границу полигона --> <outerBoundaryIs> <LinearRing> <!-- Точки разделяются между собой пробелом, долгота и широта — запятой; первой указывается долгота, второй — широта --> <coordinates>80.7643897, 45.7327094 80.7777888, 45.7297088 80.7831002, 45.7416147 80.8001875, 45.7445317 80.8058787, 45.7502633 80.7931381, 45.758115 80.7738655, 45.7542795 80.7643897, 45.7327094</coordinates> </LinearRing> </outerBoundaryIs> </Polygon> </MultiGeometry> </Placemark>

Финишная прямая: от KML к отображению своих объектов на карте

Файл из тысяч элементов не хочется формировать вручную. С генерацией KML-файлов мне помогла Python-библиотека pyKML.

Я написала небольшой скрипт: на вход он принимает XLSX-файл с данными о географических объектах. Структура файла – четыре колонки: наименование, описание, координата точки, геометрия в текстовом формате WKT (может быть пустой). На выходе формируется KML-файл, который можно использовать для отображения своих объектов на картах.

На всякий случай предупрежу: у Google Maps есть ограничение по количеству импортируемых объектов в 2000 штук. Если нужно отобразить больше, то придётся сделать несколько файлов.

Помните, как выглядел Алматы на карте в начале статьи? Несколько точек и только одна из них принадлежала непосредственно городу Алматы, остальные являлись районами, улицами, парками, в общем, не являлись населенными пунктами. Имея дело с такими данными, наш сервис в большинстве случаев ошибался (у Алматы не было полигона, поэтому алгоритм находил не сам город, а ближайшую точку, которая по факту городом не является).

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

Когда всё-таки звать разработчиков для помощи

Google Maps предоставляет отличные возможности для отображения географических данных без каких-либо серьёзных дополнительных манипуляций. Для визуализации в виде «было — стало» сервис подходит отлично, на мой взгляд: можно наглядно убедиться в корректности географических данных.

Когда может не подойти такой подход, и потребуется привлекать тяжёлую артиллерию— разработчиков? Предположим, у вас есть данные о движении грозовых фронтов, и вы хотите показывать их пользователю в режиме реального времени. В этом случае импорт файлов на карту вручную не подойдёт. Однако предполагаю, что формирование KML-файлов для решения этой задачи тоже может пригодиться: вы сможете встроить в своё приложение карту и отрисовывать данные уже программным способом.

Как всегда, это история о балансе: сделать быстро или основательно, разбираться самостоятельно или обратиться за помощью, следовать инструкции или интуиции. Когда вам в следующий раз придётся делать такой выбор, надеюсь, моя история не будет вас перетягивать на одну из сторон, но напомнит: иногда вы можете больше, чем сами от себя ожидаете.

И конечно, желаю вам качественных данных и успехов в их визуализации!

Ссылки вдогонку

Читайте так же: