图例中的两种线条样式

Bli*_*ink 4 python plot matplotlib legend

我有一个有两种线条样式的图(实线和虚线).我希望它们可用于相同的图例条目.下面的代码生成典型的图例,有两个条目.

import matplotlib.pyplot as plt
import numpy as np

xy = np.linspace(0,10,10)

plt.figure()
plt.plot(xy,xy, c='k', label='solid')
plt.plot(xy,xy+1, c='k', ls='dashed', label='dashed')
plt.plot(xy,xy-1, c='k', ls='dashed')
plt.legend()

plt.show()
Run Code Online (Sandbox Code Playgroud)

我想要的是类似的东西:

我曾尝试过与代理艺术家一起玩,但似乎无法获得两条线,彼此相互偏移以显示一个条目.

Amy*_*den 11

我根据HandlerLineCollection类创建了一个自定义图例处理程序.它计算出集合中有多少行并将它们垂直展开.

示例图片:具有多行图例的图像

这是处理程序:

from matplotlib.legend_handler import HandlerLineCollection
from matplotlib.collections import LineCollection
from matplotlib.lines import Line2D


class HandlerDashedLines(HandlerLineCollection):
"""
Custom Handler for LineCollection instances.
"""
def create_artists(self, legend, orig_handle,
                   xdescent, ydescent, width, height, fontsize, trans):
    # figure out how many lines there are
    numlines = len(orig_handle.get_segments())
    xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent,
                                         width, height, fontsize)
    leglines = []
    # divide the vertical space where the lines will go
    # into equal parts based on the number of lines
    ydata = ((height) / (numlines + 1)) * np.ones(xdata.shape, float)
    # for each line, create the line at the proper location
    # and set the dash pattern
    for i in range(numlines):
        legline = Line2D(xdata, ydata * (numlines - i) - ydescent)
        self.update_prop(legline, orig_handle, legend)
        # set color, dash pattern, and linewidth to that
        # of the lines in linecollection
        try:
            color = orig_handle.get_colors()[i]
        except IndexError:
            color = orig_handle.get_colors()[0]
        try:
            dashes = orig_handle.get_dashes()[i]
        except IndexError:
            dashes = orig_handle.get_dashes()[0]
        try:
            lw = orig_handle.get_linewidths()[i]
        except IndexError:
            lw = orig_handle.get_linewidths()[0]
        if dashes[0] != None:
            legline.set_dashes(dashes[1])
        legline.set_color(color)
        legline.set_transform(trans)
        legline.set_linewidth(lw)
        leglines.append(legline)
    return leglines
Run Code Online (Sandbox Code Playgroud)

以下是如何使用它的示例:

#make proxy artists
#make list of one line -- doesn't matter what the coordinates are
line = [[(0, 0)]]
#set up the line collections
lc = LineCollection(2 * line, linestyles = ['solid', 'dashed'], colors = ['black', 'black'])
lc2 = LineCollection(2 * line, linestyles = ['solid', 'dashed'], colors = ['blue', 'blue'])
lc3 = LineCollection(3 * line, linestyles = ['solid', 'dashed', 'solid'], colors = ['blue', 'red', 'green'])
#create the legend
plt.legend([lc, lc2, lc3], ['text', 'more text', 'extra line'], handler_map = {type(lc) : HandlerDashedLines()}, handlelength = 2.5)
Run Code Online (Sandbox Code Playgroud)


gyg*_*ger 7

基于@Amys 的回答,我构建了另一个实现,将HandlerTuple扩展为垂直堆叠,因此您无需添加代理艺术家。

import matplotlib.pyplot as plt
from matplotlib.legend_handler import HandlerTuple

class HandlerTupleVertical(HandlerTuple):
    def __init__(self, **kwargs):
        HandlerTuple.__init__(self, **kwargs)

    def create_artists(self, legend, orig_handle,
                       xdescent, ydescent, width, height, fontsize, trans):
        # How many lines are there.
        numlines = len(orig_handle)
        handler_map = legend.get_legend_handler_map()

        # divide the vertical space where the lines will go
        # into equal parts based on the number of lines
        height_y = (height / numlines)

        leglines = []
        for i, handle in enumerate(orig_handle):
            handler = legend.get_legend_handler(handler_map, handle)

            legline = handler.create_artists(legend, handle,
                                             xdescent,
                                             (2*i + 1)*height_y,
                                             width,
                                             2*height,
                                             fontsize, trans)
            leglines.extend(legline)

        return leglines
Run Code Online (Sandbox Code Playgroud)

然后就可以使用了,使用

line1 = plt.plot(xy,xy, c='k', label='solid')
line2 = plt.plot(xy,xy+1, c='k', ls='dashed', label='dashed')
line3 = plt.plot(xy,xy-1, c='k', ls='dashed', label='dashed')

plt.legend([(line1, line2), line3], ['text', 'more text', 'even more'],
           handler_map = {tuple : HandlerTupleVertical()})
Run Code Online (Sandbox Code Playgroud)