如何在matplotlib图例中放置多个色图补丁?

Zau*_*aus 3 python matplotlib legend colormap

当前情况:

我有多组线,其中同一组中的线会根据某些特定于组的参数而变化。我根据此参数为同一组内的每行分配一种颜色表中的颜色,并对每个组使用不同的颜色表。

现在,我想在图上添加图例,每组线有一个条目。 stackoverflow问题:如何在matplotlib图例中放置多个颜色图补丁?

仅适用于组线的解决方案:

如果我只有一组线,则最好的标注方法是按照答案的建议添加色条Matplotlib:将色条添加到不可映射的对象

如何最好地对多组线执行此操作?

因为我有多组这样的线,所以我不想为每个新参数添加一个颜色条。相反,我宁愿在图例中放置填充有对应色图的色块(作为一种迷你色条)。

最小的工作示例:

在下面的内容中,您可以找到当前情况的最小工作示例。但是请注意,我在很大程度上简化了隐藏参数依赖性的行的计算。因此,我的“参数” param就是我要遍历的索引。我的实际代码根据具有更复杂功能的模型参数来计算x和y值。因此,param_max此处的最大值对于每组线都是相同的,尽管实际上并非如此。

import numpy as np
import matplotlib.pyplot as plt

x_array = np.linspace(1, 10, 10)
y_array = x_array
param_max = x_array.size
cmaps = [plt.cm.spring, plt.cm.winter]  # set of colormaps 
                                        # (as many as there are groups of lines)
plt.figure()
for param, (x, y) in enumerate(zip(x_array, y_array)):  
    x_line1 = np.linspace(x, 1.5 * x, 10)
    y_line1 = np.linspace(y**2, y**2 - x, 10)
    x_line2 = np.linspace(1.2 * x, 1.5 * x, 10)
    y_line2 = np.linspace(2 * y, 2 * y - x, 10)
    # plot lines with color depending on param using different colormaps:
    plt.plot(x_line1, y_line1, c=cmaps[0](param / param_max))
    plt.plot(x_line2, y_line2, c=cmaps[1](param / param_max))
plt.show()
Run Code Online (Sandbox Code Playgroud)

这将产生上面显示的图。


由于找不到任何直接在stackoverflow上回答此问题的方法,因此我尝试自己找到一种解决方案,您可以在答案部分中找到它。如果有更直接/合适的方法,我将很高兴知道。

Zau*_*aus 5

在这种情况下,我将ImportanceOfBeingErnest的答案的解决方案调整为“用双色矩形为图例创建matplotlib mpatches”。链接在那里,在matplotlib图例指南中有关实现自定义图例处理程序的部分中的说明特别有用。

结果:

stackoverflow答案:如何在matplotlib图例中放置多个颜色图补丁?

解:

我创建了HandlerColormap从matplotlib的图例处理程序基类派生的类HandlerBaseHandlerColormap以一个颜色图和一些条纹作为参数。

对于参数,应给出cmapmatplotlib 颜色图实例。

该参数num_stripes确定图例补丁中颜色渐变的(非)连续性。

按照HandlerBase我的指示,我create_artist使用给定的维度覆盖了它的方法,因此应该按字体大小自动缩放代码。在这种新create_artist方法中,我创建了Rectangles根据输入颜色图着色的多个条纹(苗条matplotlib )。

码:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.legend_handler import HandlerBase

class HandlerColormap(HandlerBase):
    def __init__(self, cmap, num_stripes=8, **kw):
        HandlerBase.__init__(self, **kw)
        self.cmap = cmap
        self.num_stripes = num_stripes
    def create_artists(self, legend, orig_handle, 
                       xdescent, ydescent, width, height, fontsize, trans):
        stripes = []
        for i in range(self.num_stripes):
            s = Rectangle([xdescent + i * width / self.num_stripes, ydescent], 
                          width / self.num_stripes, 
                          height, 
                          fc=self.cmap((2 * i + 1) / (2 * self.num_stripes)), 
                          transform=trans)
            stripes.append(s)
        return stripes

x_array = np.linspace(1, 10, 10)
y_array = x_array
param_max = x_array.size
cmaps = [plt.cm.spring, plt.cm.winter]  # set of colormaps 
                                        # (as many as there are groups of lines)
plt.figure()
for param, (x, y) in enumerate(zip(x_array, y_array)):  
    x_line1 = np.linspace(x, 1.5 * x, 10)
    y_line1 = np.linspace(y**2, y**2 - x, 10)
    x_line2 = np.linspace(1.2 * x, 1.5 * x, 10)
    y_line2 = np.linspace(2 * y, 2 * y - x, 10)
    # plot lines with color depending on param using different colormaps:
    plt.plot(x_line1, y_line1, c=cmaps[0](param / param_max))
    plt.plot(x_line2, y_line2, c=cmaps[1](param / param_max))

cmap_labels = ["parameter 1 $\in$ [0, 10]", "parameter 2 $\in$ [-1, 1]"]
# create proxy artists as handles:
cmap_handles = [Rectangle((0, 0), 1, 1) for _ in cmaps]
handler_map = dict(zip(cmap_handles, 
                       [HandlerColormap(cm, num_stripes=8) for cm in cmaps]))
plt.legend(handles=cmap_handles, 
           labels=cmap_labels, 
           handler_map=handler_map, 
           fontsize=12)
plt.show()
Run Code Online (Sandbox Code Playgroud)