Python Erstellen von cartopy-Karten beschleunigen

Woodz

Lieutenant
Registriert
Apr. 2009
Beiträge
689
Hallo.
Ich erstelle in einer Prozedur ca. 60 Karten in die ich Messwerte plotte. Das sind ca. 400 Messwerte pro Karte.
Ich benutze bereits Multiprozessing (3 Prozesse) um die Erstellung etwas anzutreiben, aber ich brauche immer noch ca. 5 Minuten für alle Karten.
Die Frage ist nun, ob ich das Ganze noch weiter Beschleunigen kann (Außer mehr Prozesse zu nutzen (was auch geplant ist :))). Zum Einen stört mich die Nutzng der for-Schleife noch gewaltig. Zudem frage ich mich, ob es möglich wäre die cartopy-basemap abzuspeichern und jedes mal neu zu laden, anstatt sie jedes mal neu erstellen zu müssen.
Für weitere Inspirationen wäre ich sehr dankbar!


Hier der vereinfachte Code den ich zum Erstellen der Karten nutze:
Code:
import matplotlib.pyplot as plt
import cartopy
import cartopy.crs as ccrs
import cartopy.feature as cfeature


res = '10m'

lllon=6.00
lllat=47.0
urlon=15.4
urlat=55.10
central_lon = (lllon + urlon)/2
central_lat = (lllat + urlat)/2

proj = ccrs.TransverseMercator(central_longitude = central_lon, central_latitude = central_lat)

list = ["Niederschlag", "Temperatur", "Schneehoehe", etc..]

for parameter in list:

    # create map
    ax = plt.axes(projection=proj)
    ax.set_extent([lllon, urlon, lllat, urlat])
    land = cfeature.NaturalEarthFeature('physical', 'land', res, edgecolor='face', facecolor='#1F1F1F', zorder=0)
    states_provinces = cfeature.NaturalEarthFeature(category='cultural', name='admin_1_states_provinces_lines', scale='10m', facecolor='none', linewidth=0.1)

    # add features
    ax.add_feature(states_provinces, edgecolor='white')
    ax.add_feature(land)
    ax.add_feature(cartopy.feature.BORDERS.with_scale(res), linestyle='-', linewidth=0.3, edgecolor='white')
    ax.add_feature(cartopy.feature.COASTLINE.with_scale(res), linestyle='-', edgecolor='#1F1F1F', linewidth=0.1)
    ax.add_feature(cartopy.feature.OCEAN.with_scale(res), facecolor='grey')

    # data plotting
    for x, y, value in zip(data["lon"].values, data["lat"].values, data["parameter"].values):
        ax.text(x, y, value, color='silver', size=3, transform = ccrs.Geodetic())


    plt.title("Title")
    plt.savefig("Example.png", format="png")

    plt.clf()
 
Zuletzt bearbeitet:
Hej,

um die 24.000 Messwerte in 5 Minuten klingt doch garnichtmal so übel!?
Hab in einem Projekt für einen Kunden mal was Ähnliches umgesetzt, da ging es aber immer nur um die Visualisierung eines Reports und immer nur um eine einzige Karte pro Anwendungsfall - daher spielte Tempo keine Rolle (und es wurde PHP genutzt).
Der Kunde war zufrieden, weil die Karte immer "sofort" da war - denn die kannten noch Zeiten, in denen Ergebnisse auf eine DIN-A2-Landkarte geplottet wurden (also auf Papier).

Zu Deiner for-Schleife (Z. 18): Beide Variablen "parameter" und "list" kommen in Deinem Snippet nicht nochmal vor; so lässt sich unmöglich etwas zu Optimierungspotential sagen.
 
list und parameter sind letzten Endes nicht relevant. Wie ich bereits geschrieben hatte, handelt es sich hier nur um eine vereinfachte Version des Moduls.
Aber sagen wir:
Code:
list = ["Niederschlag", "Temperatur", "Schneehoehe", etc..]
data ...  ist ein pandas DataFrame

Code wurde oben angepasst.

Ok, die Verwendung von:
Code:
zip(data["lat"].values, data["lon"].values, data["parameter"].values)
ist etwas umständlich, entspricht aber auch nicht der tatsächlichen Version. Es soll nur grob verdeutlichen, dass ich aus 3 listen eine 3-spaltige Liste erstelle, um dann den Wert (value) an seine Position zu plotten (x,y).

"um die 24.000 Messwerte in 5 Minuten klingt doch garnichtmal so übel!?"

Ja, das ist schon ok, aber ich musste mein bisherige Lösung mit Hilfe des Moduls "basemap" auf "cartopy" umbauen, weil basemap als deprecated gelabelt wurde.

In meiner bisherigen Lösung war es möglich die Basemap, die ich erstellt habe mit pickle binär abzuspeichern. Das hat natürlich viel Zeit eingespart und ich kam auf zeiten von rund 3 Minuten. Folglich sind 5 Minuten aktuell noch etwas viel und ich suche nun nach Optimierungsmöglichkeiten. Nach ersten Versuchen, scheint das speichern und spätere Bearbeiten von matplotlib-objekten nicht möglich zu sein. Aber ich lass mich gern eines Besseren belehren. ;)
 
Bei Deinen matplotlib-Objekten kann ich Dir leider auch nicht helfen, aber da wir "nur" über ca. 60 Karten sprechen, hast Du bestimmt grösstes Potential durch mehr Prozesse zu erwarten - das Problem sollte sich ja wunderbar parallelisieren lassen.
 
Mit Matplotlib wirst du vermutlich nicht viel mehr Performance rausholen können.
Du kannst evtl. das Backend ändern damit es etwas schnell läuft. Da Matplotlib aber anscheinend für hohe Qualität und nicht Geschwindigkeit optimiert wurde wird der Gewinn aber nicht so extrem hoch sein. Soweit ich weiß benutzt Matplotlib auch nur die CPU und nicht GPU, was bei großen Matrixoperationen im Allgemeinen nicht optimal ist.

Mein Tipp wäre, wenn es wirklich performant sein soll, schau mal ob du eine Lib zum Plotten findet, die auf der GPU ausgeführt wird. Selbst wenn du nur eine Intel IGPU haben solltest wird das um einen großen Faktor schneller sein als auf der CPU.
 
Ich habe mich nochmal mit den Möglichkeiten befasst, die figure - Objekte evtl. zu kopieren, so dass ich immer nur mit einer Kopie arbeite, aber das scheint auch nicht zu funktionieren. Ich werde wohl den Weg über mehr Prozesse gehen müssen , was ja auch geplant war. Danke
 
Zurück
Oben