pyplot TwoSlopeNorm LinearSegmentedColormap 中零值的唯一颜色
Unique color for zero values in pyplot TwoSlopeNorm LinearSegmentedColormap
我想在数据为零的绘图上使用自定义(蓝色)颜色。我试过 set_under 方法,但失败了。所需的输出将是图形底部的一条蓝线和图形上部的两个蓝色方块。感谢任何帮助。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap,TwoSlopeNorm
# TwoSlopeNorm see:
# https://matplotlib.org/devdocs/tutorials/colors/colormapnorms.html#sphx-glr-tutorials-colors-colormapnorms-py
red2orange = np.array([np.linspace(1, 1, 256),
np.linspace(0, 165/256, 256),
np.linspace(0, 0, 256),
np.ones(256)]).T
grey2black = np.array([np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.ones(256)]).T
all_colors = np.vstack((grey2black,red2orange))
cmap = LinearSegmentedColormap.from_list('two_slope_cmap', all_colors)
divnorm = TwoSlopeNorm(vmin=1, vcenter=400, vmax=1000)
# seting bad and under
cmap.set_bad('mediumspringgreen')
cmap.set_under('blue')
#fake data
data = np.arange(1400)[:,None]* np.ones(200)
data[ 1100:1150, 50:150] = np.nan # bad data
data[ 1200:1250, 50:150] = 0 # zero data
data[ 1300:1350, 50:150] = -1 # under data
# plot
f,a = plt.subplots()
raster = a.pcolormesh(data,cmap=cmap, norm=divnorm)
cbar = f.colorbar(raster,ax=a, extend='both')
由于某些未知原因,TwoSlopeNorm
似乎不支持 under
或 over
颜色。将代码更改为使用 plt.Normalize()
而不是 TwoSlopeNorm()
表示对于该规范,under
颜色按预期工作。
一种解决方法是再次绘制 pcolormesh
,仅绘制 under
颜色。一个缺点是底色没有显示在颜色条扩展中。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, ListedColormap, TwoSlopeNorm
red2orange = np.array([np.linspace(1, 1, 256),
np.linspace(0, 165 / 256, 256),
np.linspace(0, 0, 256),
np.ones(256)]).T
grey2black = np.array([np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.ones(256)]).T
all_colors = np.vstack((grey2black, red2orange))
cmap = LinearSegmentedColormap.from_list('two_slope_cmap', all_colors)
divnorm = TwoSlopeNorm(vmin=1, vcenter=400, vmax=1000)
# seting bad and under
cmap.set_bad('mediumspringgreen')
cmap.set_under('dodgerblue') # this doesn't seem to be used with a TwoSlopeNorm
# fake data
data = np.arange(1400)[:, None] * np.ones(200)
data[1100:1150, 50:150] = np.nan # bad data
data[1200:1250, 50:150] = 0 # zero data
data[1300:1350, 50:150] = -1 # under data
# plot
f, a = plt.subplots()
raster = a.pcolormesh(data, cmap=cmap, norm=divnorm)
cbar = f.colorbar(raster, ax=a, extend='both')
# draw the mesh a second time, only for the under color
a.pcolormesh(np.where(data < 1, 0, np.nan), cmap=ListedColormap([cmap.get_under()]))
plt.show()
另一种解决方法是更改颜色图本身,将最低颜色设置为所需的底色。缺点是 vmin
需要移动一点。 (距离似乎是 vmin 和 vcenter 之间距离的 1/127。在内部,颜色图保持 256 种颜色,vcenter 的颜色在位置 128。)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, TwoSlopeNorm, to_rgba
red2orange = np.array([np.linspace(1, 1, 256),
np.linspace(0, 165 / 256, 256),
np.linspace(0, 0, 256),
np.ones(256)]).T
grey2black = np.array([np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.ones(256)]).T
all_colors = np.vstack((grey2black, red2orange))
all_colors[0, :] = to_rgba('dodgerblue')
cmap = LinearSegmentedColormap.from_list('two_slope_cmap', all_colors)
vmin = 1
vcenter = 400
vmax = 1000
divnorm = TwoSlopeNorm(vmin=vmin-(vcenter-vmin)/127, vcenter=vcenter, vmax=vmax)
# seting bad and under
cmap.set_bad('mediumspringgreen')
cmap.set_under('red') # this doesn't seem to be used with a TwoSlopeNorm
# fake data
data = np.arange(1400)[:, None] * np.ones(200)
data[1100:1150, 50:150] = np.nan # bad data
data[1200:1250, 50:150] = 0 # zero data
data[1300:1350, 50:150] = -1 # under data
# plot
f, a = plt.subplots()
raster = a.pcolormesh(data, cmap=cmap, norm=divnorm)
cbar = f.colorbar(raster, ax=a, extend='both')
plt.show()
PS:下面的代码试图可视化两个规范如何以不同方式处理 under
颜色:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import TwoSlopeNorm
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10, 3))
data = np.arange(0, 100)[:, None]
cmap = plt.get_cmap('viridis').copy()
cmap.set_under('crimson')
cmap.set_over('skyblue')
norm1 = plt.Normalize(20, 80)
im1 = ax1.imshow(data, cmap=cmap, norm=norm1, aspect='auto', origin='lower', interpolation='nearest')
plt.colorbar(im1, ax=ax1, extend='both')
ax1.set_title('using plt.Normalize()')
norm2 = TwoSlopeNorm(vmin=20, vcenter=30, vmax=80)
im2 = ax2.imshow(data, cmap=cmap, norm=norm2, aspect='auto', origin='lower', interpolation='nearest')
plt.colorbar(im2, ax=ax2, extend='both')
ax2.set_title('using TwoSlopeNorm')
plt.show()
PPS: 在github查看TwoSlopeNorm的源码,下个版本的matplotlib(当前版本是3.4.3)似乎解决了这个问题。所以,你可以尝试安装开发版。 (更改涉及将 left=-np.inf, right=np.inf
作为参数添加到 colors.py
中 TwoSlopeNorm
class 的 __call__
方法中的 np.interp
。
我想在数据为零的绘图上使用自定义(蓝色)颜色。我试过 set_under 方法,但失败了。所需的输出将是图形底部的一条蓝线和图形上部的两个蓝色方块。感谢任何帮助。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap,TwoSlopeNorm
# TwoSlopeNorm see:
# https://matplotlib.org/devdocs/tutorials/colors/colormapnorms.html#sphx-glr-tutorials-colors-colormapnorms-py
red2orange = np.array([np.linspace(1, 1, 256),
np.linspace(0, 165/256, 256),
np.linspace(0, 0, 256),
np.ones(256)]).T
grey2black = np.array([np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.ones(256)]).T
all_colors = np.vstack((grey2black,red2orange))
cmap = LinearSegmentedColormap.from_list('two_slope_cmap', all_colors)
divnorm = TwoSlopeNorm(vmin=1, vcenter=400, vmax=1000)
# seting bad and under
cmap.set_bad('mediumspringgreen')
cmap.set_under('blue')
#fake data
data = np.arange(1400)[:,None]* np.ones(200)
data[ 1100:1150, 50:150] = np.nan # bad data
data[ 1200:1250, 50:150] = 0 # zero data
data[ 1300:1350, 50:150] = -1 # under data
# plot
f,a = plt.subplots()
raster = a.pcolormesh(data,cmap=cmap, norm=divnorm)
cbar = f.colorbar(raster,ax=a, extend='both')
由于某些未知原因,TwoSlopeNorm
似乎不支持 under
或 over
颜色。将代码更改为使用 plt.Normalize()
而不是 TwoSlopeNorm()
表示对于该规范,under
颜色按预期工作。
一种解决方法是再次绘制 pcolormesh
,仅绘制 under
颜色。一个缺点是底色没有显示在颜色条扩展中。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, ListedColormap, TwoSlopeNorm
red2orange = np.array([np.linspace(1, 1, 256),
np.linspace(0, 165 / 256, 256),
np.linspace(0, 0, 256),
np.ones(256)]).T
grey2black = np.array([np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.ones(256)]).T
all_colors = np.vstack((grey2black, red2orange))
cmap = LinearSegmentedColormap.from_list('two_slope_cmap', all_colors)
divnorm = TwoSlopeNorm(vmin=1, vcenter=400, vmax=1000)
# seting bad and under
cmap.set_bad('mediumspringgreen')
cmap.set_under('dodgerblue') # this doesn't seem to be used with a TwoSlopeNorm
# fake data
data = np.arange(1400)[:, None] * np.ones(200)
data[1100:1150, 50:150] = np.nan # bad data
data[1200:1250, 50:150] = 0 # zero data
data[1300:1350, 50:150] = -1 # under data
# plot
f, a = plt.subplots()
raster = a.pcolormesh(data, cmap=cmap, norm=divnorm)
cbar = f.colorbar(raster, ax=a, extend='both')
# draw the mesh a second time, only for the under color
a.pcolormesh(np.where(data < 1, 0, np.nan), cmap=ListedColormap([cmap.get_under()]))
plt.show()
另一种解决方法是更改颜色图本身,将最低颜色设置为所需的底色。缺点是 vmin
需要移动一点。 (距离似乎是 vmin 和 vcenter 之间距离的 1/127。在内部,颜色图保持 256 种颜色,vcenter 的颜色在位置 128。)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, TwoSlopeNorm, to_rgba
red2orange = np.array([np.linspace(1, 1, 256),
np.linspace(0, 165 / 256, 256),
np.linspace(0, 0, 256),
np.ones(256)]).T
grey2black = np.array([np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.linspace(0.75, 0.25, 256),
np.ones(256)]).T
all_colors = np.vstack((grey2black, red2orange))
all_colors[0, :] = to_rgba('dodgerblue')
cmap = LinearSegmentedColormap.from_list('two_slope_cmap', all_colors)
vmin = 1
vcenter = 400
vmax = 1000
divnorm = TwoSlopeNorm(vmin=vmin-(vcenter-vmin)/127, vcenter=vcenter, vmax=vmax)
# seting bad and under
cmap.set_bad('mediumspringgreen')
cmap.set_under('red') # this doesn't seem to be used with a TwoSlopeNorm
# fake data
data = np.arange(1400)[:, None] * np.ones(200)
data[1100:1150, 50:150] = np.nan # bad data
data[1200:1250, 50:150] = 0 # zero data
data[1300:1350, 50:150] = -1 # under data
# plot
f, a = plt.subplots()
raster = a.pcolormesh(data, cmap=cmap, norm=divnorm)
cbar = f.colorbar(raster, ax=a, extend='both')
plt.show()
PS:下面的代码试图可视化两个规范如何以不同方式处理 under
颜色:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import TwoSlopeNorm
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10, 3))
data = np.arange(0, 100)[:, None]
cmap = plt.get_cmap('viridis').copy()
cmap.set_under('crimson')
cmap.set_over('skyblue')
norm1 = plt.Normalize(20, 80)
im1 = ax1.imshow(data, cmap=cmap, norm=norm1, aspect='auto', origin='lower', interpolation='nearest')
plt.colorbar(im1, ax=ax1, extend='both')
ax1.set_title('using plt.Normalize()')
norm2 = TwoSlopeNorm(vmin=20, vcenter=30, vmax=80)
im2 = ax2.imshow(data, cmap=cmap, norm=norm2, aspect='auto', origin='lower', interpolation='nearest')
plt.colorbar(im2, ax=ax2, extend='both')
ax2.set_title('using TwoSlopeNorm')
plt.show()
PPS: 在github查看TwoSlopeNorm的源码,下个版本的matplotlib(当前版本是3.4.3)似乎解决了这个问题。所以,你可以尝试安装开发版。 (更改涉及将 left=-np.inf, right=np.inf
作为参数添加到 colors.py
中 TwoSlopeNorm
class 的 __call__
方法中的 np.interp
。