Guia de legenda #

Gerando legendas de forma flexível no Matplotlib.

Este guia de legendas é uma extensão da documentação disponível em legend()- verifique se você está familiarizado com o conteúdo dessa documentação antes de prosseguir com este guia.

Este guia faz uso de alguns termos comuns, que estão documentados aqui para maior clareza:

entrada da legenda #

Uma legenda é composta de uma ou mais entradas de legenda. Uma entrada é composta por exatamente uma chave e um rótulo.

chave da legenda #

O marcador colorido/padronizado à esquerda de cada legenda.

rótulo da legenda #

O texto que descreve o identificador representado pela chave.

identificador de legenda #

O objeto original que é usado para gerar uma entrada apropriada na legenda.

Controlando as entradas de legenda #

Chamar legend()sem argumentos busca automaticamente os identificadores de legenda e seus rótulos associados. Esta funcionalidade é equivalente a:

handles, labels = ax.get_legend_handles_labels()
ax.legend(handles, labels)

A get_legend_handles_labels()função retorna uma lista de manipuladores/artistas que existem nos Axes que podem ser usados ​​para gerar entradas para a legenda resultante - vale a pena notar, entretanto, que nem todos os artistas podem ser adicionados a uma legenda, ponto em que um "proxy" será devem ser criados (consulte Criando artistas especificamente para adicionar à legenda (aka. Artistas proxy) para obter mais detalhes).

Observação

Artistas com uma string vazia como rótulo ou com um rótulo começando com um sublinhado, "_", serão ignorados.

Para controle total do que está sendo adicionado à legenda, é comum passar os handles apropriados diretamente para legend():

fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend(handles=[line_up, line_down])

Em alguns casos, não é possível definir o rótulo do identificador, portanto, é possível passar pela lista de rótulos para legend():

fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend([line_up, line_down], ['Line Up', 'Line Down'])

Criando artistas especificamente para adicionar à legenda (aka. Artistas proxy) #

Nem todos os identificadores podem ser transformados em entradas de legenda automaticamente, portanto, muitas vezes é necessário criar um artista que possa . Os identificadores de legenda não precisam existir na Figura ou nos Eixos para serem usados.

Suponha que queremos criar uma legenda que tenha uma entrada para alguns dados representados por uma cor vermelha:

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
red_patch = mpatches.Patch(color='red', label='The red data')
ax.legend(handles=[red_patch])

plt.show()
guia de legenda

Existem muitos identificadores de legenda suportados. Em vez de criar um patch de cor, poderíamos ter criado uma linha com um marcador:

import matplotlib.lines as mlines

fig, ax = plt.subplots()
blue_line = mlines.Line2D([], [], color='blue', marker='*',
                          markersize=15, label='Blue stars')
ax.legend(handles=[blue_line])

plt.show()
guia de legenda

Localização da legenda #

A localização da legenda pode ser especificada pelo argumento de palavra-chave loc . Consulte a documentação em legend()para obter mais detalhes.

A bbox_to_anchorpalavra-chave fornece um alto grau de controle para o posicionamento manual da legenda. Por exemplo, se você deseja que a legenda dos eixos seja localizada no canto superior direito da figura em vez do canto dos eixos, basta especificar a localização do canto e o sistema de coordenadas desse local:

ax.legend(bbox_to_anchor=(1, 1),
          bbox_transform=fig.transFigure)

Mais exemplos de colocação de legenda personalizada:

fig, ax_dict = plt.subplot_mosaic([['top', 'top'], ['bottom', 'BLANK']],
                                  empty_sentinel="BLANK")
ax_dict['top'].plot([1, 2, 3], label="test1")
ax_dict['top'].plot([3, 2, 1], label="test2")
# Place a legend above this subplot, expanding itself to
# fully use the given bounding box.
ax_dict['top'].legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left',
                      ncol=2, mode="expand", borderaxespad=0.)

ax_dict['bottom'].plot([1, 2, 3], label="test1")
ax_dict['bottom'].plot([3, 2, 1], label="test2")
# Place a legend to the right of this smaller subplot.
ax_dict['bottom'].legend(bbox_to_anchor=(1.05, 1),
                         loc='upper left', borderaxespad=0.)

plt.show()
guia de legenda

Múltiplas legendas nos mesmos eixos #

Às vezes é mais claro dividir as entradas de legenda em várias legendas. Embora a abordagem instintiva para fazer isso possa ser chamar a legend()função várias vezes, você descobrirá que apenas uma legenda existe nos eixos. Isso foi feito para que seja possível chamar legend()repetidamente para atualizar a legenda para os últimos manipuladores dos eixos. Para manter as instâncias de legendas antigas, devemos adicioná-las manualmente aos Axes:

fig, ax = plt.subplots()
line1, = ax.plot([1, 2, 3], label="Line 1", linestyle='--')
line2, = ax.plot([3, 2, 1], label="Line 2", linewidth=4)

# Create a legend for the first line.
first_legend = ax.legend(handles=[line1], loc='upper right')

# Add the legend manually to the Axes.
ax.add_artist(first_legend)

# Create another legend for the second line.
ax.legend(handles=[line2], loc='lower right')

plt.show()
guia de legenda

Manipuladores de legendas #

Para criar entradas de legenda, os manipuladores são fornecidos como um argumento para uma HandlerBasesubclasse apropriada. A escolha da subclasse do manipulador é determinada pelas seguintes regras:

  1. Atualize get_legend_handler_map() com o valor na palavra- handler_mapchave.

  2. Verifique se o handleestá no arquivo handler_map.

  3. Verifique se o tipo de handleestá no arquivo handler_map.

  4. Verifique se algum dos tipos no handlemro está no recém-criado handler_map.

Para completar, essa lógica é implementada principalmente em get_legend_handler().

Toda essa flexibilidade significa que temos os ganchos necessários para implementar manipuladores personalizados para nosso próprio tipo de chave de legenda.

O exemplo mais simples de uso de manipuladores personalizados é instanciar uma das legend_handler.HandlerBasesubclasses existentes. Para simplificar, vamos escolher legend_handler.HandlerLine2D qual aceita um argumento numpoints (numpoints também é uma palavra-chave na legend()função por conveniência). Podemos então passar o mapeamento da instância para o Handler como uma palavra-chave para a legenda.

from matplotlib.legend_handler import HandlerLine2D

fig, ax = plt.subplots()
line1, = ax.plot([3, 2, 1], marker='o', label='Line 1')
line2, = ax.plot([1, 2, 3], marker='o', label='Line 2')

ax.legend(handler_map={line1: HandlerLine2D(numpoints=4)})
guia de legenda
<matplotlib.legend.Legend object at 0x7f2cf9a16ef0>

Como você pode ver, a "Linha 1" agora tem 4 marcadores, onde a "Linha 2" tem 2 (o padrão). Tente o código acima, apenas altere a chave do mapa de line1para type(line1). Observe como agora ambas as Line2Dinstâncias obtêm 4 marcadores.

Juntamente com manipuladores para tipos complexos de plotagem, como barras de erro, plotagens de haste e histogramas, o padrão handler_mappossui um tuplemanipulador especial ( legend_handler.HandlerTuple) que simplesmente plota os manipuladores uns sobre os outros para cada item na tupla especificada. O exemplo a seguir demonstra a combinação de duas chaves de legenda uma sobre a outra:

from numpy.random import randn

z = randn(10)

fig, ax = plt.subplots()
red_dot, = ax.plot(z, "ro", markersize=15)
# Put a white cross over some of the data.
white_cross, = ax.plot(z[:5], "w+", markeredgewidth=3, markersize=15)

ax.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"])
guia de legenda
<matplotlib.legend.Legend object at 0x7f2cfb693760>

A legend_handler.HandlerTupleclasse também pode ser usada para atribuir várias chaves de legenda à mesma entrada:

from matplotlib.legend_handler import HandlerLine2D, HandlerTuple

fig, ax = plt.subplots()
p1, = ax.plot([1, 2.5, 3], 'r-d')
p2, = ax.plot([3, 2, 1], 'k-o')

l = ax.legend([(p1, p2)], ['Two keys'], numpoints=1,
              handler_map={tuple: HandlerTuple(ndivide=None)})
guia de legenda

Implementando um manipulador de legenda personalizado #

Um manipulador personalizado pode ser implementado para transformar qualquer identificador em uma chave de legenda (os identificadores não precisam necessariamente ser artistas matplotlib). O manipulador deve implementar um legend_artistmétodo que retorne um único artista para a legenda usar. A assinatura necessária para legend_artistestá documentada em legend_artist.

import matplotlib.patches as mpatches


class AnyObject:
    pass


class AnyObjectHandler:
    def legend_artist(self, legend, orig_handle, fontsize, handlebox):
        x0, y0 = handlebox.xdescent, handlebox.ydescent
        width, height = handlebox.width, handlebox.height
        patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red',
                                   edgecolor='black', hatch='xx', lw=3,
                                   transform=handlebox.get_transform())
        handlebox.add_artist(patch)
        return patch

fig, ax = plt.subplots()

ax.legend([AnyObject()], ['My first handler'],
          handler_map={AnyObject: AnyObjectHandler()})
guia de legenda
<matplotlib.legend.Legend object at 0x7f2cddb26a10>

Como alternativa, se quiséssemos aceitar AnyObjectinstâncias globalmente sem precisar definir manualmente a palavra-chave handler_map o tempo todo, poderíamos ter registrado o novo manipulador com:

from matplotlib.legend import Legend
Legend.update_default_handler_map({AnyObject: AnyObjectHandler()})

Embora o poder aqui seja claro, lembre-se de que já existem muitos manipuladores implementados e o que você deseja alcançar já pode ser facilmente possível com as classes existentes. Por exemplo, para produzir chaves de legenda elípticas, em vez de retangulares:

from matplotlib.legend_handler import HandlerPatch


class HandlerEllipse(HandlerPatch):
    def create_artists(self, legend, orig_handle,
                       xdescent, ydescent, width, height, fontsize, trans):
        center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent
        p = mpatches.Ellipse(xy=center, width=width + xdescent,
                             height=height + ydescent)
        self.update_prop(p, orig_handle, legend)
        p.set_transform(trans)
        return [p]


c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green",
                    edgecolor="red", linewidth=3)

fig, ax = plt.subplots()

ax.add_patch(c)
ax.legend([c], ["An ellipse, not a rectangle"],
          handler_map={mpatches.Circle: HandlerEllipse()})
guia de legenda
<matplotlib.legend.Legend object at 0x7f2d00dde710>

Tempo total de execução do script: (0 minutos 3,053 segundos)

Galeria gerada por Sphinx-Gallery