微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何安全地修补 matplotlib 的轴不影响将来的调用?

如何解决如何安全地修补 matplotlib 的轴不影响将来的调用?

我有一个使用 bar3d 可视化矩阵元素的函数I was trying to remove margins at the bounding limits 的 z 轴。我发现this answer(第一个)使用猴子补丁。所以我的代码看起来像这样:

from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.axis3d import Axis

# function which applies monkey patching
def _remove_margins():
    """
    Removes margins about z=0 and improves the style
    """
    if not hasattr(Axis,"_get_coord_info_old"):
        def _get_coord_info_new(self,renderer):
            mins,maxs,centers,deltas,tc,highs = \
                self._get_coord_info_old(renderer)
            mins += deltas/4
            maxs -= deltas/4
            return mins,highs
        Axis._get_coord_info_old = Axis._get_coord_info
        Axis._get_coord_info = _get_coord_info_new


# function which visualizes the matrix
# ✅ this function should be affected by monkey patching
def visualize_matrix(M,figsize,... ):
    _remove_margins()
    
    fig = plt.figure(figsize=figsize)
    ax  = Axes3D(fig)
    ax.bar3d(...)
    .
    .
    .
    return fig,ax

# another function that uses Axes3D
# ⛔️ this function should not be affected by monkey patching
def visualize_sphere(...):
    fig = plt.figure(figsize=figsize)
    ax  = Axes3D(fig)
    .
    .
    .
    return fig,ax

问题:

在未来的 Axes3D 调用中(例如使用 visualize_sphere 函数),monkey patching 所做的更改仍然存在。

问题:

如何通过猴子补丁安全解决问题?

解决方法

我更改了猴子补丁以仅更改实例,而不是类。 创建 patch_axis 后,将 ax.xaxis 应用于 ax.yaxisax.zaxisax

import matplotlib.pyplot as plt
import numpy as np


def patch_axis(axis):
    def _get_coord_info_new(renderer):
        mins,maxs,centers,deltas,tc,highs = _get_coord_info_old(renderer)
        mins += deltas / 4
        maxs -= deltas / 4
        return mins,highs

    _get_coord_info_old = axis._get_coord_info
    axis._get_coord_info = _get_coord_info_new


def test():
    fig = plt.figure()
    ax = fig.add_subplot(111,projection='3d')
    ax.margins(0)
    for c,z in zip(['r','g','b','y'],[30,20,10,0]):
        xs = np.arange(20)
        ys = np.random.rand(20)

        # You can provide either a single color or an array. To demonstrate this,# the first bar of each set will be colored cyan.
        cs = [c] * len(xs)
        cs[0] = 'c'
        ax.bar(xs,ys,zs=z,zdir='y',color=cs,alpha=0.8)

    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')

    return fig,ax

# without the margin
fig,ax = test()
patch_axis(ax.xaxis)
patch_axis(ax.yaxis)
patch_axis(ax.zaxis)
fig.savefig("test1.png")

# with the margin
fig,ax = test()
fig.savefig("test2.png")

方法只是在类的命名空间中定义的函数,实例化隐式地填充自参数。您可以通过在实例化添加的命名空间中分配不带自参数的函数来替换 bound method

>>> class C:
...     def f(self): return 1
... 
>>> C.f
<function C.f at 0x7f36a7eb53a0>
>>> c = C()
>>> c.f
<bound method C.f of <__main__.C object at 0x7f36a7f48eb0>>
>>> c.f()
1
>>> c.f = lambda: 2
>>> c.f()
2

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。