<jupyter_start><jupyter_text>`xarray-leaflet``xarray-leaflet` ist eine xarray-Erweiterung für das Plotten von gekachelten Karten. Sowohl [xarray](http://xarray.pydata.org/) als auch [Leaflet](ipyleaflet.ipynb) können mit Datenfragmenten arbeiten, `xarray` durch [Dask Chunks](https://docs.dask.org/en/latest/array-chunks.html) und Leaflet durch *map tiles*. Mit `xarray-leaflet` arbeiten beide zusammen.  InstallationIhr könnt `xarray-leaflet` in eurem Jupyter-Kernel installieren mit:``` console$ pipenv install xarray-leafletInstalling xarray-leaflet……``` Standardmäßig generiert `xarray-leaflet` Kacheln in temporären Verzeichnissen. Bei dynamischen Karten wird bei jeder Interaktion mit der Karte ein neues Verzeichnis erstellt, entweder durch Ziehen oder Zoomen. Dies liegt daran, dass eine direkte Zuordnung zwischen dem Kachelverzeichnis und der URL besteht, unter der die Kacheln bereitgestellt werden. Da bei dynamischen Karten Kacheln nicht vom Browser zwischengespeichert werden sollten, muss sich die URL ständig ändern. Diese temporären Verzeichnisse werden derzeit nicht automatisch bereinigt. Ihr solltet dies daher regelmäßig selbst tun. In ix-Systemen sind sie unter `/tmp/xarray_leaflet_*`.  BeispielUm das Beispiel ausführen zu können, müsst Ihr zusätzlich die folgenden Pakete in Eurem Kernel installieren:* requests* tqdm* matplotlib* scipy<jupyter_code>import requests
import os
from tqdm import tqdm
import zipfile
import xarray as xr
import numpy as np
import scipy.ndimage
import matplotlib.pyplot as plt
import xarray_leaflet
from ipyleaflet import Map, basemaps<jupyter_output><empty_output><jupyter_text>Nun laden wir den [HydroSHEDS](https://hydrosheds.org/)-Datensatz herunter:<jupyter_code>url = 'https://edcintl.cr.usgs.gov/downloads/sciweb1/shared/hydrosheds/sa_30s_zip_grid/sa_acc_30s_grid.zip'
filename = os.path.basename(url)
name = filename[:filename.find('_grid')]
adffile = name + '/' + name + '/w001001.adf'

if not os.path.exists(adffile):
    r = requests.get(url, stream=True)
    with open(filename, 'wb') as f:
        total_length = int(r.headers.get('content-length'))
        for chunk in tqdm(r.iter_content(chunk_size=1024), total=(total_length/1024) + 1):
            if chunk:
                f.write(chunk)
                f.flush()
    zip = zipfile.ZipFile(filename)
    zip.extractall('.')
da = xr.open_rasterio(adffile)
da<jupyter_output><empty_output><jupyter_text>Ihr könnt sehen, dass die Projektion `EPSG: 4326` (auch bekannt als `WGS84`) ist. Dies ist die einzige Projektion, die derzeit von `xarray-leaflet` unterstützt wird. Hier entspricht die Koordinate `x` dem Längengrad und `y` dem Breitengrad. Die `band`-Koordinate ist hier ziemlich nutzlos. Die einzige Vorverarbeitung, die wir durchführen werden, besteht darin, NaN-Werte durch Nullen zu ersetzen.<jupyter_code>nan = da.attrs['nodatavals'][0]
da = da.sel(band=1)
da = xr.where(da==nan, 0, da)<jupyter_output><empty_output><jupyter_text>`xarray-leaflet` verfügt über zwei Modi, einen für statische Karten und einen für dynamische Karten. Mit dynamisch ist gemint, dass Ihr abhängig von der aktuellen Kartenansicht nicht dasselbe seht. Wenn Ihr beispielsweise zoomt, möchtet ihr vermutlich Details angezeigt bekommen, die vorher nicht zu sehen waren. Die Karte passt sich also wirklich an. Der Nachteil dynamischer Karten ist, dass Ihr bei der Interaktion mit der Karte mehr Flackern seht, da Kacheln aktualisiert werden müssen, sobald Ihr zieht oder zoomt.Das folgende Beispiel könnt Ihr so konfigurieren, dass es sowohl im statischen als auch im dynamischen Modus funktioniert. Ihr könnt die folgende dynamische Variable von `True` auf `False` ändern, um in den statischen Modus zu wechseln.<jupyter_code>dynamic = True
if not dynamic:
    global_vmin = np.min(da).values
    global_vmax = np.max(da).values<jupyter_output><empty_output><jupyter_text>Es gibt 3 Stufen in der `array-leaflet`, in denen ihr die Daten transofmieren könnt:1. Der erste Stufe arbeitet am sichtbaren Teil. Wenn Ihr dynamische Transformationen anwenden wollt, könnt ihr diese hier als Python-Funktionen mit den Daten als erstem Argument und optional Parameter aus den vorherigen Transformationen angeben. Da `transform0` die erste Transformation ist, werden `DataArray` keine weiteren Eingabeparameter zugewiesen. Hier geben wir die in den Daten vorhandenen Minimal- und Maximalwerte zurück:<jupyter_code>def transform0(da):
    if dynamic:
        vmin = np.min(da).values
        vmax = np.max(da).values
    else:
        vmin = global_vmin
        vmax = global_vmax
    return da, vmin, vmax<jupyter_output><empty_output><jupyter_text>2. Die zweite Transformation gilt für die Daten, die in jeder Leaflet-Kachel vor der Neuprojektion enthalten sind. Bei der Neuprojektion müsst Ihr Daten in den Speicher laden. Daher möchtet Ihr die Daten vermutlich verkleinern auf ungefähr die gleiche Anzahl von Pixeln wie in einer Kachel (256 x 256). In dieser Transformation möchtet Ihr auch, dass Ihre Daten zwischen `0` und `1` normalisiert werden, was wir dank der `vmin`- und `vmax`-Werte tun können, die wir aus der vorherigen Transformation erhalten haben.<jupyter_code>def transform1(xr_tile, vmin, vmax):
    ny, nx = xr_tile.shape
    wx = nx // (256 // 2)
    wy = ny // (256 // 2)
    if wx > 0 and wy > 0:
        xr_tile = xr_tile.coarsen(x=wx, y=wy, boundary="trim").max()
    xr_tile = (xr_tile - vmin) / (vmax - vmin)
    return xr_tile<jupyter_output><empty_output><jupyter_text>3. Bei der dritten und letzten Umwandlung werden die Daten in Web Mercator (die in Leaflet standardmäßig verwendete Projektion) transformiert. Dies ist die letzte Möglichkeit, Eure Daten zu transformieren, bevor Ihr sie in einer PNG-Datei speichert. Daher passen wir jetzt noch das Styling an und lassen die Flüsse dicker erscheinen, reduzieren die Amplitude mit einer Quadratwurzel und wählen eine Farbkarte.<jupyter_code>def transform2(np_tile):
    radius = 2
    circle = np.zeros((2*radius+1, 2*radius+1)).astype('uint8')
    y, x = np.ogrid[-radius:radius+1,-radius:radius+1]
    index = x**2 + y**2 <= radius**2
    circle[index] = 1
    np_tile = np.sqrt(np_tile)
    np_tile = scipy.ndimage.maximum_filter(np_tile, footprint=circle)
    np_tile = plt.cm.inferno(np_tile)
    return np_tile<jupyter_output><empty_output><jupyter_text>Wir sind fast fertig, wir müssen nur eine Karte erstellen, bevor wir sie an unser `DataArray` übergeben:<jupyter_code>m = Map(center=[-20, -60], zoom=3, basemap=basemaps.CartoDB.DarkMatter)
m<jupyter_output><empty_output><jupyter_text>Um unsere Daten auf der Karte anzuzeigen, rufen wir `.leaflet.plot()` in unserem `DataArray` auf und übergeben als Parameter die Karte, Längen- und Breitengrade, die Transformationsfunktionen und den dynamischen Wert. Wir erhalten eine Schicht zurück, die wir `z` – einen Schieberegler zum Einstellen der Deckkraft.<jupyter_code>l = da.leaflet.plot(m, lat_dim='y', lon_dim='x',
                    transform0=transform0,
                    transform1=transform1,
                    transform2=transform2,
                    dynamic=dynamic)
l.interact(opacity=(0.1,1.0,0.1))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08505298382598996, 'fraction_numerical': 0.011712214166201896, 'mean_word_length': 4.766077170418006, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 39, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '72614', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2514, 'n_tokens_neox': 2504, 'n_words': 754, 'path': 'docs/js/xarray-leaflet.ipynb', 'repo_name': 'veit/pyviz-tutorial', 'size': '7172'}