matplotlib 中的固定大小矩形? [英] Fixed size rectangle in matplotlib?

查看:47
本文介绍了matplotlib 中的固定大小矩形?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么方法可以绘制一个跨越 X 轴整个长度的矩形 但具有固定和静态高度,比如 20 像素?矩形的高度应该保持不变像素,无论缩放图或调整图大小.我花了几个小时寻找解决方案,但我无法让它发挥作用.有什么建议么?谢谢

解决方案

您想创建一个矩形,以轴坐标定位,并在轴坐标中水平调整大小,但高度以像素(屏幕-)坐标表示.

这里的棘手之处在于,简单地应用混合变换是行不通的,因为y位置所处的坐标系必须不同于矩形的高度;在 y 方向上没有问题,因为位置和宽度都是相同的坐标系.
下面显示了三个可能的选项.

A.使用偏移框

一个解决方案是创建矩形并将其打包成一个

现在矩形始终与轴相连,即使在平移/缩放/重新缩放时也是如此.

B.使用回调

或者,您可以使用回调来调整矩形的高度.

i.轴坐标,更新高度

在此,可以在轴坐标中定义矩形,这对于位置和宽度都是有用的.然后可以将高度计算为 20 个像素除以轴的高度(以像素为单位).您可能会在每次调整图形大小和更改轴的高度时重新计算高度.

 将matplotlib.pyplot导入为plt导入 matplotlib.transforms 作为 mtransforms无花果,ax = plt.subplots()高度 = 20 # 像素rect = plt.Rectangle((0,0),1,1,transform = ax.transAxes)ax.add_patch(rect)def update_rect(evt=None):bbox_pixel = mtransforms.TransformedBbox(ax.get_position(), fig.transFigure)rect.set_height(height/bbox_pixel.height)update_rect()fig.canvas.mpl_connect("resize_event", update_rect)plt.show()

ii.像素坐标,更新位置和宽度

同样,您当然可以在像素坐标中定义矩形,并根据实际轴大小使用回调设置宽度和位置.

 将matplotlib.pyplot导入为plt导入 matplotlib.transforms 作为 mtransforms无花果,ax = plt.subplots()pos = (0,0) #轴坐标宽度 = 1 #-"-rect = plt.Rectangle((0,0),20,20,transform = None)ax.add_patch(rect)def update_rect(evt=None):bbox_pixel = mtransforms.TransformedBbox(ax.get_position(),图transFigure)打印(bbox_pixel.width)rect.set_width(bbox_pixel.width*width)rect.set_xy((bbox_pixel.x0 + pos [0] * bbox_pixel.width,bbox_pixel.y0 + pos[1]*bbox_pixel.height))update_rect()fig.canvas.mpl_connect("resize_event",update_rect)plt.show()

C.创建插入轴

您还可以创建一个位于左下角的插入轴,该轴是父轴的 100% 宽,20 像素/图形 dpi 高.在该插图中,您可以创建一个填充整个轴的矩形.

 将matplotlib.pyplot导入为plt从 mpl_toolkits.axes_grid1.inset_locator 导入 inset_axes无花果,ax = plt.subplots()rect_ax = inset_axes(ax, "100%", 20/fig.dpi, loc="左下角", borderpad=0)rect_ax.axis("关闭")rect = plt.Rectangle((0,0),1,1,transform = rect_ax.transAxes)rect_ax.add_patch(rect)plt.show()

Is there any way to plot a rectangle spanning the entire length of the X-axis but with a fixed and static height of, say 20 pixels? The height of the rectangle should remain a constant number of pixels regardless of zooming or resizing the plot. I've spent hours looking for a solution to this but I just cannot make it work. Any suggestions? Thanks

解决方案

You want to create a rectangle, positionned in axes coordinates, and horizontally sized in axes coordinates as well, but with a height in pixel (screen-) coordinates.

The tricky bit here is that simply applying a blended transform does not work, because the y position needs to be in a different coordinate system than the height of the rectangle; in y direction there is no problem, because both, position and width, would be the same coordinate frame.
Three possible options are shown below.

A. Using an offset box

A solution is to create the rectangle and to pack it into a matplotlib.offsetbox.AuxTransformBox. Then applying the blended transform to the AuxTransformBox will affect only width and height.
The AuxTransformBox can then be packed into a matplotlib.offsetbox.AnchoredOffsetbox. This is positionned, similar to a legend, inside a bbox, which is the axes bbox by default. Since the axes is indeed the desired system to be used here, no bbox_to_anchor needs to be specified. Inside of the axes bbox, the lower left corner is chosen as anchor point (loc="lower left").

import matplotlib.pyplot as plt
import matplotlib.offsetbox
import matplotlib.transforms as mtransforms

fig, ax = plt.subplots()

# create rectangle with 
# * lower left corner at (0,0); will later be interpreted as axes coordinates
# * width=1; will later be interpreted in axes coordinates
# * height=20; will later be interpreted as pixel coordinates
rect = plt.Rectangle((0,0), 1,20)

# create transform; axes coordinates along x axis, pixel coordinates along y axis
trans = mtransforms.blended_transform_factory(ax.transAxes, 
                                              mtransforms.IdentityTransform())
# create an offset box from the above transform; the contents will be transformed
# with trans from above
aux = matplotlib.offsetbox.AuxTransformBox(trans)
aux.add_artist(rect)

# create an anchored offsetbox. Its child is the aux box from above,
# its position is the lower left corner of the axes (loc="lower left")
ab = matplotlib.offsetbox.AnchoredOffsetbox("lower left", pad=0, borderpad=0, frameon=False)
ab.set_child(aux)

ax.add_artist(ab)
plt.show()

Now the rectangle stays always attached to the axes, even upon panning/zooming/rescaling.

B. Using a callback

Alternatively, you may use a callback to adjust the height of the rectangle.

i. axes coordinates, update height

Here the rectangle may be defined in axes coordinates, which is useful for the position as well as the width. Then the height might be calculated as 20 pixels divided by the height of the axes in pixels. You might then recalculate the height each time the figure is resized and the height of the axes changes.

import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms

fig, ax = plt.subplots()

height = 20 # pixels
rect = plt.Rectangle((0,0), 1,1, transform=ax.transAxes)
ax.add_patch(rect)

def update_rect(evt=None):
    bbox_pixel = mtransforms.TransformedBbox(ax.get_position(), fig.transFigure)
    rect.set_height(height/bbox_pixel.height)

update_rect()
fig.canvas.mpl_connect("resize_event", update_rect)

plt.show()

ii. Pixel coordinates, update position and width

Equally you may of course define the rectangle in pixel coordinates, and use a callback to set the width and position depending on the actual axes size.

import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms

fig, ax = plt.subplots()

pos = (0,0) #axes coordinates
width = 1   #   -"-
rect = plt.Rectangle((0,0), 20,20, transform=None)
ax.add_patch(rect)

def update_rect(evt=None):
    bbox_pixel = mtransforms.TransformedBbox(ax.get_position(), fig.transFigure)
    print(bbox_pixel.width)
    rect.set_width(bbox_pixel.width*width)
    rect.set_xy((bbox_pixel.x0 + pos[0]*bbox_pixel.width, 
                 bbox_pixel.y0 + pos[1]*bbox_pixel.height))

update_rect()
fig.canvas.mpl_connect("resize_event", update_rect)

plt.show()

C. Creating an inset axes

You might also create an inset axes positionned in the lower left corner which is 100% of the parent axes wide and 20 pixels / figure-dpi tall. Inside that inset you may create a rectangle which fills the complete axes.

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes

fig, ax = plt.subplots()

rect_ax = inset_axes(ax, "100%", 20/fig.dpi, loc="lower left", borderpad=0)
rect_ax.axis("off")

rect=plt.Rectangle((0,0), 1,1, transform=rect_ax.transAxes)
rect_ax.add_patch(rect)

plt.show()

这篇关于matplotlib 中的固定大小矩形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆