Здравствуй, Хабр!
В этой статье я хочу рассмотреть пакет Python под названием "Shapely" и показать, как он может помочь в решении задач, как уже помог мне.
Содержание статьи:
Географические координаты и форматы хранения
Проблема: сложности с обработкой координат в автотестах
Что такое "Shapely"?
Основные возможности "Shapely" для работы с геометрией
Пример автотеста с использованием пакета "Shapely"
Заключение
Если хотите разобраться самостоятельно или углубиться в детали, то можете воспользоваться документацией :)
Географические координаты и форматы хранения
Для начала вспомним, что такое географические координаты. В школе на уроках географии нас просили найти разные точки на карте и, например, показать, где находиться КанадА?
Географические координаты — это система координат, используемая для определения положения точек на поверхности Земли. Они основаны на двух ключевых параметрах: широте и долготе. Эта система позволяет точно указывать любое местоположение на планете. Важно, что землю рассматривают не как элипсойд вращения, а как шар.
Основные компоненты географических координат
-
Широта (latitude):
Широта указывает, насколько далеко точка находится от экватора. Она измеряется в градусах (°) и может принимать значения от 0° на экваторе до 90° на полюсах.
-
Широта делится на:
Северную широту (N) — положительные значения от 0° до 90°.
Южную широту (S) — отрицательные значения от 0° до -90°.
-
Долгота (longitude):
Долгота указывает, насколько далеко точка находится от начального меридиана, который проходит через Гринвич в Англии. Она также измеряется в градусах (°).
-
Долгота делится на:
Восточную долготу (E) — положительные значения от 0° до 180°.
Западную долготу (W) — отрицательные значения от 0° до -180°.
Пример:
Широта: 55.7558° N (северная широта)
Долгота: 37.6173° E (восточная долгота)
Эти координаты означают, что Москва расположена примерно на 55.76 градуса к северу от экватора и на 37.62 градуса к востоку от начального меридиана в Гринвиче.
Форматы хранения
Существует множество различных форматов, в которых могут храниться геометрические значения. На некоторых я остановлюсь более подробно, а некоторые просто перечислю и это далеко не все
1. Well-Known Text (WKT)
WKT — это текстовый формат, который описывает геометрические объекты. Он используется для представления простых и сложных геометрий, таких как точки, линии и полигоны.
2. Well-Known Binary (WKB)
WKB — это бинарное представление геометрических объектов, которое более эффективно для хранения и передачи данных, чем WKT. WKB используется в базах данных, таких как PostGIS, для хранения геометрических значений.
Пример: Бинарное представление точки может выглядеть так: 01010000005839B3D70A3D7C0A5B9B74814C0E00
3. GeoJSON
GeoJSON — это формат данных, основанный на JSON, который используется для представления различных геометрических объектов, включая точки, линии и полигоны. Он часто используется в веб-приложениях и для обмена географическими данными.
Примеры:
-
Точка:
jsonCopy code{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [30, 10] }, "properties": {} }
-
Полигоны:
jsonCopy code{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [[[30, 10], [40, 40], [20, 40], [10, 20], [30, 10]]] }, "properties": {} }
4. KML (Keyhole Markup Language)
KML — это XML-формат, который используется для отображения географических данных в программах, таких как Google Earth. KML поддерживает различные геометрические объекты, такие как точки, линии и полигоны, а также аннотации и стили.
Пример:
xmlCopy code<kml xmlns="http://www.opengis.net/kml/2.2">
<Placemark>
<name>Точка</name>
<Point>
<coordinates>30,10</coordinates>
</Point>
</Placemark>
</kml>
5. GML (Geography Markup Language)
GML — это XML-формат, разработанный для представления географических данных. Он более сложный и мощный, чем KML, и позволяет описывать геометрию и топологию.
6. WFS (Web Feature Service)
WFS — это стандарт OGC для доступа к географическим данным через веб. Он может возвращать геометрические значения в различных форматах, включая GML и GeoJSON.
7. Shapefile
Shapefile — это формат, разработанный Esri для хранения географических объектов в виде наборов файлов. Он используется в геоинформационных системах (ГИС) для хранения векторной информации, такой как точки, линии и полигоны. Каждый шейп-файл состоит из нескольких файлов (например, .shp, .shx, .dbf).
8.PostGIS
PostGIS — это расширение для PostgreSQL, которое добавляет поддержку географических объектов. Он использует собственные форматы хранения (например, WKB и WKT) и предоставляет функции для работы с геометрией, такие как вычисление расстояний и пространственные запросы.
9. MapInfo TAB
TAB — это формат, используемый программным обеспечением MapInfo для хранения векторных географических данных. Он может включать точки, линии и полигоны, а также сопутствующую атрибутивную информацию.
10. DGN (MicroStation)
DGN — это формат файлов, используемый в программном обеспечении MicroStation. Он поддерживает векторные данные и может содержать геометрические объекты, такие как линии, полигоны и текстовые метки.
11. GPKG (GeoPackage)
GeoPackage — это формат контейнера для хранения географических данных, который поддерживает векторные и растровые данные. Это стандарт OGC, который позволяет хранить географические объекты вместе с метаданными в одном файле.
12. WMS (Web Map Service)
13. FlatGeobuf
14. SDF (Spatial Data File)
15. Raster Formats (TIFF, GeoTIFF)
16. CSV с географическими координатами
И т. д.
Проблема: сложности с обработкой координат в автотестах
Обычно в базе данных координаты не хранятся в формате широты и долготы. В моем случае, в PostgreSQL они представлены в формате Well-Known Binary (WKB), что не позволяет напрямую использовать широту и долготу через latitude
и longitude
. Хотя бывают исключения, когда широта и долгота разделяются по отдельным столбцам.
01010000008BEFC6F6B3FD43409A9999999999B641
Для работы с точками на карте многие используют Elasticsearch, так как он предоставляет встроенные возможности для работы с геоданными. Это включает поддержку различных форматов для хранения координат (широты и долготы), а также типы полей, которые позволяют эффективно индексировать и искать географические данные. В Elasticsearch широта и долгота хранятся в читабельном формате Well-Known Text (WKT):
POINT (37.6173 55.7558)
Главное — не перепутать широту с долготой, иначе вместо Москвы можно попасть в Иран :)
При написании автотестов можно обращаться к базе Elasticsearch и получать оттуда координаты. Но если требуется сравнить значения из баз данных, на помощь приходит библиотека "Shapely".
Что такое "Shapely"?
Shapely — это библиотека для Python, которая помогает работать с геометрическими объектами, такими как точки, линии и полигоны. Она позволяет создавать, изменять и анализировать геометрические фигуры, что особенно полезно в задачах, связанных с картами и географией.
Например, с помощью Shapely можно легко рассчитать расстояние между точками, проверить, пересекаются ли две линии, или определить, находится ли точка внутри полигона. Библиотека также поддерживает разные форматы для представления геометрии, что делает ее удобной для работы с данными из баз данных и других источников.
Библиотека Shapely не сосредоточена на форматах хранения данных или системах координат, но её можно легко интегрировать с другими библиотеками, которые работают с этими аспектами.
Основные возможности "Shapely" для работы с геометрией
Использование "Shapely"
Вот пример из документации https://pypi.org/project/shapely/ создания круглой области вокруг точки с помощью буферизации в скалярном геометрическом интерфейсе:
# Импортируем класс Point
from shapely import Point
# Создаем объект Point, который представляет точку с координатами (0.0, 0.0)
# Затем используем метод buffer(10.0) для создания окружности радиусом 10.0 вокруг этой точки.
patch = Point(0.0, 0.0).buffer(10.0)
# Выводим полученный объект 'patch' на экран.
# Это будет полигон, который описывает окружность с радиусом 10.0, с координатами его границ.
print(patch)
# Вычисляем и выводим площадь полигона 'patch'.
# Площадь равна π * r^2, где r = 10.0, что примерно равно 314.16.
# В этом случае результат будет примерно 313.65.
print(patch.area)
Другой пример:
import shapely
from shapely.geometry import Point, Polygon
# Задаем координаты широты и долготы в виде точки
# Например, точка для Москвы (55.7558, 37.6173)
moscow = Point(37.6173, 55.7558)
# Создаем полигон, представляющий некоторую область
# Например, квадрат вокруг Москвы (можно представить в виде 4-х вершин)
# Координаты: (37.6, 55.75), (37.6, 55.76), (37.62, 55.76), (37.62, 55.75)
region = Polygon([
(37.6, 55.75),
(37.6, 55.76),
(37.62, 55.76),
(37.62, 55.75)
])
# Проверяем, находится ли точка Москвы внутри заданного полигона
is_in_region = region.contains(moscow)
# Выводим результат
if is_in_region:
print("Москва находится в заданной области.")
else:
print("Москва не находится в заданной области.")
Пример автотеста с использованием пакета "Shapely"
Задача: У вас есть две базы данных: PostgreSQL с таблицей, содержащей местоположения объектов в формате WKB, и Elasticsearch с индексом, содержащим точки в формате WKT. Вам нужно выполнить сравнение координат между двумя источниками данных и найти совпадения.
Важно! Допущение: Коннекты к базам данных у вас не будут в теле теста, а будут определены отдельно. Предположим, что запрос к базе данных PostgreSQL вы сделаете с помощью SQLAlchemy. В этом примере мы просто присвоим переменные. То же самое касается Elasticsearch. Схемы БД у вас хранятся отдельно и определены.
from shapely import wkb, wkt
import unittest
# Заранее заданное значение WKB для Москвы в шестнадцатичном формате
point_moscow_wkb = '01010000008BEFC6F6B3FD43409A9999999999B641'
# Преобразуем WKB из строки в байтовый формат
# Это необходимо для корректной работы с Shapely
moscow_wkb = bytes.fromhex(point_moscow_wkb)
# Преобразуем WKB в объект Shapely
moscow_point = wkb.loads(moscow_wkb)
# Координаты Москвы в формате WKT
moscow_wkt = "POINT (37.6173 55.7558)" # Точка (долгота, широта)
# Преобразуем WKT в объект Shapely
moscow_point_wkt = wkt.loads(moscow_wkt)
# Сравнение координат: ищем совпадения
if moscow_point.equals(moscow_point_wkt):
# Метод equals() проверяет, равны ли два геометрических объекта
# В данном случае он сравнивает точку из WKB и точку из WKT
print("Координаты Москвы совпадают в форматах WKB и WKT.")
else:
print("Координаты Москвы не совпадают в форматах WKB и WKT.")
# Автотест
class TestGeometricComparison(unittest.TestCase):
def test_coordinates_equivalence(self):
point_moscow_wkb = '01010000008BEFC6F6B3FD43409A9999999999B641'
moscow_wkb = bytes.fromhex(point_moscow_wkb)
moscow_point = wkb.loads(moscow_wkb)
moscow_wkt = "POINT (37.6173 55.7558)"
moscow_point_wkt = wkt.loads(moscow_wkt)
# Проверка равенства
self.assertTrue(moscow_point.equals(moscow_point_wkt),
"Координаты Москвы не совпадают в форматах WKB и WKT.")
Конечно, ваш автотест будет выглядеть иначе, в зависимости от особенностей вашего проекта и задач. Это просто как пример
Заключение
Пакет "Shapely" представляет собой мощный инструмент для работы с геометрическими данными в Python. Его возможности охватывают широкий спектр задач, связанных с манипуляцией и анализом геометрических объектов, включая создание, изменение и сравнение геометрий. "Shapely" предоставляет удобные интерфейсы для работы с различными форматами
Спасибо за уделенное время!
Если вам понравилась статья или вы узнали что-то новое, если не сложно накиньте пожалуйста "кармы"?. Коплю карму, чтобы делиться полезной информацией или натолкнуть кого-то на мысль о том, как ещё можно решить вашу задачу.
Конечно, я понимаю, что в одной статье невозможно ответить на все вопросы, но я лишь хотел рассказать о таком, на мой взгляд, полезном инструменте, который может облегчить вашу жизнь при выполнении повседневных задач.