将matplotlib矩形边设置为指定宽度的外部?

时间:2023-02-09 18:31:56

Is there a way to specify the edge for matplotlib's Rectangle patch so that the border is outside the domain specified? In photoshop, this is would be called "stroke position", for example. Allow me to illustrate with an example:

有没有办法为matplotlib的Rectangle补丁指定边缘,以便边界在指定的域之外?例如,在photoshop中,这将被称为“笔画位置”。请允许我举例说明:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle


# Here's my "image"
X = np.arange(16).reshape(4,4)

# Suppose I want to highlight some feature in the middle boxes.
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(X, cmap=plt.cm.gray, interpolation='nearest')
ax.add_patch( Rectangle((0.5, 0.5), 2, 2, fc='none', ec='r') )
plt.show()

This yields the following:

这产生以下结果:

将matplotlib矩形边设置为指定宽度的外部?

However, if modified the above as follows

但是,如果修改如下

ax.add_patch( Rectangle((0.5, 0.5), 2, 2, fc='none', ec='r', lw=10) )

I obtain the figure:

我得到了这个数字:

将matplotlib矩形边设置为指定宽度的外部?

As you can see, the edge is center-positioned along the border of the domain of the Rectangle object, and so bleeds into this domain. Is it possible to force the edge border to be strictly outside the Rectangle's domain?

如您所见,边缘位于Rectangle对象域边界的中心位置,因此会渗入此域。是否可以强制边缘边界严格位于Rectangle域之外?

1 个解决方案

#1


You may use an AnnotationBbox inside of which an AuxTransformBox is placed. This AuxTransformBox would contain a proxy rectangle of the desired size. This can be made invisible (e.g. fc='none', ec='none'). Its only function is to scale the AuxTransformBox to the right size. Now the AnnotationBbox can be given a border of some large linewidth. If it is sitting tight against the AuxTransformBox the border will only start where the AuxTransformBox ends. To let the border fit tightly, one can set the padding pad to half the linewidth of the border. Since padding is given in units of fontsize, it is the fontsize which needs to be set to the linewidth and the padding to 0.5, pad=0.5,fontsize=linewidth. Note that it appears that a slightly larger padding of 0.52 looks nicer on the plot; in any case this can be adjusted to one's liking.

您可以使用其中放置AuxTransformBox的AnnotationBbox。此AuxTransformBox将包含所需大小的代理矩形。这可以是不可见的(例如fc ='none',ec ='none')。它唯一的功能是将AuxTransformBox缩放到合适的大小。现在可以为AnnotationBbox指定一些大线宽的边框。如果它紧靠AuxTransformBox,边框将仅在AuxTransformBox结束的地方开始。为了使边框紧密贴合,可以将填充垫设置为边框线宽的一半。由于填充是以fontsize为单位给出的,因此需要将字体大小设置为线宽,将填充设置为0.5,pad = 0.5,fontsize = linewidth。请注意,看起来0.52的稍大填充看起来更好;无论如何,这可以根据自己的喜好进行调整。

Sounds complicated, but the code is copy and pastable to be used anywhere a Rectangle would usually be used.

听起来很复杂,但代码是copy和pastable,可以在任何通常使用Rectangle的地方使用。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.offsetbox import AnnotationBbox, AuxTransformBox


# Here's my "image"
X = np.arange(16).reshape(4,4)

# Suppose I want to highlight some feature in the middle boxes.
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(X, cmap=plt.cm.gray, interpolation='nearest', aspect="auto")

linewidth=14
xy, w, h = (0.5, 0.5), 2, 2
r = Rectangle(xy, w, h, fc='none', ec='gold', lw=1)

offsetbox = AuxTransformBox(ax.transData)
offsetbox.add_artist(r)
ab = AnnotationBbox(offsetbox, (xy[0]+w/2.,xy[1]+w/2.),
                    boxcoords="data", pad=0.52,fontsize=linewidth,
                    bboxprops=dict(facecolor = "none", edgecolor='r', 
                              lw = linewidth))
ax.add_artist(ab)


plt.show()

将matplotlib矩形边设置为指定宽度的外部?

#1


You may use an AnnotationBbox inside of which an AuxTransformBox is placed. This AuxTransformBox would contain a proxy rectangle of the desired size. This can be made invisible (e.g. fc='none', ec='none'). Its only function is to scale the AuxTransformBox to the right size. Now the AnnotationBbox can be given a border of some large linewidth. If it is sitting tight against the AuxTransformBox the border will only start where the AuxTransformBox ends. To let the border fit tightly, one can set the padding pad to half the linewidth of the border. Since padding is given in units of fontsize, it is the fontsize which needs to be set to the linewidth and the padding to 0.5, pad=0.5,fontsize=linewidth. Note that it appears that a slightly larger padding of 0.52 looks nicer on the plot; in any case this can be adjusted to one's liking.

您可以使用其中放置AuxTransformBox的AnnotationBbox。此AuxTransformBox将包含所需大小的代理矩形。这可以是不可见的(例如fc ='none',ec ='none')。它唯一的功能是将AuxTransformBox缩放到合适的大小。现在可以为AnnotationBbox指定一些大线宽的边框。如果它紧靠AuxTransformBox,边框将仅在AuxTransformBox结束的地方开始。为了使边框紧密贴合,可以将填充垫设置为边框线宽的一半。由于填充是以fontsize为单位给出的,因此需要将字体大小设置为线宽,将填充设置为0.5,pad = 0.5,fontsize = linewidth。请注意,看起来0.52的稍大填充看起来更好;无论如何,这可以根据自己的喜好进行调整。

Sounds complicated, but the code is copy and pastable to be used anywhere a Rectangle would usually be used.

听起来很复杂,但代码是copy和pastable,可以在任何通常使用Rectangle的地方使用。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.offsetbox import AnnotationBbox, AuxTransformBox


# Here's my "image"
X = np.arange(16).reshape(4,4)

# Suppose I want to highlight some feature in the middle boxes.
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(X, cmap=plt.cm.gray, interpolation='nearest', aspect="auto")

linewidth=14
xy, w, h = (0.5, 0.5), 2, 2
r = Rectangle(xy, w, h, fc='none', ec='gold', lw=1)

offsetbox = AuxTransformBox(ax.transData)
offsetbox.add_artist(r)
ab = AnnotationBbox(offsetbox, (xy[0]+w/2.,xy[1]+w/2.),
                    boxcoords="data", pad=0.52,fontsize=linewidth,
                    bboxprops=dict(facecolor = "none", edgecolor='r', 
                              lw = linewidth))
ax.add_artist(ab)


plt.show()

将matplotlib矩形边设置为指定宽度的外部?