Ich habe mich jetzt den ganzen Tag mit ChatGPT „herumgeschlagen“. Immerhin, mit tatkräftiger Unterstützung funktioniert das Script, obwohl ich keine Ahnung habe, was ich da genau mache. Es ist nicht genau das, was ich als Kartenbild wollte, aber zu 90% nahe dran. Ich vermute, dass die Karte tatsächlich neu erstellt wird, so wie ich den Code verstehe, aber wie und womit, kann ich nicht sagen.
Ich hatte eigentlich eine fertige physikalische Rasterkarte als Vorlage (400 MB…), mit Wüsten und Vegetationszonen - aber eigentlich ist es gut so, weil diese Landschaften dann ja auch an die neuen Küsten angepasst werden müssten. Und einfach überfluten sieht auch doof aus. So ist es mehr generalisiert.
Das vorherige Kleinskalieren klappte nicht, so dass ich 70 MB-große Tiffs erhalte (beim Skalieren gingen offenbar die Geo-Daten verloren…) - aber die PNG lassen sich dann eben in PS runterskalieren.
Die Flachwasserzonen wollte ich nicht in Hellblau, aber ich weiß nicht, wie ich die Schattierung wegbekomme. Im Script kann man dort Zahlenwerte eingeben. Aber ich habe null Ahnung von Python und den beteiligten Bibliotheken, - das ist alles Blindflug. Naja, immerhin könnte ich jetzt theoretisch für jeden Meter eine Datei rendern lassen, und eigentlich wollte ich gar nicht mehr. 
Das Programm OSGeo4w habe ich jetzt nicht gebraucht, aber ich schaue trotzdem rein. Karten selbermachen mag ich!
#!/usr/bin/env python3"""
Erzeugt Weltkarten mit verändertem Meeresspiegel aus ETOPO 2022.
Benötigt:
pip install rasterio numpy pillow
Datei:
etopo.tif
Ausgabe:
flood_10m.png
flood_20m.png
flood_50m.png
"""
import numpy as np
import rasterio
from rasterio.enums import Resampling
from PIL import Image
# ---------------------------------------------------
# Einstellungen
# ---------------------------------------------------
ETOPO = "etopo.tif"
OUTPUT_WIDTH = 16384
OUTPUT_HEIGHT = 8192
SEA_LEVELS = [2, 5, 10, 20, 50, 100, 150, 200, 300, 500, 1000]
# Farben
DEEP_WATER = np.array([25, 70, 170], dtype=np.uint8)
SHALLOW_WATER = np.array([90, 160, 255], dtype=np.uint8)
LOWLAND = np.array([170, 185, 120], dtype=np.uint8)
HIGHLAND = np.array([120, 105, 85], dtype=np.uint8)
MOUNTAIN = np.array([245, 245, 245], dtype=np.uint8)
# ---------------------------------------------------
# Hilfsfunktion
# ---------------------------------------------------
def blend(c1, c2, t):
return (c1 * (1 - t) + c2 * t).astype(np.uint8)
# ---------------------------------------------------
# ETOPO laden
# ---------------------------------------------------
print("Lade ETOPO...")
with rasterio.open(ETOPO) as src:
elev = src.read(
1,
out_shape=(OUTPUT_HEIGHT, OUTPUT_WIDTH),
resampling=Resampling.bilinear,
)
print("Größe:", elev.shape)
# ---------------------------------------------------
# Karten erzeugen
# ---------------------------------------------------
for sea in SEA_LEVELS:
print(f"Erzeuge +{sea} m")
rgb = np.zeros((OUTPUT_HEIGHT, OUTPUT_WIDTH, 3), dtype=np.uint8)
water = elev <= sea
land = ~water
# ---------------------------
# Wasser
# ---------------------------
depth = np.clip((sea - elev) / 6000.0, 0, 1)
rgb[water] = blend(
SHALLOW_WATER,
DEEP_WATER,
depth[water][:, None]
)
# ---------------------------
# Land
# ---------------------------
h = np.clip((elev - sea) / 4000.0, 0, 1)
low = h < 0.5
high = ~low
land_index = np.where(land)
hh = h[land]
colours = np.empty((hh.size, 3), dtype=np.uint8)
a = hh < 0.5
colours[a] = blend(
LOWLAND,
HIGHLAND,
(hh[a] * 2)[:, None]
)
colours[~a] = blend(
HIGHLAND,
MOUNTAIN,
((hh[~a] - 0.5) * 2)[:, None]
)
rgb[land_index] = colours
outfile = f"flood_{sea}m.png"
Image.fromarray(rgb).save(outfile)
print("Gespeichert:", outfile)
print("Fertig.")