Matplotlib ScalarMappable: 如果使用了norm,为什么还需要设置set_array()?

3

我正在尝试用一张颜色地图绘制一组多边形。我设置了一个ScalarMappable对象,并从该ScalarMappable生成多边形的颜色,但当我尝试添加一个颜色条时,出现了错误:

TypeError: You must first set_array for mappable

“set_array” 的文档并没有详细说明其作用,因此我不清楚它在做什么,是否需要给它赋值,如果需要,应该赋什么值。

请问有人能解释一下 set_array 的作用,并告诉我如何处理吗?

    plt.clf()
    fig, ax  = plt.subplots(1,1)

    # Set color mappable
    range_min = df.col1.min()
    range_max = df.col1.max()
    cmap = matplotlib.cm.ScalarMappable(
          norm = mcolors.Normalize(range_min, range_max), 
          cmap = plt.get_cmap('binary'))

    for i in polygonDict.keys():
        ax.add_patch(ds.PolygonPatch(polygonDict[i], fc = cmap.to_rgba(df.col1.loc[i])))

    fig.colorbar(cmap, ax = ax)

1
这些是用于生成颜色的值。 ScalarMappable 通常不会直接像这样使用,而是作为其他类(如PolygonCollection)的混入使用,以允许您在 R^1 -> RGBA 之间进行映射。 - tacaswell
@tcaswell -- 谢谢。那么我是否可以毫不担心地将一些任意值提供给cmap.set_array(),因为我已经在mcolors.Normalize()中设置了vmax和vmin值? - nick_eu
1
不确定你现在这样使用是否正确。我认为你应该在这里使用PolygonCollection,因为mpl会为你处理所有的颜色映射,我猜它在绘制时会更高效,并且代码更易读。 - tacaswell
好的,谢谢@tcaswell。这是一个修复超出此片段范围的问题的方法 - 我正在尝试将数据框中的值与形状文件中的多边形合并,以便可以使用在pandas中计算的变量值对每个多边形(区域)进行着色。按顺序执行可能有些具有挑战性,但我会仔细考虑! - nick_eu
1
我建议只需制作列表(而不是添加补丁),然后在最后进行一次对PolygonCollection的调用,这样就可以解决排序问题。 - tacaswell
啊,那么建立一个标量值列表(变成颜色),和一个多边形列表,然后将多边形列表放入PolygonCollection中,并将标量值列表分配为PolygonCollection的颜色值?这很聪明,谢谢! - nick_eu
3个回答

4
一个更简单的方法是发送一个空数组 []set_array()。 我不知道为什么,但我在这个答案中看到过,并且它有效。
我唯一知道的是,在设置数组之前,您从get_array()得到None,这可能是您出现此错误的原因。
你可以这样做:
plt.clf()
fig, ax  = plt.subplots(1,1)

# Set color mappable
range_min = df.col1.min()
range_max = df.col1.max()
cmap = matplotlib.cm.ScalarMappable(
      norm = mcolors.Normalize(range_min, range_max), 
      cmap = plt.get_cmap('binary'))

for i in polygonDict.keys():
    ax.add_patch(ds.PolygonPatch(polygonDict[i], fc = cmap.to_rgba(df.col1.loc[i])))

cmap.set_array([]) # or alternatively cmap._A = []

fig.colorbar(cmap, ax = ax)

经过一些测试,似乎你可以将世界上任何数组([df.col1]、[0,1]、['hello'])发送到set_array()中,你想要的颜色条就会出现。只是不能是None
我注意到,如果将数组设置为数字数组,然后调用autoscale(),颜色条的最小值和最大值将是该数组的最小值和最大值。
希望这能帮到你。

3
这可能有点晚了,但我今天遇到了同样的问题。
就我所理解的,imshow()和scatter()创建一个可映射对象,通过两个步骤将浮点值转换为颜色。 首先,将浮点数映射到0..1范围内,然后在颜色地图中查找该归一化数字对应的RGB。
像PolygonPatch这样的艺术家不会创建这个可映射对象,因此您需要使用ColorbarBase()进行操作。
以下是我的做法。
def createColourbar(lwr, upr):
    """Create a colourbar with limits of lwr and upr"""
    cax, kw = matplotlib.colorbar.make_axes(mp.gca())
    norm = matplotlib.colors.Normalize(vmin = lwr, vmax = upr, clip = False)

    c = matplotlib.colorbar.ColorbarBase(cax, cmap=mp.spectral(), norm=norm)
    return c

2

这个问题在 matplotlib v3.1.0 中已经得到了解决(在v3.0.2中无法工作)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接