web-dev-qa-db-fra.com

augmenter la largeur de ligne des lignes de légende dans matplotlib

Je sais que si je modifie la largeur de ligne d'une ligne, celle-ci est automatiquement mise à jour dans la légende. Cependant, je voudrais juste changer la largeur de ligne de la légende sans affecter le tracé.

49
Andrea Zonca

Voici un exemple simple de la façon de procéder:

import numpy as np
import matplotlib.pyplot as plt

# make some data
x = np.linspace(0, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

# plot sin(x) and cos(x)
p1 = plt.plot(x, y1, 'b-', linewidth=1.0)
p2 = plt.plot(x, y2, 'r-', linewidth=1.0)

# make a legend for both plots
leg = plt.legend([p1, p2], ['sin(x)', 'cos(x)'], loc=1)

# set the linewidth of each legend object
for legobj in leg.legendHandles:
    legobj.set_linewidth(2.0)

plt.show()
62
Brendan Wood

La méthode de @Brendan Wood utilise l'API fournie par pyplot. Dans matplotlib, le le style orienté objet utilisant des axes est préférable . Voici comment vous pouvez y parvenir en utilisant la méthode axes.

import numpy as np
import matplotlib.pyplot as plt

# make some data
x = np.linspace(0, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

fig, ax = plt.subplots()
ax.plot(x, y1, linewidth=1.0, label='sin(x)')
ax.plot(x, y2, linewidth=1.0, label='cos(x)')
leg = ax.legend()

for line in leg.get_lines():
    line.set_linewidth(4.0)

plt.show()

Le graphique produit est illustré ci-dessous, enter image description here

6
jdhao

Par défaut, la légende contient les lignes elles-mêmes. Par conséquent, la modification de la largeur de ligne des lignes dans le canevas modifiera également les lignes dans la légende (et vice versa, car elles sont essentiellement le même objet).

Une solution possible consiste à utiliser une copie de l'artiste à partir du canevas et à modifier uniquement la largeur de ligne de la copie.

import numpy as np
import matplotlib.pyplot as plt
import copy

x = np.linspace(0, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)
fig = plt.figure()
ax  = fig.add_subplot(111)
ax.plot(x, y1, c='b', label='y1',linewidth=1.0)
ax.plot(x, y2, c='r', label='y2')

# obtain the handles and labels from the figure
handles, labels = ax.get_legend_handles_labels()
# copy the handles
handles = [copy.copy(ha) for ha in handles ]
# set the linewidths to the copies
[ha.set_linewidth(7) for ha in handles ]
# put the copies into the legend
leg = plt.legend(handles=handles, labels=labels)

plt.savefig('leg_example')
plt.show()

enter image description here

Une autre option serait d'utiliser un handler_map et une fonction de mise à jour. C'est en quelque sorte automatique, spécifiant que la carte du gestionnaire ferait automatiquement n'importe quelle ligne de la légende de 7 points de large.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.legend_handler import HandlerLine2D

x = np.linspace(0, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)
fig = plt.figure()
ax  = fig.add_subplot(111)
ax.plot(x, y1, c='b', label='y1',linewidth=1.0)
ax.plot(x, y2, c='r', label='y2')

linewidth=7
def update(handle, orig):
    handle.update_from(orig)
    handle.set_linewidth(7)

plt.legend(handler_map={plt.Line2D : HandlerLine2D(update_func=update)})

plt.show()

Le résultat est le même que ci-dessus.

3

Si vous souhaitez modifier toutes les lignes d'un tracé, il peut être utile de définir votre propre gestionnaire de légende:

import matplotlib.pyplot as plt
from matplotlib import legend_handler
from matplotlib.lines import Line2D
import numpy as np

class MyHandlerLine2D(legend_handler.HandlerLine2D):
    def create_artists(self, legend, orig_handle,
                       xdescent, ydescent, width, height, fontsize,
                       trans):

        xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent,
                                             width, height, fontsize)

        ydata = ((height-ydescent)/2.)*np.ones(xdata.shape, float)
        legline = Line2D(xdata, ydata)

        self.update_prop(legline, orig_handle, legend)
        #legline.update_from(orig_handle)
        #legend._set_artist_props(legline) # after update
        #legline.set_clip_box(None)
        #legline.set_clip_path(None)
        legline.set_drawstyle('default')
        legline.set_marker("")
        legline.set_linewidth(10)


        legline_marker = Line2D(xdata_marker, ydata[:len(xdata_marker)])
        self.update_prop(legline_marker, orig_handle, legend)
        #legline_marker.update_from(orig_handle)
        #legend._set_artist_props(legline_marker)
        #legline_marker.set_clip_box(None)
        #legline_marker.set_clip_path(None)
        legline_marker.set_linestyle('None')
        if legend.markerscale != 1:
            newsz = legline_marker.get_markersize()*legend.markerscale
            legline_marker.set_markersize(newsz)
        # we don't want to add this to the return list because
        # the texts and handles are assumed to be in one-to-one
        # correpondence.
        legline._legmarker = legline_marker

        return [legline, legline_marker]


plt.plot( [0, 1], [0, 1], '-r', lw=1, label='Line' )
plt.legend(handler_map={Line2D:MyHandlerLine2D()})

plt.show()
3
David Zwicker