【问题标题】:Matplotlib: make objects ignored by axis autoscalingMatplotlib:使对象被轴自动缩放忽略
【发布时间】:2021-06-22 14:08:07
【问题描述】:

是否可以创建一个被 Axes 自动缩放器忽略的绘图对象?

我经常需要添加垂直线,或对绘图区域进行着色以显示所需的数据范围(作为查看器的参考框架),但随后我必须设置轴自动缩放 x/ylimits回到它们之前的位置 - 或将线条/阴影截断到当前轴限制或各种其他 fandangos。

如果这些着色器/垂直线充当绘图上的“背景”对象,被自动缩放器忽略,那么只有我的真实数据会影响自动缩放。

这是一个例子: 这个图是真实世界的数据,我想看看数据是否每天都在期望的范围内。

我想在 -50 nm ≤ Y ≤ +50 nm 的范围内对第 3 轴图进行着色。 我很想从 -50 --> +50nm 添加一个巨大的半透明矩形,但让自动缩放忽略它。 例如。像这样(我在绘图程序中手动添加了红色阴影):

另外,您可以看到我已经使用这样的代码手动添加了垂直线(我真的应该只使用垂直网格线位置...):

ax1.set_ylim(ymin, ymax)
ax1.vlines( self.Dates , color="grey", alpha=0.05, ymin=ax1.get_ylim()[0], ymax=ax1.get_ylim()[1] )

您可以在第 2 和第 3 轴中看到,VLine 将 AutoScaling 向外推,所以现在 VLine 和 Axis 之间存在间隙。目前我需要确定调用fig.tight_layout()ax2/ax3.plot() 的顺序,或者转换为手动设置X-Tick 位置/网格线等-但如果这些VLines 甚至不被视为数据,那就更容易了,所以自动缩放忽略了它们。

是否可以自动缩放“忽略”某些对象?

【问题讨论】:

  • axvlines 怎么样?
  • 这是一个关于如何在自动缩放期间忽略对象的更一般性问题 - 这些图只是随机示例,但我经常在各种项目中遇到这种需求。
  • 在这种情况下,我真的应该用自定义网格线替换vlines,但对矩形没有帮助。我想知道是否有办法让自动缩放器忽略某些对象(尤其是待处理的矩形)。
  • 我无法重现:如果我在创建 vlines 之前使用 ax.set_ylim(ymin, ymax),则绘图限制不会改变。
  • 也许阻止艺术家影响限制的一种方法是将他们的sticky_edges x 和 y 数组设置为不会影响自动缩放的东西? matplotlib.org/stable/api/_as_gen/…

标签: python matplotlib plot scale axes


【解决方案1】:

autoscale_view 主要使用轴的dataLim 属性来计算轴限制。反过来,数据限制由轴方法设置,例如 _update_image_limits_update_line_limits_update_patch_limits。这些方法都使用这些艺术家的基本属性来计算新的数据限制(例如路径),因此为“背景”艺术家覆盖它们是行不通的。所以不,严格来说,我认为自动缩放不可能忽略某些对象,只要它们是可见的。

但是,除了目前提到的之外,还有其他选项可以保留数据视图。

使用不影响数据限制的艺术家,例如axhlineaxvline 或使用 add_artist 添加补丁(和派生类)。

#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt

x, y = np.random.randn(2, 1000)

fig, ax = plt.subplots()
ax.scatter(x, y, zorder=2)
ax.add_artist(plt.Rectangle((0,0), 6, 6, alpha=0.1, zorder=1))
ax.axhline(0)
ax.axvline(0)

您可以绘制前景对象,然后关闭自动缩放。

#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt

x, y = np.random.randn(2, 1000)

fig, ax = plt.subplots()
ax.scatter(x, y, zorder=2)
ax.autoscale_view() # force auto-scale to update data limits based on scatter
ax.set_autoscale_on(False)
ax.add_patch(plt.Rectangle((0,0), 6, 6, alpha=0.1, zorder=1))

我唯一的另一个想法是修改Axes.relim() 以检查background 属性(这可能最接近您的想象):

import numpy as np
import matplotlib.axes
import matplotlib.transforms as mtransforms
import matplotlib.image as mimage
import matplotlib.lines as mlines
import matplotlib.patches as mpatches

class PatchedAxis(matplotlib.axes.Axes):
    def relim(self, visible_only=False):
        """
        Recompute the data limits based on current artists.
        At present, `.Collection` instances are not supported.
        Parameters
        ----------
        visible_only : bool, default: False
            Whether to exclude invisible artists.
        """
        # Collections are deliberately not supported (yet); see
        # the TODO note in artists.py.
        self.dataLim.ignore(True)
        self.dataLim.set_points(mtransforms.Bbox.null().get_points())
        self.ignore_existing_data_limits = True

        for artist in self._children:
            if not visible_only or artist.get_visible():
                if not hasattr(artist, "background"):
                    if isinstance(artist, mlines.Line2D):
                        self._update_line_limits(artist)
                    elif isinstance(artist, mpatches.Patch):
                        self._update_patch_limits(artist)
                    elif isinstance(artist, mimage.AxesImage):
                        self._update_image_limits(artist)

matplotlib.axes.Axes = PatchedAxis

import matplotlib.pyplot as plt

x, y = np.random.randn(2, 1000)

fig, ax = plt.subplots()
ax.scatter(x, y, zorder=2)
rect = plt.Rectangle((0,0), 6, 6, alpha=0.1, zorder=1)
rect.background = True
ax.add_patch(rect)
ax.relim()
ax.autoscale_view()

但是,由于某种原因,在调用 relim 时未填充 ax._children。也许其他人可以弄清楚ax._children属性是在什么条件下创建的。

【讨论】:

  • 谢谢你,add_artist() 完全符合我的要求。结合this hint 在 MPL 轴上绘制一个 Rectangle,效果很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 1970-01-01
  • 2012-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多