В этом примере подробно объясняется, как использовать GeoPandas для визуализации структурированных данных.
Чтобы начать, перейдите на mecsimcalc.com/create, нажмите Карты и выберите Создать новое пустое приложение.
Шаг 1: Код
Получить данные
Сначала импортируйте или создайте геопространственные данные для визуализации. В этом примере мы создадим DataFrame
Panda, а затем преобразуем его в GeoDataFrame
.
Создайте DataFrame с координатами Easting и Northing.
df = pd.DataFrame({"Easting": [444246.35, 444247.044, 444247.3266, 444247.5912, 444247.8385],
"Northing": [5465340.18, 5465359.6118, 5465367.5256, 5465374.9338, 5465381.8589]})
df
выглядит так:
Объедините столбцы Easting
и Northing
в один столбец. Это облегчит создание фигур позже. Новый столбец должен называться geometry
, как будет объяснено позже.
df["geometry"] = df[["Easting", "Northing"]].values.tolist()
df
выглядит так:
Теперь преобразуйте df
DataFrame в GeoDataFrame, gdf
.
gdf = geopandas.GeoDataFrame(df, crs="EPSG:26911")
Система отсчета координат (CRS)
Обратите внимание, что координаты указаны в восточном направлении и северном направлении, тогда как GeoPandas ожидает широту и долготу. Поэтому координаты должны быть проецированы на широту и долготу. К счастью, GeoDataFrame
имеет встроенную crs
(систему отсчета координат), которая применяет проекцию к столбцу geometry
.
В этом примере crs
равно "EPSG:26911"
, но для вашего кода оно, вероятно, будет другим, в зависимости от используемой системы отсчета координат.
СОВЕТ
Если ваши координаты уже указаны в широте и долготе, вы можете пропустить настройку атрибута crs
.
ОПАСНОСТЬ
Ваши фигуры должны находиться в столбце geometry
, чтобы проекция crs
применялась правильно!
Манипулировать данными
Преобразуйте столбец geometry
в точки, применив функцию Point
из shapely.geometry
ко всем строкам, используя .apply()
.
gdf["geometry"] = gdf["geometry"].apply(Point)
gdf
выглядит так:
Далее мы создадим дополнительные геометрии в отдельном GeoDataFrame
, а затем добавим его в конец существующих GeoDataFrame
, gdf
.
Используйте LineString
и Polygon
для создания новых фигур внутри нового GeoDataFrame
под названием more_geometries
.
СОВЕТ
Вы можете найти более стройные геометрии здесь.
Используйте pd.concat
для присоединения more_geometries
к концу gdf
. Обратите внимание, что axis=0
означает объединение в новую строку, тогда как axis=1
означает объединение в новый столбец.
more_geometries = geopandas.GeoDataFrame(
{
"geometry": [
LineString([[444248.0694, 5.465388e06], [444248.2847, 5.465394e06], [444248.4852, 5.465400e06]]),
Polygon([[444243.6719, 5.465405e06], [444248.8454, 5.465410e06], [444249.0068, 5.465415e06], [444299.1569, 5.465419e06]]),
]
}
)
gdf = pd.concat((gdf, more_geometries), axis=0)
gdf
выглядит так:
Теперь, когда мы определили все геометрии, мы можем добавить наши вычисленные значения для каждой геометрии в виде нового столбца с именем value
. Здесь мы используем некоторые случайные числа, но вам следует вычислять более значимые числа с помощью других библиотек, таких как Numpy, GeoPandas или Pandas.
gdf["value"] = [1,2,3,4,5,6,7] # computed values
gdf
выглядит так:
Экспорт карты
Интерактивная карта
Экспортируйте gdf
GeoDataFrame как интерактивную карту:
m1 = gdf.explore("value", cmap="Spectral", name="My shapes", tiles=None)
m1.options["preferCanvas"] = True
Где,
gdf.explore
возвращает объект карты Folium."value"
— это столбецgdf
, который содержит числовые значения для визуализации.cmap
— цвет шкалы. Смотрите больше цветовых карт здесь.name
– это имя LayerControl для геометрических фигур.tiles=None
чтобы не устанавливать тайл карты. В большинстве случаев вам не нужно указывать атрибутtiles
.m1.options["preferCanvas"] = True
следует установить наTrue
, когда вы рисуете много геометрии или когда карта кажется медленной или тормозной. В противном случае вы можете пропустить эту строку.
Затем мы добавим на карту LayerControl, который позволит переключать фрагменты карты и включать и выключать геометрию.
Добавьте каждое TileLayer
отдельно на карту. Обратите внимание, что OpenStreetMap и Stamen Terrain являются строками, тогда как Satellite должен указывать URL-адрес для tiles
. Это связано с тем, что OpenStreetMap и Stamen Terrain — это тайлы карты, встроенные в Folium, тогда как Satellite — это пользовательский фрагмент карты.
folium.TileLayer("OpenStreetMap", name="Road").add_to(m1)
folium.TileLayer("Stamen Terrain", name="Terrain").add_to(m1)
folium.TileLayer(
tiles="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
attr="Esri",
name="Satellite",
).add_to(m1)
folium.LayerControl().add_to(m1)
Наконец, преобразуйте объект карты в HTML, который можно отобразить на веб-странице.
interactive_map = m1._repr_html_()
Статическая карта
Мы также экспортируем карту как статический график Matplotlib.
def plt_show(plt, width=500, dpi=100): # Converts matplotlib plt to image data string # plt is the matplotlib pyplot or figure # width is the width of the graph image in pixels # dpi (dots per inch) is the resolution of the image bytes = io.BytesIO() plt.savefig(bytes, format="png", dpi=dpi) # Save as png image if hasattr(plt, "close"): plt.close() bytes.seek(0) base64_string = "data:image/png;base64," + base64.b64encode(bytes.getvalue()).decode("utf-8") return "<img src='" + base64_string + "' width='" + str(width) + "'>"
m2 = gdf.plot("value", cmap="Spectral", legend=True) static_map = plt_show(m2.figure)
Где,
gdf.plot
возвращает фигуру Matplotlib."value"
— это столбецgdf
, который содержит числовые значения для визуализации.cmap
— цвет шкалы. Смотрите больше цветовых карт здесь.legend=True
отображает цветную полосу справа.- Передайте
m2.figure
вplt_show
, чтобы вернуть изображение, которое можно отобразить на веб-странице.
Полный код
import io import base64 import folium import geopandas import pandas as pd from shapely.geometry import LineString, Point, Polygon
def plt_show(plt, width=500, dpi=100): # Converts matplotlib plt to image data string # plt is the matplotlib pyplot or figure # width is the width of the graph image in pixels # dpi (dots per inch) is the resolution of the image bytes = io.BytesIO() plt.savefig(bytes, format="png", dpi=dpi) # Save as png image if hasattr(plt, "close"): plt.close() bytes.seek(0) base64_string = "data:image/png;base64," + \ base64.b64encode(bytes.getvalue()).decode("utf-8") return "<img src='" + base64_string + "' width='" + str(width) + "'>"
def main(inputs): # Create data as Panda's DataFrame df = pd.DataFrame({"Easting": [444246.35, 444247.044, 444247.3266, 444247.5912, 444247.8385], "Northing": [5465340.18, 5465359.6118, 5465367.5256, 5465374.9338, 5465381.8589]}) # Merge `Easting` and `Northing` columns into one column called `geometry` df["geometry"] = df[["Easting", "Northing"]].values.tolist()
# Convert DataFrame to GeoDataFrame and project coordinates to "EPSG:26911" gdf = geopandas.GeoDataFrame(df, crs="EPSG:26911") # Convert all geometries into Point shapes gdf["geometry"] = gdf["geometry"].apply(Point)
# Create a new GeoDataFrame with a LineString and a Polygon more_geometries = geopandas.GeoDataFrame( { "geometry": [ LineString([[444248.0694, 5.465388e06], [444248.2847, 5.465394e06], [444248.4852, 5.465400e06]]), Polygon([[444243.6719, 5.465405e06], [444248.8454, 5.465410e06], [ 444249.0068, 5.465415e06], [444299.1569, 5.465419e06]]), ] } ) # Add the new geometries as new rows to the existing GeoDataFrame, gdf gdf = pd.concat((gdf, more_geometries), axis=0)
# Add computed values as a new column to gdf gdf["value"] = [1, 2, 3, 4, 5, 6, 7] # computed values
# Export gdf as an interactive Folium map m1 = gdf.explore("value", cmap="Spectral", name="My shapes", tiles=None) # Set `preferCanvas` to optimize performance of map m1.options["preferCanvas"] = True
# Add a LayerControl with different TileLayers folium.TileLayer("OpenStreetMap", name="Road").add_to(m1) folium.TileLayer("Stamen Terrain", name="Terrain").add_to(m1) folium.TileLayer( tiles="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", attr="Esri", name="Satellite", ).add_to(m1) folium.LayerControl().add_to(m1)
# Get Folium map as HTML string interactive_map = m1._repr_html_()
# Export gdf as Matplotlib plot image m2 = gdf.plot("value", cmap="Spectral", legend=True) static_map = plt_show(m2.figure)
return { "interactive_map": interactive_map, "static_map": static_map }
Шаг 2: Вывод
{{ outputs.interactive_map }}
{{ outputs.static_map }}
Для получения дополнительных руководств посетите здесь.