将颜色条作为图例添加到matplotlib散点图(多个子图,多个散点)

时间:2018-10-18 07:17:30

标签: python matplotlib legend colorbar scatter

我有几个要添加单个颜色条的子图。每个子图由7个散点组成。我发现了有关如何添加颜色条的建议,但它们主要与每个散点的值有关,而与行本身无关。

代表性示例代码:

import numpy as np
from matplotlib import pyplot as plt

x = range(50)
scales = np.linspace(0, 2, 7)
locs = range(4)
cmap = plt.get_cmap("Spectral")
for s_plot in range(4):
    plt.subplot(2, 2, s_plot+1)
    color = iter(cmap(np.linspace(0, 1, len(scales))))
    for scale in scales:
        c = next(color)
        y = np.random.normal(loc=locs[s_plot], scale=scale, size=50)
        plt.scatter(x, y, c=c, s=5)
        plt.title("Mean = {:d}".format(locs[s_plot]))
plt.subplots_adjust(hspace=0.4)
plt.show()

以上示例给出: enter image description here

我想要的颜色条看起来像这样(假的,要放在图的旁边):

enter image description here

因此,颜色栏并没有描述我的分散点的值,而是描述了经过迭代的不同“行”(在本例中为不同的比例)。在该示例中,这将有助于将点与比例尺匹配。

我尝试过的很简单

plt.colorbar()

,在完成每个子图后将调用一次。但是我明白了 TypeError: You must first set_array for mappable 另外,由于是我要为其创建颜色图的不同比例,因此我也尝试了

plt.colorbar(scales) 

返回:AttributeError: 'numpy.ndarray' object has no attribute 'autoscale_None'

我目前对如何进行此操作缺乏方向。 编辑:我被标记为matplotlib colorbar for scatter的可能重复项。我已经找到了这个问题,但是对我的问题没有帮助。在我的情况下,我需要一个独立于z值的色图,但只表示“行号”或“散点行”,或者您要调用它(等效于{{1 }}。

2 个答案:

答案 0 :(得分:2)

颜色条需要输入ScalarMappable作为输入。因此,如果您在绘图中创建的所有内容均不适合此操作,则可以自己创建。

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.cm import ScalarMappable

x = range(50)
scales = np.linspace(0, 2, 7)
locs = range(4)
cmap = plt.get_cmap("Spectral")
norm = plt.Normalize(scales.min(), scales.max())

fig, axes = plt.subplots(2,2, constrained_layout=True, sharey=True)

for s_plot, ax in enumerate(axes.flat):
    for scale in scales:
        y = np.random.normal(loc=locs[s_plot], scale=scale, size=50)
        sc = ax.scatter(x, y, c=[cmap(norm(scale))], s=5)
        ax.set_title("Mean = {:d}".format(locs[s_plot]))

sm =  ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])
cbar = fig.colorbar(sm, ax=axes[:,1])
cbar.ax.set_title("scale")

plt.show()

enter image description here

答案 1 :(得分:1)

如果我理解正确,那么您有一定范围,并希望为此绘制一个颜色图(实际上没有使用该颜色图的任何图)。基本上,您可以使用

在任何轴上绘制颜色图
import matplotlib
norm = matplotlib.colors.Normalize(vmin=0, vmax=50)

ax = plt.gca()
matplotlib.colorbar.ColorbarBase(ax, cmap='viridis', norm=norm)

当然,您可以在任何地方使用任何轴(或使用inset_axes在特定位置放置轴)。

更棘手的是为散点图获取颜色,该颜色首先与色图匹配。我不确定是否有更简单的方法,但是我将颜色转换为RGB以进行绘制。这是一个完整的示例:

import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import numpy as np

N = 10

# dummy data
x_ = [k/10*np.arange(10) for k in range(N)]

cmap = matplotlib.cm.get_cmap('viridis')
cmap_values = np.linspace(0., 1., N)
colors = cmap(cmap_values)

colors_rgb = ['#{0:02x}{1:02x}{2:02x}'.format(int(255*a), int(255*b), int(255*c)) for a, b, c, _ in colors]

plt.figure()

for x, c in zip(x_, colors_rgb):
    plt.plot(x, c=c)

norm = matplotlib.colors.Normalize(vmin=0, vmax=50)
ticks = np.arange(0, 60, 10)

# vertical colorbar
cbaxes = inset_axes(plt.gca(), width="3%", height="80%", loc=2)
cbar = matplotlib.colorbar.ColorbarBase(cbaxes, cmap=cmap, norm=norm, ticks=ticks)
cbar.set_label('scale')
cbar.ax.set_yticklabels(ticks, fontsize=12)

enter image description here