【问题标题】:How to put multiple colormap patches in a matplotlib legend?如何在 matplotlib 图例中放置多个颜色图补丁?
【发布时间】:2019-04-04 02:34:22
【问题描述】:

当前情况:

我有多组线路,同一组内的线路根据某些组特定参数而有所不同。我根据此参数为同一组中的每条线分配颜色图中的颜色,并为每个组使用不同的颜色图。

现在,我想在绘图中添加一个图例,每组线一个条目。

仅适用于 一个 组行的解决方案:

如果我只有一组线条,最好的标记方法是添加一个颜色条,如Matplotlib: Add colorbar to non-mappable object 的答案中所建议的那样。

如何最好地为多组线做到这一点?

由于我有多个这样的行组,我不想为每个新参数添加一个颜色条。相反,我宁愿在图例中放置填充了相应颜色图的补丁(作为一种迷你颜色条)。

最小的工作示例:

在下面,您可以找到当前情况的最小工作示例。但是请注意,我大大简化了隐藏参数依赖性的线条的计算。因此,我的“参数”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()

这会产生如上所示的图。


由于我在 stackoverflow 上找不到任何直接回答此问题的内容,因此我尝试自己找到一个解决方案,您可以在答案部分找到该解决方案。如果有更直接/更合适的方法,我很乐意知道。

【问题讨论】:

  • 你说,你没有找到任何答案。虽然我觉得this Q&A 几乎是一样的;也许有一个优势:如果你有很多行,无论如何你都不会在循环中使用plot,而是使用LineCollection

标签: python matplotlib legend colormap


【解决方案1】:

我将 ImportanceOfBeingErnest 的答案解决方案调整为 "Create a matplotlib mpatches with a rectangle bi-colored for figure legend" 以适应这种情况。正如那里的链接,matplotlib legend guide 中关于Implementing a custom legend handler 部分中的说明特别有用。

结果:

解决方案:

我为图例处理程序 HandlerBase 创建了派生自 matplotlib 基类的类 HandlerColormapHandlerColormap 将颜色图和许多条纹作为参数。

对于 cmap 参数,应该给出一个 matplotlib colormap 实例。

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

按照HandlerBase 中的说明,我使用给定尺寸覆盖其create_artist 方法,以便代码应该(自动)按字体大小缩放。在这个新的create_artist 方法中,我创建了多个根据输入颜色图着色的条纹(slim matplotlib Rectangles)。

代码:

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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 2020-10-12
    • 2013-11-15
    • 1970-01-01
    • 2020-12-11
    • 2015-10-03
    • 2011-12-28
    相关资源
    最近更新 更多