matplotlib
Легенды
Поиск…
Простая легенда
Предположим, у вас есть несколько строк на одном и том же сюжете, каждый из другого цвета, и вы хотите сделать легенду, чтобы сообщить, что представляет каждая строка. Вы можете сделать это, передав метку каждой строке при вызове plot()
, например, следующая строка будет помечена как «Моя линия 1» .
ax.plot(x, y1, color="red", label="My Line 1")
Это указывает текст, который будет отображаться в легенде для этой строки. Теперь, чтобы сделать реальную легенду видимой, мы можем вызвать ax.legend()
По умолчанию он создает легенду внутри поля в правом верхнем углу графика. Вы можете передать аргументы в legend()
чтобы настроить его. Например, мы можем поместить его в нижнем правом углу, без рамки рамки вокруг него и создания заголовка для легенды, вызвав следующее:
ax.legend(loc="lower right", title="Legend Title", frameon=False)
Ниже приведен пример:
import matplotlib.pyplot as plt
# The data
x = [1, 2, 3]
y1 = [2, 15, 27]
y2 = [10, 40, 45]
y3 = [5, 25, 40]
# Initialize the figure and axes
fig, ax = plt.subplots(1, figsize=(8, 6))
# Set the title for the figure
fig.suptitle('Simple Legend Example ', fontsize=15)
# Draw all the lines in the same plot, assigning a label for each one to be
# shown in the legend
ax.plot(x, y1, color="red", label="My Line 1")
ax.plot(x, y2, color="green", label="My Line 2")
ax.plot(x, y3, color="blue", label="My Line 3")
# Add a legend with title, position it on the lower right (loc) with no box framing (frameon)
ax.legend(loc="lower right", title="Legend Title", frameon=False)
# Show the plot
plt.show()
Легенда, размещенная за пределами участка
Иногда необходимо или желательно разместить легенду вне сюжета. Следующий код показывает, как это сделать.
import matplotlib.pylab as plt
fig, ax = plt.subplots(1, 1, figsize=(10,6)) # make the figure with the size 10 x 6 inches
fig.suptitle('Example of a Legend Being Placed Outside of Plot')
# The data
x = [1, 2, 3]
y1 = [1, 2, 4]
y2 = [2, 4, 8]
y3 = [3, 5, 14]
# Labels to use for each line
line_labels = ["Item A", "Item B", "Item C"]
# Create the lines, assigning different colors for each one.
# Also store the created line objects
l1 = ax.plot(x, y1, color="red")[0]
l2 = ax.plot(x, y2, color="green")[0]
l3 = ax.plot(x, y3, color="blue")[0]
fig.legend([l1, l2, l3], # List of the line objects
labels= line_labels, # The labels for each line
loc="center right", # Position of the legend
borderaxespad=0.1, # Add little spacing around the legend box
title="Legend Title") # Title for the legend
# Adjust the scaling factor to fit your legend text completely outside the plot
# (smaller value results in more space being made for the legend)
plt.subplots_adjust(right=0.85)
plt.show()
Другой способ разместить легенду вне сюжета - использовать bbox_to_anchor
+ bbox_extra_artists
+ bbox_inches='tight'
, как показано в примере ниже:
import matplotlib.pyplot as plt
# Data
all_x = [10,20,30]
all_y = [[1,3], [1.5,2.9],[3,2]]
# Plot
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.plot(all_x, all_y)
# Add legend, title and axis labels
lgd = ax.legend([ 'Lag ' + str(lag) for lag in all_x], loc='center right', bbox_to_anchor=(1.3, 0.5))
ax.set_title('Title')
ax.set_xlabel('x label')
ax.set_ylabel('y label')
fig.savefig('image_output.png',
dpi=300,
format='png',
bbox_extra_artists=(lgd,),
bbox_inches='tight')
Единая легенда, разделенная на несколько подсетей
Иногда у вас будет сетка подзаголовков, и вы хотите иметь одну легенду, которая описывает все строки для каждой из подзаголовков, как на следующем изображении.
Для этого вам нужно будет создать глобальную легенду для фигуры вместо создания легенды на уровне осей (которая создаст отдельную легенду для каждого подзаголовка). Это достигается путем вызова fig.legend()
как это видно из кода для следующего кода.
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(10,4))
fig.suptitle('Example of a Single Legend Shared Across Multiple Subplots')
# The data
x = [1, 2, 3]
y1 = [1, 2, 3]
y2 = [3, 1, 3]
y3 = [1, 3, 1]
y4 = [2, 2, 3]
# Labels to use in the legend for each line
line_labels = ["Line A", "Line B", "Line C", "Line D"]
# Create the sub-plots, assigning a different color for each line.
# Also store the line objects created
l1 = ax1.plot(x, y1, color="red")[0]
l2 = ax2.plot(x, y2, color="green")[0]
l3 = ax3.plot(x, y3, color="blue")[0]
l4 = ax3.plot(x, y4, color="orange")[0] # A second line in the third subplot
# Create the legend
fig.legend([l1, l2, l3, l4], # The line objects
labels=line_labels, # The labels for each line
loc="center right", # Position of legend
borderaxespad=0.1, # Small spacing around legend box
title="Legend Title" # Title for the legend
)
# Adjust the scaling factor to fit your legend text completely outside the plot
# (smaller value results in more space being made for the legend)
plt.subplots_adjust(right=0.85)
plt.show()
Что-то, что следует отметить в приведенном выше примере, следующее:
l1 = ax1.plot(x, y1, color="red")[0]
Когда вызывается plot()
, он возвращает список объектов line2D . В этом случае он просто возвращает список с одним единственным объектом line2D , который извлекается с индексированием [0]
и сохраняется в l1
.
Список всех объектов line2D, которые мы заинтересованы в включении в легенду, должен быть передан в качестве первого аргумента fig.legend()
. Также необходим второй аргумент fig.legend()
. Он должен быть списком строк для использования в качестве меток для каждой строки в легенде.
Другие аргументы, переданные fig.legend()
являются необязательными и просто помогают с тонкой настройкой эстетики легенды.
Несколько легенд о тех же топорах
Если вы вызываете plt.legend()
или ax.legend()
более одного раза, первая легенда удаляется и создается новый. Согласно официальной документации :
Это было сделано так, чтобы можно было вызвать legend () несколько раз, чтобы обновить легенду до последних дескрипторов на оси
Не бойтесь, хотя: до сих пор довольно просто добавить вторую легенду (или третью, или четвертую ...) к осям. В примере здесь мы построим две строки, затем построим маркеры по их соответствующим максимумам и минимумам. Одна легенда относится к строкам, а другая - к маркерам.
import matplotlib.pyplot as plt
import numpy as np
# Generate data for plotting:
x = np.linspace(0,2*np.pi,100)
y0 = np.sin(x)
y1 = .9*np.sin(.9*x)
# Find their maxima and minima and store
maxes = np.empty((2,2))
mins = np.empty((2,2))
for k,y in enumerate([y0,y1]):
maxloc = y.argmax()
maxes[k] = x[maxloc], y[maxloc]
minloc = y.argmin()
mins[k] = x[minloc], y[minloc]
# Instantiate figure and plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x,y0, label='y0')
ax.plot(x,y1, label='y1')
# Plot maxima and minima, and keep references to the lines
maxline, = ax.plot(maxes[:,0], maxes[:,1], 'r^')
minline, = ax.plot(mins[:,0], mins[:,1], 'ko')
# Add first legend: only labeled data is included
leg1 = ax.legend(loc='lower left')
# Add second legend for the maxes and mins.
# leg1 will be removed from figure
leg2 = ax.legend([maxline,minline],['max','min'], loc='upper right')
# Manually add the first legend back
ax.add_artist(leg1)
Ключ должен убедиться, что у вас есть ссылки на объекты легенды. Первый экземпляр ( leg1
) удаляется из рисунка при добавлении второго, но объект leg1
все еще существует и может быть добавлен обратно с помощью ax.add_artist
.
Самое замечательное, что вы все еще можете манипулировать обоими легендами. Например, добавьте следующее в нижнюю часть приведенного выше кода:
leg1.get_lines()[0].set_lw(8)
leg2.get_texts()[1].set_color('b')
Наконец, стоит упомянуть, что в примере только строкам были нанесены метки при построении графика, что означает, что ax.legend()
добавляет только те строки в leg1
. Поэтому легенда для маркеров ( leg2
) требовала, чтобы строки и метки были аргументами, когда они были созданы. Мы могли бы, в качестве альтернативы, дать метки маркерам, когда они были заложены. Но тогда оба вызова ax.legend
потребовали бы дополнительных аргументов, чтобы каждая легенда содержала только те предметы, которые мы хотели.