Python 更正 matplotlib 颜色条刻度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18704353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 11:31:33  来源:igfitidea点击:

Correcting matplotlib colorbar ticks

pythonmatplotlibcolor-mapping

提问by urschrei

I've placed a color bar alongside a choropleth map. Because the data being plotted are discrete rather than continuous values, I've used a LinearSegmentedColormap (using the recipe from the scipy cookbook), which I've initialised with my max counted value + 1, in order to show a colour for 0. However, I now have two problems:

我在等值分布图旁边放置了一个颜色条。因为绘制的数据是离散值而不是连续值,所以我使用了 LinearSegmentedColormap(使用scipy cookbook 中的配方),我已经用我的最大计数值 + 1 对其进行了初始化,以便显示 0 的颜色。但是,我现在有两个问题:

enter image description here

在此处输入图片说明

  1. The tick labels are incorrectly spaced (except for 5, more or less) – they should be located in the middle of the colour they identify; i.e. 0 - 4 should be moved up, and 6 - 10 should be moved down.

  2. If I initialise the colorbar with drawedges=True, so that I can style its dividersproperties, I get this:

  1. 刻度标签的间距不正确(除了 5 个,或多或少)——它们应该位于它们识别的颜色的中间;即 0 - 4 应该向上移动,6 - 10 应该向下移动。

  2. 如果我用 初始化颜色栏drawedges=True,以便我可以设置其dividers属性的样式,我会得到:

enter image description here

在此处输入图片说明

I'm creating my colormap and colorbar like so:

我正在像这样创建我的颜色图和颜色条:

cbmin, cbmax = min(counts), max(counts)
# this normalises the counts to a 0,1 interval
counts /= np.max(np.abs(counts), axis=0)
# density is a discrete number, so we have to use a discrete color ramp/bar
cm = cmap_discretize(plt.get_cmap('YlGnBu'), int(cbmax) + 1)
mappable = plt.cm.ScalarMappable(cmap=cm)
mappable.set_array(counts)
# set min and max values for the colour bar ticks
mappable.set_clim(cbmin, cbmax)
pc = PatchCollection(patches, match_original=True)
# impose our colour map onto the patch collection
pc.set_facecolor(cm(counts))
ax.add_collection(pc,)
cb = plt.colorbar(mappable, drawedges=True)

So I'm wondering whether my converting the counts to a 0,1 interval is one of the problems.

所以我想知道将计数转换为 0,1 间隔是否是问题之一。

Update :

更新 :

Having tried what Hooked suggested, the 0-value is correct, but subsequent values are set progressively higher, to the the point where 9 is where 10 should be:

尝试了 Hooked 的建议后,0 值是正确的,但随后的值逐渐设置得更高,直到 9 应该是 10:

enter image description here

在此处输入图片说明

Here's the code I used:

这是我使用的代码:

cb = plt.colorbar(mappable)
labels = np.arange(0, int(cbmax) + 1, 1)
loc = labels + .5
cb.set_ticks(loc)
cb.set_ticklabels(labels)

And just to confirm, labelsdefinitely has the correct values:

只是为了确认,labels肯定有正确的值:

In [3]: np.arange(0, int(cbmax) + 1, 1)
Out[3]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

采纳答案by unutbu

You are suffering from an off-by-one error. You have 10 ticklabels spread among 11 colors. You might be able to correct the error by using np.linspaceinstead of np.arange. Using np.linspacethe third argument is the number of values desired. This reduces the amount of mental gymnastics needed to avoid the off-by-one error:

您正遭受逐一错误的困扰。您有 10 个刻度标签,分布在 11 种颜色中。您也许可以通过使用np.linspace代替来更正错误np.arange。使用np.linspace第三个参数是所需值的数量。这减少了避免一对一错误所需的心理体操量:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.cm as cm
import matplotlib.colors as mcolors

def colorbar_index(ncolors, cmap):
    cmap = cmap_discretize(cmap, ncolors)
    mappable = cm.ScalarMappable(cmap=cmap)
    mappable.set_array([])
    mappable.set_clim(-0.5, ncolors+0.5)
    colorbar = plt.colorbar(mappable)
    colorbar.set_ticks(np.linspace(0, ncolors, ncolors))
    colorbar.set_ticklabels(range(ncolors))

def cmap_discretize(cmap, N):
    """Return a discrete colormap from the continuous colormap cmap.

        cmap: colormap instance, eg. cm.jet. 
        N: number of colors.

    Example
        x = resize(arange(100), (5,100))
        djet = cmap_discretize(cm.jet, 5)
        imshow(x, cmap=djet)
    """

    if type(cmap) == str:
        cmap = plt.get_cmap(cmap)
    colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
    colors_rgba = cmap(colors_i)
    indices = np.linspace(0, 1., N+1)
    cdict = {}
    for ki,key in enumerate(('red','green','blue')):
        cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki])
                       for i in xrange(N+1) ]
    # Return colormap object.
    return mcolors.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)

fig, ax = plt.subplots()
A = np.random.random((10,10))*10
cmap = plt.get_cmap('YlGnBu')
ax.imshow(A, interpolation='nearest', cmap=cmap)
colorbar_index(ncolors=11, cmap=cmap)    
plt.show()

enter image description here

在此处输入图片说明

回答by Hooked

You can control the placement and the labels by hand. I'll start with a linear cmap generated from cmap_discretizeon the page you linked:

您可以手动控制位置和标签。我将从您链接的页面cmap_discretize上生成的线性 cmap 开始:

import numpy as np
import pylab as plt

# The number of divisions of the cmap we have
k = 10

# Random test data
A = np.random.random((10,10))*k
c = cmap_discretize('jet', k)

# First show without
plt.subplot(121)
plt.imshow(A,interpolation='nearest',cmap=c)
plt.colorbar()

# Now label properly
plt.subplot(122)
plt.imshow(A,interpolation='nearest',cmap=c)

cb = plt.colorbar()
labels = np.arange(0,k,1)
loc    = labels + .5
cb.set_ticks(loc)
cb.set_ticklabels(labels)

plt.show()

enter image description here

在此处输入图片说明