在 matplotlib 中剪切注释
Clipping annotations in matplotlib
有没有办法为 matplotlib.text.Annotation
设置剪辑边界?
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
fig, ax = plt.subplots()
vals = [
(10,20,"Lorem ipsum dolor sit amet, consectetur adipiscing elit"),
(30,20, "Pellentesque scelerisque congue fermentum."),
(50,10, "Aliquam erat volutpat")
]
ax.set_ylim(0,1)
ax.broken_barh(map(lambda v: v[:2],vals), (0, 1), facecolors=('yellow','red','green'))
for v in vals:
ax.annotate(
v[2],
xy=(v[0],0.4),
clip_on=True,
clip_box=Bbox([[v[0],0],[v[0]+v[1],1]])
)
plt.show()
我尝试在 ax.annotate
调用上设置 clip_box
和 clip_path
,但这不起作用。
首先,问得好!您正在深入细节,因此您需要了解相当多的 semi-undocumented 细节。
除了以下两点,您当前的方法是可行的:
clip_box
应该在显示坐标中,因此您需要对其进行转换。
- 为此使用 "plain"
Bbox
是不够的。每次显示更改时,要将数据坐标转换为 re-done,您需要使用 TransformedBbox
.
为了进一步说明发生了什么,让我们解决第一个问题,而不是第二个问题:
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
fig, ax = plt.subplots()
vals = [
(10,20,"Lorem ipsum dolor sit amet, consectetur adipiscing elit"),
(30,20, "Pellentesque scelerisque congue fermentum."),
(50,10, "Aliquam erat volutpat")
]
ax.set_ylim(0,1)
ax.broken_barh(map(lambda v: v[:2],vals), (0, 1),
facecolors=('yellow','red','green'))
for v in vals:
box = Bbox([[v[0],0],[v[0]+v[1],1]]).transformed(ax.transData)
anno = ax.annotate(v[2], xy=(v[0],0.4), clip_box=box)
plt.show()
一开始看起来不错,但还有一个问题:因为 clip_box
是静态的并且在显示坐标中,所以一旦您以任何方式更改绘图(例如,缩放、平移、自动缩放、更改图形 window 大小、更改图形 DPI)。
例如,如果我点击 "save" 按钮(或调用 savefig
),剪辑框将不正确,因为图形的 DPI 将在之前更改(从 80 到 100)节省!
因此,您需要为此使用 TransformedBbox
。它只是 Bbox
的一个版本,它保存对转换的引用,如果转换发生变化,则 re-transforms 底层 Bbox
。在 matplotlib 中有一些 Transformed*
类 沿着这些线:例如TransformedPath
,等等。它们不是您总是需要了解的详细程度,但它们可能非常有用。
作为最后一个例子,无论情节如何,它都会正常工作 zoomed/panned/changed:
import matplotlib.pyplot as plt
from matplotlib.transforms import TransformedBbox, Bbox
fig, ax = plt.subplots()
vals = [
(10,20,"Lorem ipsum dolor sit amet, consectetur adipiscing elit"),
(30,20, "Pellentesque scelerisque congue fermentum."),
(50,10, "Aliquam erat volutpat")
]
ax.set_ylim(0,1)
ax.broken_barh(map(lambda v: v[:2],vals), (0, 1),
facecolors=('yellow','red','green'))
for v in vals:
box = TransformedBbox(Bbox([[v[0],0],[v[0]+v[1],1]]), ax.transData)
anno = ax.annotate(v[2], xy=(v[0],0.4), clip_box=box)
plt.show()
有没有办法为 matplotlib.text.Annotation
设置剪辑边界?
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
fig, ax = plt.subplots()
vals = [
(10,20,"Lorem ipsum dolor sit amet, consectetur adipiscing elit"),
(30,20, "Pellentesque scelerisque congue fermentum."),
(50,10, "Aliquam erat volutpat")
]
ax.set_ylim(0,1)
ax.broken_barh(map(lambda v: v[:2],vals), (0, 1), facecolors=('yellow','red','green'))
for v in vals:
ax.annotate(
v[2],
xy=(v[0],0.4),
clip_on=True,
clip_box=Bbox([[v[0],0],[v[0]+v[1],1]])
)
plt.show()
我尝试在 ax.annotate
调用上设置 clip_box
和 clip_path
,但这不起作用。
首先,问得好!您正在深入细节,因此您需要了解相当多的 semi-undocumented 细节。
除了以下两点,您当前的方法是可行的:
clip_box
应该在显示坐标中,因此您需要对其进行转换。- 为此使用 "plain"
Bbox
是不够的。每次显示更改时,要将数据坐标转换为 re-done,您需要使用TransformedBbox
.
为了进一步说明发生了什么,让我们解决第一个问题,而不是第二个问题:
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
fig, ax = plt.subplots()
vals = [
(10,20,"Lorem ipsum dolor sit amet, consectetur adipiscing elit"),
(30,20, "Pellentesque scelerisque congue fermentum."),
(50,10, "Aliquam erat volutpat")
]
ax.set_ylim(0,1)
ax.broken_barh(map(lambda v: v[:2],vals), (0, 1),
facecolors=('yellow','red','green'))
for v in vals:
box = Bbox([[v[0],0],[v[0]+v[1],1]]).transformed(ax.transData)
anno = ax.annotate(v[2], xy=(v[0],0.4), clip_box=box)
plt.show()
一开始看起来不错,但还有一个问题:因为 clip_box
是静态的并且在显示坐标中,所以一旦您以任何方式更改绘图(例如,缩放、平移、自动缩放、更改图形 window 大小、更改图形 DPI)。
例如,如果我点击 "save" 按钮(或调用 savefig
),剪辑框将不正确,因为图形的 DPI 将在之前更改(从 80 到 100)节省!
因此,您需要为此使用 TransformedBbox
。它只是 Bbox
的一个版本,它保存对转换的引用,如果转换发生变化,则 re-transforms 底层 Bbox
。在 matplotlib 中有一些 Transformed*
类 沿着这些线:例如TransformedPath
,等等。它们不是您总是需要了解的详细程度,但它们可能非常有用。
作为最后一个例子,无论情节如何,它都会正常工作 zoomed/panned/changed:
import matplotlib.pyplot as plt
from matplotlib.transforms import TransformedBbox, Bbox
fig, ax = plt.subplots()
vals = [
(10,20,"Lorem ipsum dolor sit amet, consectetur adipiscing elit"),
(30,20, "Pellentesque scelerisque congue fermentum."),
(50,10, "Aliquam erat volutpat")
]
ax.set_ylim(0,1)
ax.broken_barh(map(lambda v: v[:2],vals), (0, 1),
facecolors=('yellow','red','green'))
for v in vals:
box = TransformedBbox(Bbox([[v[0],0],[v[0]+v[1],1]]), ax.transData)
anno = ax.annotate(v[2], xy=(v[0],0.4), clip_box=box)
plt.show()