[英]Legend outside the plot in Python - matplotlib
我試圖在matplotlib的情節之外放置一個相當廣泛的傳奇。 這個圖例有很多條目,每個條目都可以很長(但我不確切知道多長時間)。
顯然,這很容易使用
legendHandle = plt.legend(loc = "center left", bbox_to_anchor = (1, 0.5))
但問題是圖例被窗戶邊緣切斷了。 我花了很長時間尋找解決方案。 到目前為止我能找到的最好的事情是:
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
plt.legend(loc = "center left", bbox_to_anchor = (1, 0.5))
不幸的是,這並沒有真正解決我的問題。 由於應用於框寬的顯式因子0.8,這僅適用於圖形和圖例寬度的一個特定組合。 如果我調整圖形窗口的大小,或者我的圖例條目具有不同的長度,則它不起作用。
我只是不明白如何在圖中放置一個圖例是如此困難。 我習慣了Matlab,就像它一樣簡單
legend('Location', 'eastoutside')
Python中是否有類似的東西我缺少?
嘗試了很多,這是我能想到的最好的:
from matplotlib.lines import Line2D
from matplotlib.gridspec import GridSpec
from enum import Enum
class Location(Enum):
EastOutside = 1
WestOutside = 2
NorthOutside = 3
SouthOutside = 4
class Legend:
def __init__(self, figure, plotAxes, location: Location):
self.figure = figure
self.plotAxes = plotAxes
self.location = location
# Create a separate subplot for the legend. Actual location doesn't matter - will be modified anyway.
self.legendAxes = figure.add_subplot(1, 2, 1)
self.legendAxes.clear() # remove old lines
self.legendAxes.set_axis_off()
# Add all lines from the plot to the legend subplot
for line in plotAxes.get_lines():
legendLine = Line2D([], [])
legendLine.update_from(line)
self.legendAxes.add_line(legendLine)
if self.location == Location.EastOutside:
self.legend = self.legendAxes.legend(loc = "center left")
elif self.location == Location.WestOutside:
self.legend = self.legendAxes.legend(loc = "center right")
elif self.location == Location.NorthOutside:
self.legend = self.legendAxes.legend(loc = "lower center")
elif self.location == Location.SouthOutside:
self.legend = self.legendAxes.legend(loc = "upper center")
else:
raise Exception("Unknown legend location.")
self.UpdateSize()
# Recalculate legend size if the size changes
figure.canvas.mpl_connect('resize_event', lambda event: self.UpdateSize())
def UpdateSize(self):
self.figure.canvas.draw() # draw everything once in order to get correct legend size
# Extract legend size in percentage of the figure width
legendSize = self.legend.get_window_extent().inverse_transformed(self.figure.transFigure)
legendWidth = legendSize.width
legendHeight = legendSize.height
# Update subplot such that it is only as large as the legend
if self.location == Location.EastOutside:
gridspec = GridSpec(1, 2, width_ratios = [1 - legendWidth, legendWidth])
legendLocation = 1
plotLocation = 0
elif self.location == Location.WestOutside:
gridspec = GridSpec(1, 2, width_ratios = [legendWidth, 1 - legendWidth])
legendLocation = 0
plotLocation = 1
elif self.location == Location.NorthOutside:
gridspec = GridSpec(2, 1, height_ratios = [legendHeight, 1 - legendHeight])
legendLocation = 0
plotLocation = 1
elif self.location == Location.SouthOutside:
gridspec = GridSpec(2, 1, height_ratios = [1 - legendHeight, legendHeight])
legendLocation = 1
plotLocation = 0
else:
raise Exception("Unknown legend location.")
self.legendAxes.set_position(gridspec[legendLocation].get_position(self.figure))
self.legendAxes.set_subplotspec(gridspec[legendLocation]) # to make figure.tight_layout() work if that's desired
self.plotAxes.set_position(gridspec[plotLocation].get_position(self.figure))
self.plotAxes.set_subplotspec(gridspec[plotLocation]) # to make figure.tight_layout() work if that's desired
在我到目前為止測試的情況下,這使得圖例或多或少都沒有。 用法是例如
import matplotlib.pyplot as plt
plt.ion()
figure = plt.figure()
plotAxes = figure.gca()
plotAxes.plot([1, 2, 3], [4, 5, 6], "b-", label = "Testaaaaaaaaaaaaaa 1")
plotAxes.plot([1, 2, 3], [6, 5, 4], "r-", label = "Test 2")
legend = Legend(figure, plotAxes, Location.EastOutside)
讓我問一下我在評論中發布的問題......我將如何建議將其作為matplotlib開發人員的附加功能? (不是我的黑客,而是在圖中有傳說的本地方式)
只是偶然發現了這個問題,我想你可以使用這個圖的傳奇方法:
import matplotlib.pyplot as plt
# sample data
x1 = [1,2,3,4,5,6]
y1 = [0,1,0,1,0,1]
x2 = [1,2,3,4,5,6]
y2 = [9,8,8,7,8,6]
fig = plt.figure(figsize=(4, 2), dpi=100)
ax = fig.add_subplot(111)
ax.plot(x1,y1,x2,y2)
fig.legend(loc=1, mode='expand', numpoints=1, ncol=4, fancybox = True,
fontsize='small', labels=['d1', 'd2'])
# loc=1 means at the top-right of the figure
plt.show()
雖然圖例位於軸外,但如果圖例太大,它仍可能與軸重疊。
可以使用參數loc和bbox_to_anchor來控制圖例的放置 。 這是一個代碼示例:
import matplotlib.pyplot as plt
#sample data
import numpy as np
x = np.linspace(0, 2, 101)
#create figure and its axes
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
#plot 3 lines and define their labels
ax.plot(x, x**2, label="square")
ax.plot(x, x**3, label="cubic")
ax.plot(x, np.sin(x), label="sinus")
#place the legend
ax.legend(loc='lower center', bbox_to_anchor=(0.5, 1.0), ncol=3)
# The center of the lower edge of the rectangle containing the legend
# is placed at coordinates (x,y)=(0.5,1.0) of ax.
# Thus, figure and legend should not overlap.
plt.show()
您現在應該看到下圖: 帶有圖例的圖
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.