Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matplotlib 如何重写mpl_toolkits.mplot3d.Axes3D.draw()方法?_Matplotlib_Overriding_Z Order - Fatal编程技术网

Matplotlib 如何重写mpl_toolkits.mplot3d.Axes3D.draw()方法?

Matplotlib 如何重写mpl_toolkits.mplot3d.Axes3D.draw()方法?,matplotlib,overriding,z-order,Matplotlib,Overriding,Z Order,我正在做一个小项目,需要解决matplotlib中的一个bug,以便修复一些ax.patches和ax.collections的zorder。更确切地说,ax.patches是可在空间中旋转的符号,ax.collections是ax.voxels的侧面(因此必须在其上放置文本)。到目前为止,我知道在mpl_工具包的draw方法中隐藏了一个bug。mplot3d.Axes3D:zorder每次我以不希望的方式移动图表时都会重新计算。因此,我决定在以下几行中更改draw方法的定义: for

我正在做一个小项目,需要解决
matplotlib
中的一个bug,以便修复一些
ax.patches
ax.collections
的zorder。更确切地说,
ax.patches
是可在空间中旋转的符号,
ax.collections
ax.voxels
的侧面(因此必须在其上放置文本)。到目前为止,我知道在
mpl_工具包的
draw
方法中隐藏了一个bug。mplot3d.Axes3D
zorder
每次我以不希望的方式移动图表时都会重新计算。因此,我决定在以下几行中更改
draw
方法的定义:

    for i, col in enumerate(
            sorted(self.collections,
                   key=lambda col: col.do_3d_projection(renderer),
                   reverse=True)):
        #col.zorder = zorder_offset + i #comment this line
        col.zorder = col.stable_zorder + i #add this extra line
    for i, patch in enumerate(
            sorted(self.patches,
                   key=lambda patch: patch.do_3d_projection(renderer),
                   reverse=True)):
        #patch.zorder = zorder_offset + i #comment this line
        patch.zorder = patch.stable_zorder + i #add this extra line
假设
ax.collection
ax.patch
的每个对象都有一个
stable\u属性,该属性在我的项目中手动分配。所以每次我运行我的项目时,我必须确保手动更改
mpl_toolkits.mplot3d.Axes3D.draw
方法(在我的项目之外)。如何在我的项目中避免此更改并以任何方式重写此方法

这是我的项目的MWE:

import matplotlib.pyplot as plt
import numpy as np
#from mpl_toolkits.mplot3d import Axes3D
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.text import TextPath
from matplotlib.transforms import Affine2D
from matplotlib.patches import PathPatch

class VisualArray:
    def __init__(self, arr, fig=None, ax=None):
        if len(arr.shape) == 1:
            arr = arr[None,None,:]
        elif len(arr.shape) == 2:
            arr = arr[None,:,:]
        elif len(arr.shape) > 3:
            raise NotImplementedError('More than 3 dimensions is not supported')
        self.arr = arr
        if fig is None:
            self.fig = plt.figure()
        else:
            self.fig = fig
        if ax is None:
            self.ax = self.fig.gca(projection='3d')
        else:
            self.ax = ax
        self.ax.azim, self.ax.elev = -120, 30
        self.colors = None

    def text3d(self, xyz, s, zdir="z", zorder=1, size=None, angle=0, usetex=False, **kwargs):
        d = {'-x': np.array([[-1.0, 0.0, 0], [0.0, 1.0, 0.0], [0, 0.0, -1]]),
             '-y': np.array([[0.0, 1.0, 0], [-1.0, 0.0, 0.0], [0, 0.0, 1]]),
             '-z': np.array([[1.0, 0.0, 0], [0.0, -1.0, 0.0], [0, 0.0, -1]])}

        x, y, z = xyz
        if "y" in zdir:
            x, y, z = x, z, y
        elif "x" in zdir:
            x, y, z = y, z, x
        elif "z" in zdir:
            x, y, z = x, y, z

        text_path = TextPath((-0.5, -0.5), s, size=size, usetex=usetex)
        aff = Affine2D()
        trans = aff.rotate(angle)

        # apply additional rotation of text_paths if side is dark
        if '-' in zdir:
            trans._mtx = np.dot(d[zdir], trans._mtx)
        trans = trans.translate(x, y)
        p = PathPatch(trans.transform_path(text_path), **kwargs)
        self.ax.add_patch(p)
        art3d.pathpatch_2d_to_3d(p, z=z, zdir=zdir)
        p.stable_zorder = zorder
        return p

    def on_rotation(self, event):
        vrot_idx = [self.ax.elev > 0, True].index(True)
        v_zorders = 10000 * np.array([(1, -1), (-1, 1)])[vrot_idx]
        for side, zorder in zip((self.side1, self.side4), v_zorders):
            for patch in side:
                patch.stable_zorder = zorder

        hrot_idx = [self.ax.azim < -90, self.ax.azim < 0, self.ax.azim < 90, True].index(True)
        h_zorders = 10000 * np.array([(1, 1, -1, -1), (-1, 1, 1, -1),
                              (-1, -1, 1, 1), (1, -1, -1, 1)])[hrot_idx]
        sides = (self.side3, self.side2, self.side6, self.side5)
        for side, zorder in zip(sides, h_zorders):
            for patch in side:
                patch.stable_zorder = zorder

    def voxelize(self):
        shape = self.arr.shape[::-1]
        x, y, z = np.indices(shape)
        arr = (x < shape[0]) & (y < shape[1]) & (z < shape[2])
        self.ax.voxels(arr, facecolors=self.colors, edgecolor='k')
        for col in self.ax.collections:
            col.stable_zorder = col.zorder

    def labelize(self):
        self.fig.canvas.mpl_connect('motion_notify_event', self.on_rotation)
        s = self.arr.shape
        self.side1, self.side2, self.side3, self.side4, self.side5, self.side6 = [], [], [], [], [], []
        # labelling surfaces of side1 and side4
        surf = np.indices((s[2], s[1])).T[::-1].reshape(-1, 2) + 0.5
        surf_pos1 = np.insert(surf, 2, self.arr.shape[0], axis=1)
        surf_pos2 = np.insert(surf, 2, 0, axis=1)
        labels1 = (self.arr[0]).flatten()
        labels2 = (self.arr[-1]).flatten()
        for xyz, label in zip(surf_pos1, [f'${n}$' for n in labels1]):
            t = self.text3d(xyz, label, zdir="z", zorder=10000, size=1, usetex=True, ec="none", fc="k")
            self.side1.append(t)
        for xyz, label in zip(surf_pos2, [f'${n}$' for n in labels2]):
            t = self.text3d(xyz, label, zdir="-z", zorder=-10000, size=1, usetex=True, ec="none", fc="k")
            self.side4.append(t)

        # labelling surfaces of side2 and side5
        surf = np.indices((s[2], s[0])).T[::-1].reshape(-1, 2) + 0.5
        surf_pos1 = np.insert(surf, 1, 0, axis=1)
        surf = np.indices((s[0], s[2])).T[::-1].reshape(-1, 2) + 0.5
        surf_pos2 = np.insert(surf, 1, self.arr.shape[1], axis=1)
        labels1 = (self.arr[:, -1]).flatten()
        labels2 = (self.arr[::-1, 0].T[::-1]).flatten()
        for xyz, label in zip(surf_pos1, [f'${n}$' for n in labels1]):
            t = self.text3d(xyz, label, zdir="y", zorder=10000, size=1, usetex=True, ec="none", fc="k")
            self.side2.append(t)
        for xyz, label in zip(surf_pos2, [f'${n}$' for n in labels2]):
            t = self.text3d(xyz, label, zdir="-y", zorder=-10000, size=1, usetex=True, ec="none", fc="k")
            self.side5.append(t)

        # labelling surfaces of side3 and side6
        surf = np.indices((s[1], s[0])).T[::-1].reshape(-1, 2) + 0.5
        surf_pos1 = np.insert(surf, 0, self.arr.shape[2], axis=1)
        surf_pos2 = np.insert(surf, 0, 0, axis=1)
        labels1 = (self.arr[:, ::-1, -1]).flatten()
        labels2 = (self.arr[:, ::-1, 0]).flatten()
        for xyz, label in zip(surf_pos1, [f'${n}$' for n in labels1]):
            t = self.text3d(xyz, label, zdir="x", zorder=-10000, size=1, usetex=True, ec="none", fc="k")
            self.side6.append(t)
        for xyz, label in zip(surf_pos2, [f'${n}$' for n in labels2]):
            t = self.text3d(xyz, label, zdir="-x", zorder=10000, size=1, usetex=True, ec="none", fc="k")
            self.side3.append(t)

    def vizualize(self):
        self.voxelize()
        self.labelize()
        plt.axis('off')

arr = np.arange(60).reshape((2,6,5))
va = VisualArray(arr)
va.vizualize()
plt.show()
导入matplotlib.pyplot作为plt
将numpy作为np导入
#从mpl_toolkits.mplot3d导入Axes3D
将mpl_toolkits.mplot3d.art3d导入为art3d
从matplotlib.text导入文本路径
从matplotlib.transforms导入仿射2D
从matplotlib.patches导入PathPatch
类VisualArray:
定义初始化(self,arr,fig=None,ax=None):
如果len(arr.shape)==1:
arr=arr[None,None,:]
elif len(arr.shape)==2:
arr=arr[None,:,:]
elif透镜(棱角形状)>3:
raise NOTEImplementedError('不支持超过3个维度')
self.arr=arr
如果fig为无:
self.fig=plt.figure()
其他:
self.fig=fig
如果ax为无:
self.ax=self.fig.gca(投影='3d')
其他:
self.ax=ax
self.ax.azim,self.ax.elev=-120,30
self.colors=无
def text3d(self,xyz,s,zdir=“z”,zorder=1,size=None,angle=0,usetex=False,**kwargs):
d={'-x':np.array([[-1.0,0.0,0],[0.0,1.0,0.0],[0,0.0,1]]),
“-y”:np.array([[0.0,1.0,0],-1.0,0.0,0.0],[0,0.0,1]]),
“-z”:np.array([[1.0,0.0,0],[0.0,-1.0,0.0],[0,0.0,-1]])的缩写
x、 y,z=xyz
如果zdir中的“y”:
x、 y,z=x,z,y
zdir中的elif“x”:
x、 y,z=y,z,x
zdir中的elif“z”:
x、 y,z=x,y,z
text_path=TextPath(-0.5,-0.5),s,size=size,usetex=usetex)
aff=Affine2D()
变速器=完成旋转(角度)
#如果边为黑色,则应用文本路径的附加旋转
如果zdir中的“-”为:
trans.\u mtx=np.dot(d[zdir],trans.\u mtx)
trans=trans.translate(x,y)
p=路径补丁(转换路径(文本路径),**kwargs)
self.ax.add_补丁(p)
art3d.pathpatch_2d_到_3d(p,z=z,zdir=zdir)
p、 稳定的_zorder=zorder
返回p
def on_旋转(自身、事件):
vrot_idx=[self.ax.elev>0,True]。索引(True)
v_zorders=10000*np.数组([(1,-1),(-1,1)])[vrot_idx]
对于侧边,zorder在zip中((self.side1,self.side4),v_zorders):
对于侧边中的修补程序:
patch.stable_zorder=zorder
hrot_idx=[self.ax.azim<-90,self.ax.azim<0,self.ax.azim<90,真]。索引(真)
h_zorders=10000*np.数组([(1,1,-1,-1),(-1,1,1,-1),
(-1,-1,1,1),(1,-1,-1,1)][hrot_idx]
边=(self.side3、self.side2、self.side6、self.side5)
对于侧边,拉链中的zorder(侧边,h_zorder):
对于侧边中的修补程序:
patch.stable_zorder=zorder
def体素化(自):
shape=self.arr.shape[:-1]
x、 y,z=np.指数(形状)
arr=(xfrom matplotlib import artist
from mpl_toolkits.mplot3d import Axes3D

# Create a new draw function
@artist.allow_rasterization
def draw(self, renderer):
    # Your version
    # ...

    # Add Axes3D explicitly to super() calls
    super(Axes3D, self).draw(renderer)

# Overwrite the old draw function
Axes3D.draw = draw

# The rest of your code
# ...