Leider bietet Matplotlib nicht die Funktionalität von Matlab demcmap
. Es könnte tatsächlich einige eingebaute Funktionen im Python basemap
Paket, von denen ich nicht bewusst bin.
Wenn Sie also an den Optionen von matplotlib on-board festhalten, können wir Normalize
ableiten, um eine Farbnormalisierung zu erstellen, die um einen Punkt in der Mitte der Farbpalette zentriert ist. Diese Technik kann in another question auf StackOverflow gefunden und an die spezifischen Bedürfnisse angepasst werden, nämlich eine sealevel
(die wahrscheinlich am besten als 0
gewählt wird) und den Wert in der Colormap col_val
(zwischen 0 und 1), denen diese Meereshöhe entsprechen sollte . Im Fall der Geländekarte scheint es, dass 0.22
, was einer türkisfarbenen Farbe entspricht, eine gute Wahl sein könnte.
Die Normalize-Instanz kann dann als Argument an imshow
gegeben werden. Die resultierenden Zahlen sind unten in der ersten Reihe des Bildes zu sehen.
Durch den sanften Übergang um den Meeresspiegel erscheinen die Werte um 0
türkis, so dass es schwierig ist, zwischen Land und Meer zu unterscheiden.
Wir können daher die Geländekarte ein wenig ändern und diese Farben ausschneiden, so dass die Küste besser sichtbar ist. Dies geschieht durch combining two parts der Karte, von 0 bis 0,17 und von 0,25 bis 1, und damit einen Teil davon ausschneiden.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
class FixPointNormalize(matplotlib.colors.Normalize):
"""
Inspired by https://stackoverflow.com/questions/20144529/shifted-colorbar-matplotlib
Subclassing Normalize to obtain a colormap with a fixpoint
somewhere in the middle of the colormap.
This may be useful for a `terrain` map, to set the "sea level"
to a color in the blue/turquise range.
"""
def __init__(self, vmin=None, vmax=None, sealevel=0, col_val = 0.21875, clip=False):
# sealevel is the fix point of the colormap (in data units)
self.sealevel = sealevel
# col_val is the color value in the range [0,1] that should represent the sealevel.
self.col_val = col_val
matplotlib.colors.Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None):
x, y = [self.vmin, self.sealevel, self.vmax], [0, self.col_val, 1]
return np.ma.masked_array(np.interp(value, x, y))
# Combine the lower and upper range of the terrain colormap with a gap in the middle
# to let the coastline appear more prominently.
# inspired by https://stackoverflow.com/questions/31051488/combining-two-matplotlib-colormaps
colors_undersea = plt.cm.terrain(np.linspace(0, 0.17, 56))
colors_land = plt.cm.terrain(np.linspace(0.25, 1, 200))
# combine them and build a new colormap
colors = np.vstack((colors_undersea, colors_land))
cut_terrain_map = matplotlib.colors.LinearSegmentedColormap.from_list('cut_terrain', colors)
# invent some data (height in meters relative to sea level)
data = np.linspace(-1000,2400,15**2).reshape((15,15))
# plot example data
fig, ax = plt.subplots(nrows = 2, ncols=3, figsize=(11,6))
plt.subplots_adjust(left=0.08, right=0.95, bottom=0.05, top=0.92, hspace = 0.28, wspace = 0.15)
plt.figtext(.5, 0.95, "Using 'terrain' and FixedPointNormalize", ha="center", size=14)
norm = FixPointNormalize(sealevel=0, vmax=3400)
im = ax[0,0].imshow(data+1000, norm=norm, cmap=plt.cm.terrain)
fig.colorbar(im, ax=ax[0,0])
norm2 = FixPointNormalize(sealevel=0, vmax=3400)
im2 = ax[0,1].imshow(data, norm=norm2, cmap=plt.cm.terrain)
fig.colorbar(im2, ax=ax[0,1])
norm3 = FixPointNormalize(sealevel=0, vmax=0)
im3 = ax[0,2].imshow(data-2400.1, norm=norm3, cmap=plt.cm.terrain)
fig.colorbar(im3, ax=ax[0,2])
plt.figtext(.5, 0.46, "Using custom cut map and FixedPointNormalize (adding hard edge between land and sea)", ha="center", size=14)
norm4 = FixPointNormalize(sealevel=0, vmax=3400)
im4 = ax[1,0].imshow(data+1000, norm=norm4, cmap=cut_terrain_map)
fig.colorbar(im4, ax=ax[1,0])
norm5 = FixPointNormalize(sealevel=0, vmax=3400)
im5 = ax[1,1].imshow(data, norm=norm5, cmap=cut_terrain_map)
cbar = fig.colorbar(im5, ax=ax[1,1])
norm6 = FixPointNormalize(sealevel=0, vmax=0)
im6 = ax[1,2].imshow(data-2400.1, norm=norm6, cmap=cut_terrain_map)
fig.colorbar(im6, ax=ax[1,2])
for i, name in enumerate(["land only", "coast line", "sea only"]):
for j in range(2):
ax[j,i].text(0.96,0.96,name, ha="right", va="top", transform=ax[j,i].transAxes, color="w")
plt.show()
Wie sollte die matplotlib colormap wissen, welcher Datenwert in Ihrem Grundstück auf den Meeresspiegel gehört? – ImportanceOfBeingErnest
@ImportanceOfBeingErnest Der Meeresspiegel ist 0m, deshalb habe ich gesagt, dass ich die Colormap um die Null-Höhenkarte verschieben soll – mjp