matplotlib Axes3D 中的 mayavi 3d 对象

2024-01-09

有时我发现自己对 matplotlib 的 mplot3d 中缺少某些渲染功能感到沮丧。在大多数情况下,我确实发现我可以在 mayavi 中得到我想要的东西,但如果只是为了美观,比如 LaTeX 化的标签以及与我的其他图形的视觉一致性,那么 matplotlib 3d 轴仍然更可取。

我的问题是关于明显的黑客:是否可以在没有轴的mayavi中绘制一些3d对象(表面或3d散点图或其他),导出该图像,然后将其放置在正确大小,方向,坐标的matplotlib Axes3D中投影等?谁能想出实现这一目标需要什么的概要,或者甚至提供一个框架解决方案?

我前段时间摆弄过这个,发现导出透明背景 Mayavi 图形并将其放置在空的 matplotlib Axes3D (带有刻度、标签等)中没有遇到任何问题,但我并没有取得多大进展要匹配的 mayavi 和 matplotlib 的相机配置。简单地在两种环境中设置相同的方位角、仰角和距离这三个常见参数并不能解决问题。想必需要考虑渲染整个场景的透视(或其他)变换,而我在该领域相当无能。

看起来这可能有用:http://docs.enthought.com/mayavi/mayavi/auto/example_mlab_3D_to_2D.html http://docs.enthought.com/mayavi/mayavi/auto/example_mlab_3D_to_2D.html


我使用 Mayavi -> PGFPlots 制作了一个概念验证解决方案mlab_3D_to_2D.py example https://docs.enthought.com/mayavi/mayavi/auto/example_mlab_3D_to_2D.html以及 PGFPlots 手册的“对外部三维图形的支持”部分。

程序:

  1. 运行修改后的mlab_3D_to_2D.py使用 Mayavi 生成img.png。四个随机点打印到控制台,将它们复制到剪贴板。请注意,图形尺寸和分辨率被硬编码到脚本中,应针对不同的图像尺寸对其进行编辑或自动提取。
  2. 将点粘贴到mlab_pgf.tex.
  3. 运行 LaTeXmlab_pgf.tex.

Result:

修改的mlab_3D_to_2D.py:

# Modified mlab_3D_to_2D.py from https://docs.enthought.com/mayavi/mayavi/auto/example_mlab_3D_to_2D.html

# Original copyright notice:
# Author: S. Chris Colbert <[email protected] /cdn-cgi/l/email-protection>
# Copyright (c) 2009, S. Chris Colbert
# License: BSD Style

from __future__ import print_function

# this import is here because we need to ensure that matplotlib uses the
# wx backend and having regular code outside the main block is PyTaboo.
# It needs to be imported first, so that matplotlib can impose the
# version of Wx it requires.
import matplotlib
# matplotlib.use('WXAgg')
import pylab as pl


import numpy as np
from mayavi import mlab
from mayavi.core.ui.mayavi_scene import MayaviScene

def get_world_to_view_matrix(mlab_scene):
    """returns the 4x4 matrix that is a concatenation of the modelview transform and
    perspective transform. Takes as input an mlab scene object."""

    if not isinstance(mlab_scene, MayaviScene):
        raise TypeError('argument must be an instance of MayaviScene')


    # The VTK method needs the aspect ratio and near and far clipping planes
    # in order to return the proper transform. So we query the current scene
    # object to get the parameters we need.
    scene_size = tuple(mlab_scene.get_size())
    clip_range = mlab_scene.camera.clipping_range
    aspect_ratio = float(scene_size[0])/float(scene_size[1])

    # this actually just gets a vtk matrix object, we can't really do anything with it yet
    vtk_comb_trans_mat = mlab_scene.camera.get_composite_projection_transform_matrix(
                                aspect_ratio, clip_range[0], clip_range[1])

     # get the vtk mat as a numpy array
    np_comb_trans_mat = vtk_comb_trans_mat.to_array()

    return np_comb_trans_mat


def get_view_to_display_matrix(mlab_scene):
    """ this function returns a 4x4 matrix that will convert normalized
        view coordinates to display coordinates. It's assumed that the view should
        take up the entire window and that the origin of the window is in the
        upper left corner"""

    if not (isinstance(mlab_scene, MayaviScene)):
        raise TypeError('argument must be an instance of MayaviScene')

    # this gets the client size of the window
    x, y = tuple(mlab_scene.get_size())

    # normalized view coordinates have the origin in the middle of the space
    # so we need to scale by width and height of the display window and shift
    # by half width and half height. The matrix accomplishes that.
    view_to_disp_mat = np.array([[x/2.0,      0.,   0.,   x/2.0],
                                 [   0.,  -y/2.0,   0.,   y/2.0],
                                 [   0.,      0.,   1.,      0.],
                                 [   0.,      0.,   0.,      1.]])

    return view_to_disp_mat


def apply_transform_to_points(points, trans_mat):
    """a function that applies a 4x4 transformation matrix to an of
        homogeneous points. The array of points should have shape Nx4"""

    if not trans_mat.shape == (4, 4):
        raise ValueError('transform matrix must be 4x4')

    if not points.shape[1] == 4:
        raise ValueError('point array must have shape Nx4')

    return np.dot(trans_mat, points.T).T

def test_surf():
    """Test surf on regularly spaced co-ordinates like MayaVi."""
    def f(x, y):
        sin, cos = np.sin, np.cos
        return sin(x + y) + sin(2 * x - y) + cos(3 * x + 4 * y)

    x, y = np.mgrid[-7.:7.05:0.1, -5.:5.05:0.05]
    z = f(x, y)
    s = mlab.surf(x, y, z)
    #cs = contour_surf(x, y, f, contour_z=0)
    return x, y, z, s

if __name__ == '__main__':
    f = mlab.figure()
    f.scene.parallel_projection = True

    N = 4

    # x, y, z, m = test_mesh()
    x, y, z, s = test_surf()

    mlab.move(forward=2.0)

    # now were going to create a single N x 4 array of our points
    # adding a fourth column of ones expresses the world points in
    # homogenous coordinates
    W = np.ones(x.flatten().shape)
    hmgns_world_coords = np.column_stack((x.flatten(), y.flatten(), z.flatten(), W))

    # applying the first transform will give us 'unnormalized' view
    # coordinates we also have to get the transform matrix for the
    # current scene view
    comb_trans_mat = get_world_to_view_matrix(f.scene)
    view_coords = \
            apply_transform_to_points(hmgns_world_coords, comb_trans_mat)

    # to get normalized view coordinates, we divide through by the fourth
    # element
    norm_view_coords = view_coords / (view_coords[:, 3].reshape(-1, 1))

    # the last step is to transform from normalized view coordinates to
    # display coordinates.
    view_to_disp_mat = get_view_to_display_matrix(f.scene)
    disp_coords = apply_transform_to_points(norm_view_coords, view_to_disp_mat)

    # at this point disp_coords is an Nx4 array of homogenous coordinates
    # where X and Y are the pixel coordinates of the X and Y 3D world
    # coordinates, so lets take a screenshot of mlab view and open it
    # with matplotlib so we can check the accuracy
    img = mlab.screenshot(figure=f, mode='rgba', antialiased=True)
    pl.imsave("img.png", img)
    pl.imshow(img)
    # mlab.close(f)

    idx = np.random.choice(range(disp_coords[:, 0:2].shape[0]), N, replace=False)

    for i in idx:
        # print('Point %d:  (x, y) ' % i, disp_coords[:, 0:2][i], hmgns_world_coords[:, 0:3][i])
        a = hmgns_world_coords[:, 0:3][i]
        a = str(list(a)).replace('[', '(').replace(']', ')').replace('  ',',')
        # See note below about 298.
        b = np.array([0, 298]) - disp_coords[:, 0:2][i]
        b = b * np.array([-1, 1])
        # Important! These values are not constant.
        # The image is 400 x 298 pixels, or 288 x 214.6 pt.
        b[0] = b[0] / 400 * 288
        b[1] = b[1] / 298 * 214.6
        b = str(list(b)).replace('[', '(').replace(']', ')').replace('  ',',')
        print(a, "=>", b)
        pl.plot([disp_coords[:, 0][i]], [disp_coords[:, 1][i]], 'ro')

    pl.show()

    # you should check that the printed coordinates correspond to the
    # proper points on the screen

    mlab.show()

#EOF

mlab_pgf.py:

\documentclass{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=1.17}

\begin{document}

\begin{tikzpicture}
\begin{axis}[
  grid=both,minor tick num=1,
  xlabel=$x$,ylabel=$y$,zlabel=$z$,
  xmin=-7,
  xmax=7,
  ymin=-5,
  ymax=5,
  zmin=-3,
  zmax=3,
  ]
  \addplot3 graphics [
  points={% important, paste points generated by `mlab_3D_to_2D.py`
    (5.100000000000001, -3.8, 2.9491697063900895) => (69.82857610254948, 129.60245304203693)
    (-6.2, -3.0999999999999996, 0.6658335107904079) => (169.834990346303, 158.6375879061911)
    (-1.7999999999999998, 0.4500000000000002, -1.0839565197346115) => (162.75120267070378, 103.53696636434113)
    (-5.3, -4.9, 0.6627774166307937) => (147.33354714145847, 162.93938533017257)
  },
  ] {img.png};
\end{axis}
\end{tikzpicture}

\end{document}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

matplotlib Axes3D 中的 mayavi 3d 对象 的相关文章

随机推荐

  • 用于包装采用 void* 参数的 C 回调的模板魔术?

    假设我正在使用 C API 它可以让您注册回调函数void 关闭 void register callback void func void void closure 在 C 中 拥有比void 所以我想创建一个包装器 让我注册强类型的 C
  • 将 zlib 过滤器与套接字对一起使用

    由于某种原因 zlib deflate过滤器似乎不适用于由生成的套接字对stream socket pair 从第二个套接字中可以读取的只是双字节 zlib 标头 之后的所有内容均为 NULL Example
  • 致命错误:调用未定义的方法 mysqli::error() [重复]

    这个问题在这里已经有答案了 我可以连接 但是当涉及到准备好的语句时 这就是我得到的错误 有什么问题吗 代码 Open connection db new mysqli DB HOST DB USER DB PASSWORD DB DATAB
  • 在 Swift 中将 CGFloat 转换为字符串

    这是我目前在 Swift 中将 CGFloat 转换为 String 的方法 let x Float Float CGFloat let y Int Int x let z String String y 有没有更有效的方法来做到这一点 您
  • 如何将数据库的结果显示到输入区域?

    正如您在我的 php 代码中看到的 我尝试通过 值 将数据库的结果回显到输入区域 但是这不断出现语法错误 有人可以
  • 如何防止在堆上创建对象?

    有谁知道如何在独立于平台的 C 代码中阻止在堆上创建对象 也就是说 对于 Foo 类 我想阻止用户这样做 Foo ptr new Foo 并且只允许他们这样做 Foo myfooObject 有人有什么想法吗 Cheers 尼克的回答 ht
  • 使用 Haskell 播放 wav 文件

    有没有一种简单 直接的方法可以使用某些库从 Haskell 播放 WAV 文件 并且可能使我可以一次播放许多声音 我知道 OpenAL 但我不是在编写一些高级音频合成程序 我只是想播放一些声音来进行一些小游戏 理想情况下 API 可能类似于
  • 如何使用 NX/Nrwl 为 Angular 创建应用程序特定配置?

    所以我有以下项目结构 apps car libs app car shared config 对于每个应用程序 我想提供不同的配置 可以在分组库中使用 export interface DefaultAppConfig language s
  • 如何让按钮看起来就像被按下一样?

    使用 VS2008 C Net 2 和 Winforms 如何使常规按钮看起来 按下 想象一下这个按钮是一个开 关开关 ToolStripButton有 Checked 属性 但常规 Button 没有 您可以用来获取此选项的一种方法是放置
  • ListFragment 的 FragmentPagerAdapter getItem 错误

    我看了很多代码 但无法弄清楚这一点 http developer android com reference android support v4 app FragmentPagerAdapter html http developer a
  • Hibernate 实体有一个通用基类吗?

    Hibernate 实体是否有一个通用基类 即具有 id 版本和其他通用属性的 MappedSuperclass 有什么缺点吗 Example MappedSuperclass public class BaseEntity private
  • 递归解析关联数组时如何检查 PHP 中的循环引用?

    我用循环引用创建了这个数组 arr array 1 gt one 2 gt two arr 3 arr 我有一个函数可以递归地打印出数组中的值 但我确实无法解决创建循环引用检查的问题 你怎么能这么做呢 我用于打印数组的当前函数复制如下 我没
  • 这个JSON的数据结构是怎样的?

    我试图使用 Gson 将 Json 解析为 Java 但是当我使用 fromJson 时 我总是得到 null 谁能帮我解释一下这个数据结构 谢谢 d results metadata uri https api datamarket az
  • 有没有办法用 Java 下载 Microsoft Azure 数据中心 IP 范围?

    我的问题类似于有没有办法以编程方式自动下载 Microsoft Azure 使用的最新 IP 范围 https stackoverflow com questions 28798014 ms azure automatically down
  • Tesseract 虚假空间识别

    我正在使用 tesseract 来识别序列号 这是可以接受的 存在常见问题 例如错误识别零和 O 6 和 5 或 M 和 H 除此之外 这个超正方体还向识别的单词添加了空格 而图像中没有空格 下图被识别为 HI 3H 这张图片的结果是 FB
  • opencv clahe参数解释

    我想知道 clahe 参数的正确解释i e clipLimit and tileGridSize 以及如何clipLimit值会影响图像的对比度以及选择时要考虑的因素 例如图像分辨率 物体尺寸 tileGridSize 提前致谢 这个问题是
  • MFMailComposeViewController 错误 [MC] 过滤邮件表帐户的捆绑包 ID

    我使用发送消息的标准功能MFMailComposeViewController My code if MFMailComposeViewController canSendMail let mail MFMailComposeViewCon
  • 在 GoDaddy 上安装 django 网站 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我以前从未部署过 Django 网站 我目前正在寻找在我的豪华 GoDaddy 帐户中进行设置 有人有
  • Rails - 删除满足条件的所有记录

    你如何以 Rails 方式编写 我有一个模型 经理 我想从 Managers 中删除满足 manager level 为 5 条件的所有记录 谢谢 我认为最好使用destroy而不是delete 因为 destroy 将从数据库中删除当前对
  • matplotlib Axes3D 中的 mayavi 3d 对象

    有时我发现自己对 matplotlib 的 mplot3d 中缺少某些渲染功能感到沮丧 在大多数情况下 我确实发现我可以在 mayavi 中得到我想要的东西 但如果只是为了美观 比如 LaTeX 化的标签以及与我的其他图形的视觉一致性 那么