使散点图颜色条仅显示vmin / vmax

时间:2016-01-25 19:01:07

标签: python matplotlib colorbar

我有一种情况,我想创建一个颜色条,其颜色(与散点图相关联)跨越特定范围,但只有显示颜色条本身上该范围的子集。我可以使用contourf执行此操作,因为我可以独立于轮廓级别设置vminvmax,但我无法弄清楚如何使用散点图来完成此操作。请参阅以下内容:

import numpy as np

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable

x = np.linspace(0, 2*np.pi, 101)
x_arr = np.sin(x)
y_arr = np.cos(x)
arr = y_arr[:,None] * x_arr[None,:]

arr = np.where(arr < 0, arr*4, arr)
ptslist = np.array([-4, -3, -2, -1, 0, 1], dtype=np.float32)

fig, axs = plt.subplots(figsize=(11,5), nrows=1, ncols=2)

# I can achieve my desired behavior with contourf
cont = axs[0].contourf(x, x, arr, levels=np.linspace(-4,1,11),
                       cmap='BrBG_r', vmin=-4, vmax=4)
div0 = make_axes_locatable(axs[0])
cax0 = div0.append_axes('right', '5%', '2%')
plt.colorbar(cont, cax=cax0)

# I can't make this colorbar do a similar thing
sc = axs[1].scatter(np.arange(-4, 2), np.arange(-4, 2), c=ptslist, cmap='BrBG_r',
                    marker='o', s=144, edgecolors='black', vmin=-4, vmax=4)
div1 = make_axes_locatable(axs[1])
cax1 = div1.append_axes('right', '5%', '2%')
cb = plt.colorbar(sc, cax=cax1)

这产生了这个数字: colorbar -4 to 4

我希望发散的色彩图以白色为中心为零,并且颜色值在零的两侧呈线性显示。两个情节都做得很好。但是,我不希望在右侧颜色条上显示1到4的额外值(请参阅左侧颜色条在1处停止的方式)。

我的第一个想法是ylim,但这一行:

cb.ax.set_ylim(-4, 1)

会导致这种奇怪的事情发生:

colorbar is squished

如果我使用set_ticks,它只会移除缺少的刻度,并且不会更改限制。有什么方法可以很好地实现这一目标吗?

我正在使用matplotlib 1.5.0。

P.S。我也尝试过在SO上找到的一个以中点为中心的Normalize子类,但是它独立地缩放了正值和负值,这是我不想要的(它使+1.0的值变成深褐色,我想要它仍然是浅棕色,除非我设置vmax=4,此时我有完全相同的问题。)

2 个答案:

答案 0 :(得分:3)

您可以通过几种不同的方式完成此操作,但听起来您真正想要的是从另一个色彩映射的一部分创建的自定义色彩映射:

例如:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap

# Let's create a new colormap from a region of another colormap.
cmap = plt.get_cmap('BrBG_r')
colors = cmap(np.linspace(0, 5 / 8.0, 20))
cmap = LinearSegmentedColormap.from_list('my cmap', colors)

# And now let's plot some data...
x, y, z = np.random.random((3, 10))
z = 5 * z - 4

fig, ax = plt.subplots()
scat = ax.scatter(x, y, c=z, s=200, cmap=cmap, vmin=-4, vmax=1)
cbar = fig.colorbar(scat)

plt.show()

enter image description here

或者,如果您更喜欢离散色图,则可以执行以下操作:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import from_levels_and_colors

# Let's create a new set of colors from a region of another colormap.
ncolors = 10
cmap = plt.get_cmap('BrBG_r')
colors = cmap(np.linspace(0, 5 / 8.0, ncolors - 1))

# We'll then create a new colormap from that set of colors and tie it
# to specific values
levels = np.linspace(-4, 1, ncolors)
cmap, norm = from_levels_and_colors(levels, colors)

x, y, z = np.random.random((3, 10))
z = 5 * z - 4

fig, ax = plt.subplots()
scat = ax.scatter(x, y, c=z, s=200, cmap=cmap, norm=norm)
cbar = fig.colorbar(scat)
cbar.set_ticks(range(-4, 2))

plt.show()

enter image description here

答案 1 :(得分:2)

您可以将boundaries参数传递给colorbar

plt.colorbar(sc, cax=cax1, boundaries=sc.get_array())

我不知道sc.get_array()在这里是否总是正确的选择,但是get_array是ScalarMappable方法,它应该将数据映射到颜色上,所以它看起来是合理的选择。 (对于轮廓集,colorbar会自动抓取轮廓级别并将其用作边界。)