In Meiner Meinung nach ist eine der besten Eigenschaften von Geodaten die Möglichkeit zur 3D-Visualisierung. Aufgrund der Menge an Rechenressourcen, die für solche Berechnungen benötigt werden, wird dies jedoch nur selten in Python durchgeführt (oft JavaScript und seine Bibliotheken werden als Alternativen verwendet). In einem meiner vorherigen Artikel habe ich sechs Python-Pakete vorgestellt, mit denen sich schöne statische und interaktive Karten erstellen lassen, allerdings nur im 2D-Raum.
Heute möchte ich diese Lücke schließen und mit Ihnen ein wirklich elegantes und effizientes Framework für leistungsstarke webbasierte Visualisierungen untersuchen. deck.jldas auch eine Python-Bibliothek hat PyDeck.
Um die Möglichkeiten in Python richtig zu erkunden, benötigen wir einen großen georäumlichen Datensatz. Ein perfekter Kandidat dafür ist Kriminalitätsdaten von Los Angeles 2010–2020 Datensatz von Kaggle. Glücklicherweise hat es eine offene Lizenzsodass wir es frei für unsere Zwecke verwenden können.
Die Autoren verteilen zwei csv Dateien, die wir zu einer einzigen zusammenführen und dabei alle Spalten außer Längen- und Breitengrad (Koordinaten der Orte, an denen die Verbrechen begangen wurden) herausfiltern.
🐍Der vollständige Python-Code: GitHub.
import numpy as np
import pandas as pd
import xarray as xr
import geopandas as gpd
import random
import mathimport matplotlib.pyplot as plt
from shapely import Level
import cartopy
import cartopy.crs as ccrs
import cartopy.function as cfeature
import warnings
warnings.filterwarnings('ignore')
latest = pd.read_csv('./LA Crimes/Crime_Data_from_2020_to_Present.csv')(('LAT', 'LON'))
previous = pd.read_csv('./LA Crimes/Crime_Data_from_2010_to_2019.csv')(('LAT', 'LON'))
df = pd.concat((previous, latest))
df = df((df.LON!=0) & (df.LAT!=0)) #zeros are Nans in response to meta information
Nach dem Laden in Pandas möchte ich eine statische 2D-Visualisierung durchführen mit kartendachnur um eine zuverlässige Referenz zu haben. Wenn wir die Daten einfach darstellen, erhalten wir eine Menge Datenpunkte, die für uns nutzlos sind.
Führen wir stattdessen eine räumliche Interpolation mit der NN-Methode durch (mehr dazu können Sie in meinem anderen Artikel lesen).
Im Grunde bedeutet es, dass wir vereinzelte Beobachtungen in ein geografisches Raster übertragen (PyDeck macht dasselbe, in diesem Fall kann man es als Datenaggregation bezeichnen).
def coords(x,y, base=0.01):
x, y = spherical(base * math.ceil(abs(x)/base),2), spherical(base * math.ceil(y/base),2)
return (y,x)def NN(information, LAT, LON):
array = np.zeros((LAT.form(0), LON.form(0)),dtype=int)
onGrid = information.apply(lambda row: coords(row.LAT, row.LON, 0.01), axis = 1).value_counts()
for coor in onGrid.index:
lon_idx, lat_idx = np.the place(LON==coor(0)), np.the place(LAT==coor(1))
array(lat_idx,lon_idx) = int(onGrid(coor))
return array
Nachdem der Algorithmus fertig ist (Sie müssen einige Zeit warten, da wir mehr als 2 Millionen Zeilen zu verarbeiten haben), können wir seine Ergebnisse in ein xarray Datensatz und ordnen Sie ihn zu.
LAT, LON = np.arange(spherical(df.LAT.min()), spherical(df.LAT.max()), 0.01).astype(np.float32), np.arange(spherical(df.LON.min()), spherical(df.LON.max()), 0.01).astype(np.float32)
crimes = NN(df, LAT, LON)
ds = xr.Dataset(
{'Crimes': (('lat', 'lon'), crimes)},
coords={'lat': LAT, 'lon': LON})fig, ax = plt.subplots(subplot_kw=dict(projection=ccrs.PlateCarree()), figsize=(16, 9))
ds.Crimes.plot(ax=ax, cmap='Reds')
ax.set_extent((-118.9, -118.1, 33.6, 34.5 ), crs=ccrs.PlateCarree())
ax.gridlines(draw_labels=True,linewidth=2, coloration='black', alpha=0.5, linestyle='--')
ax.add_feature(cfeature.BORDERS, edgecolor='black', linewidth=1)
ax.add_feature(cfeature.COASTLINE, edgecolor='black', linewidth=1)
ax.add_feature(cartopy.function.RIVERS, edgecolor='blue', linewidth=0.5)
states_provinces = cfeature.NaturalEarthFeature(
class='cultural', identify='admin_1_states_provinces',
scale='10m', facecolor='none')
plt.present()
Aus meiner Sicht sieht es nett und informativ aus, aber wenn Sie dieses Projekt jemandem verkaufen müssen, werden Sie mit einer solchen Karte höchstwahrscheinlich scheitern xD. Lassen Sie uns additionally PyDeck mit pip installieren und sehen, was es für uns tun kann!
Der erste Kartenlayertyp, den ich schön fand, warfare der Hexagon-Layer. Sie müssen ihn beim Erstellen des L angeben.ayer Variable in PyDeck. Es gibt noch mehrere andere wichtige Parameter für uns:
- Radius (der Radius des Sechsecks in Metern, d. h. räumliche Auflösung in m);
- elevation_scale (Skalierungsfaktor für Behälter, je größer der Wert, desto höher die Sechsecke);
- elevation_range (minimale und maximale Höhe);
- auswählbar (interaktive Anzeige der Werte);
- extrudiert (Zellenerhöhung).
layer = pdk.Layer(
'HexagonLayer',
df,
get_position=('LON', 'LAT'),
radius=500, #bin radius
auto_highlight=True,
elevation_scale=50, #scale issue for bins (the better - the upper)
elevation_range=(0, 3000),
pickable=True,
extruded=True,#cell elevation
)
Die zweite Variable, die wir erstellen müssen, ist der Ansichtsstatus. Wir müssen ihn mit Folgendem füttern:
- Längen-und Breitengrad;
- Zoom (Anfangszoom);
- min_zoom und max_zoom;
- Peilung (linker/rechter Blickwinkel);
- Neigung (Blickwinkel nach oben/unten).
view_state = pdk.ViewState(
longitude=-118.3,
latitude=34.4,
zoom=8,
min_zoom=6,
max_zoom=15,
bearing=-20,#left/proper angle
pitch=20, #up/down angle
)
Da wir über einen großen Datensatz verfügen, zeigt Google Colab nicht den gesamten Datensatz an. Sie haben daher zwei Möglichkeiten:
- Wählen Sie N Zeilen aus dem Datensatz aus.
- Speichern Sie die Karte als HTML und öffnen Sie sie in Ihrem Browser.
Wenn Sie die zweite Choice wählen, erhalten Sie Folgendes:
Ehrlich gesagt gefällt mir das Aussehen von Sechsecken, ich habe sie jedoch noch nie in einer wissenschaftlichen Arbeit/Präsentation/Vorlesung gesehen und würde daher empfehlen, sie bewusst einzusetzen.
Versuchen wir nun, eine ähnliche Visualisierung zu erstellen, allerdings mit Spalten. In diesem Fall müssen wir der Funktion jedoch den zuvor erstellten Xarray-Datensatz übergeben und die Farbe und die zu visualisierende Variable angeben:
layer = pdk.Layer(
'ColumnLayer',
ds.to_dataframe().reset_index(),
get_position=('lon', 'lat'),
get_elevation='Crimes',
elevation_scale=10,
radius=200,
get_fill_color=('Crimes', 220),
pickable=True,
extruded=True,
)
Im Wesentlichen ist das Streudiagramm eine Punktwolke, aber die Autoren von PyDeck haben Zylinder entwickelt, die ziemlich einzigartig aussehen:
layer = pdk.Layer(
'ColumnLayer',
df(:15000),
get_position=('LON', 'LAT'),
auto_highlight=True,
get_radius=200, # Radius is given in meters
get_fill_color=(180, 0, 200, 140), # Set an RGBA worth for fill
pickable=True)
Eine wirklich coole Sache an PyDeck ist, dass es Benutzern wie Plotly, Geemap, Folium und anderen interaktiven Mapping-Instruments ermöglicht, die Basiskarte zu ändern. Das heißt, Sie können eine Karte entsprechend dem Kontext Ihres Projekts entwerfen:
r = pdk.Deck(layers=(layer),
initial_view_state=view_state,
map_style=pdk.map_styles.LIGHT, # ‘mild’, ‘darkish’, ‘street’, ‘satellite tv for pc’, ‘dark_no_labels’, and ‘light_no_labels
)
Das nächste Function, das ich tremendous hilfreich finde, ist die Änderung der interaktiven Datenbeschreibung. Indem man den Cursor auf eine Spalte/ein Sechseck/einen Punkt setzt, kann man Metainformationen erhalten, aber das sieht oft ein bisschen absurd aus. Aber in PyDeck kann man das leicht umgehen:
r = pdk.Deck(layers=(layer),
initial_view_state=view_state,
"html": "<b>Variety of crimes:</b> {elevationValue}",
"fashion": {
"backgroundColor": "yellow",
"coloration": "black"
}
},
)
Und schließlich ist das erstaunlichste Function dieser Bibliothek Ihre Möglichkeit, den Blickwinkel auf der Karte einfach durch Klicken mit der rechten Maustaste zu ändern:
from ipywidgets import HTMLtextual content = HTML(worth='Transfer the perspective')
def filter_by_bbox(row, west_lng, east_lng, north_lat, south_lat):
return west_lng < row('lng') < east_lng and south_lat < row('lat') < north_lat
def filter_by_viewport(widget_instance, payload):
west_lng, north_lat = payload('information')('nw')
east_lng, south_lat = payload('information')('se')
filtered_df = df(df.apply(lambda row: filter_by_bbox(row, west_lng, east_lng, north_lat, south_lat), axis=1))
r.deck_widget.on_click(filter_by_viewport)
Ich genieße es auf jeden Fall PyDeck und planen, tiefer einzutauchen in die deck.jl Framework. Mit einer tremendous einfachen und intuitiven Syntax können Benutzer beeindruckende Visualisierungen erstellen, die energieeffizient sind. Python schränkt die Fähigkeiten dieses Pakets stark ein, additionally sehen Sie sich deren Galeriees ist überwältigend, insbesondere ihre experimentelle GlobalView-Funktion …
Hoffentlich warfare dieser Artikel für Sie informativ und aufschlussreich!
===========================================
Alle meine Veröffentlichungen auf Medium sind kostenlos und frei zugänglich, deshalb würde ich es sehr schätzen, wenn Sie mir hier folgen würden!
Ps Ich interessiere mich sehr für (Geo)Information Science, ML/AI und Klimawandel. Wenn Sie additionally an einem Projekt mit mir zusammenarbeiten möchten, kontaktieren Sie mich bitte unter LinkedIn.
🛰️Folgen Sie für mehr🛰️