Вертикально складывать линии в легенде - PullRequest
0 голосов
/ 06 августа 2020

enter image description here

In search for a solution to vertically stack lines in a matplotlib legend, I came across this stack post Два стиля линий в легенде , но я не могу заставить код работать, я всегда получаю ошибку в строке «legline = handler.createartists (...):

«Произошло исключение: объект AttributeError'NoneType 'не имеет атрибута' create artist '»

Здесь я воспроизвожу код (@gyger) из этого вопроса о переполнении стека:

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

Чтобы использовать этот код:

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

Ответы [ 2 ]

1 голос
/ 06 августа 2020

Похоже, что handle внутри for l oop - это список legnth-1 с дескриптором внутри него, что сбивает с толку функцию get_legend_handler, поскольку она ожидает дескриптор, а не список.

Если вместо этого вы отправите только обработчик из этого списка в legend.get_legend_handler() и handler.create_artists(), похоже, это сработает.

возможно, самый простой способ сделать это - добавить строку кода handle = handle[0] непосредственно перед вызовом функции get_legend_handler.

for i, handle in enumerate(orig_handle):

    handle = handle[0]
    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)

введите описание изображения здесь

0 голосов
/ 06 августа 2020

Как указал @tmdavison, проблема заключалась в том, что функция get_legend_handler ожидала дескриптор, а не список. Вероятно, исходный код, который я нашел, был из версии matplotlib, где это поведение было другим. Я решил это, сделав строки дескриптором (добавив запятую):

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()})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...