gpt4 book ai didi

python - Python 中情节外的图例 - matplotlib

转载 作者:太空宇宙 更新时间:2023-11-03 11:46:53 25 4
gpt4 key购买 nike

我试图在 matplotlib 的情节之外放置一个相当广泛的图例。图例有很多条目,每个条目可能很长(但我不知 Prop 体有多长)。

显然,这很容易使用

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 开发人员建议将其作为附加功能? (不是我的技巧,而是将图例置于图形之外的一种原生方式)

关于python - Python 中情节外的图例 - matplotlib,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37324419/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com