Pyvista 曲面图?
Pyvista surface plot?
我需要一种使用数百万个数据点制作 3 维曲面图的方法,因此我开始查看 pyvista,它应该可以很好地完成这项工作。
不过pyvista对我来说有点难掌握。
我有 x,y,z 数据,其中 x 是时间,y 是不同的测量值,z 是这些测量值。
我只想让 pyvista 向我显示包含此信息的曲面图。
例如,如果我在 matplotlib 或其他带有曲面图的库中使用此数组:
X = np.array([1,2,3,4,5,6,7,8,9])
Y = np.array([1,2,3,4,5,6,7,8,9])
X, Y = np.meshgrid(X, Y)
Z = X*Y
我得到这个输出:
但是如果我在任何 pyvista 图上使用相同的数据,我会得到这样的结果:
import sys
# Setting the Qt bindings for QtPy
import os
os.environ["QT_API"] = "pyqt5"
from qtpy import QtWidgets
from qtpy.QtWidgets import QMainWindow
import numpy as np
import pyvista as pv
from pyvistaqt import QtInteractor
import pandas as pd
class MainWindow(QMainWindow):
def __init__(self, parent=None, show=True):
QtWidgets.QMainWindow.__init__(self, parent)
# create the frame
self.frame = QtWidgets.QFrame()
vlayout = QtWidgets.QVBoxLayout()
# add the pyvista interactor object
self.plotter = QtInteractor(self.frame)
vlayout.addWidget(self.plotter.interactor)
self.frame.setLayout(vlayout)
self.setCentralWidget(self.frame)
# simple menu to demo functions
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('File')
exitButton = QtWidgets.QAction('Exit', self)
exitButton.setShortcut('Ctrl+Q')
exitButton.triggered.connect(self.close)
fileMenu.addAction(exitButton)
# allow adding a sphere
meshMenu = mainMenu.addMenu('Mesh')
self.add_sphere_action = QtWidgets.QAction('Add Sphere', self)
self.add_sphere_action.triggered.connect(self.add_sphere)
meshMenu.addAction(self.add_sphere_action)
x = np.array([9,8,7,6,5,4,3,2,1])
y = np.array([9,8,7,6,5,4,3,2,1])
x, y = np.meshgrid(x, y)
z = x*y
# z[z < -10] = np.nan # get rid of missing data. pyvista needs you to do this
i_res = 2 # display every nth point
j_res = 2 # display every nth point
self.grid = pv.StructuredGrid(x[::i_res, ::j_res], y[::i_res, ::j_res], z[::i_res, ::j_res])
self.z = z
self.x = x
self.y = y
self.plotter.add_mesh(self.grid, scalars=self.grid.points[:, 2], lighting=True, specular=0.5, smooth_shading=True,
show_scalar_bar=True)
if show:
self.show()
def add_sphere(self): #changing resolution, not adding a sphere
i_res = 5 # display every nth point
j_res = 5 # display every nth point
self.grid = pv.StructuredGrid(self.x[::i_res, ::j_res], self.y[::i_res, ::j_res], self.z[::i_res, ::j_res])
self.plotter.update()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
import pyvista as pv
import numpy as np
# Define a simple Gaussian surface
x = np.array([1,2,3,4,5,6,7,8,9])
y = np.array([1,2,3,4,5,6,7,8,9])
x, y = np.meshgrid(x, y)
z = x*y
# Get the points as a 2D NumPy array (N by 3)
points = np.c_[x.reshape(-1), y.reshape(-1), z.reshape(-1)]
points[0:5, :]
# simply pass the numpy points to the PolyData constructor
cloud = pv.PolyData(points)
cloud.plot(point_size=15)
我使用这段代码设法得到了一些不同的东西:
import pandas as pd
import pyvista as pv
import numpy as np
# Load Excel sheet using Pandas
# Note - you may need to `pip install xlrd`
# x = np.array([1,2,3,4,5,6,7,8,9])
# y = np.array([1,2,3,4,5,6,7,8,9])
x = np.array([[1],[2],[3],[4],[5],[6],[7],[8],[9]])
y = np.array([[1],[2],[3],[4],[5],[6],[7],[8],[9]])
# # x, y = np.meshgrid(x, y)
z = x*y
coords = np.hstack((x,y,z))
# Make the structured surface manually
structured = pv.StructuredGrid()
# Set coordinates
structured.points = coords
# Set the dimensions of the structured grid
structured.dimensions = [1, 1, 9]
# Apply an Elevation filter
elevation = structured.elevation()
elevation.plot(show_edges=True, show_grid=True, notebook=False)
但它只提供一串数据。我无法让其他任何东西正常工作。
有谁知道为什么 x、y、z 数据在 pyvista 中做奇怪的事情以及我如何只提供一个正常的曲面图?非常感谢,因为我很困惑。
你的第一个版本是正确的。
PyVista 拥有出色的文档,其中一部分是大量示例。您需要名为 Creating a Structured Surface 的那个。这最终与您最初展示的代码几乎相同:
import pyvista as pv
import numpy as np
# Define a simple linear surface
x = np.array([1,2,3,4,5,6,7,8,9])
y = np.array([1,2,3,4,5,6,7,8,9])
x, y = np.meshgrid(x, y)
z = x*y
# Create and plot structured grid
grid = pv.StructuredGrid(x, y, z)
plotter = pv.Plotter()
plotter.add_mesh(grid, scalars=grid.points[:, -1], show_edges=True,
scalar_bar_args={'vertical': True})
plotter.show_grid()
plotter.show()
这是(正确的!)输出:
这看起来不同的原因是 matplotlib 不是 3d 可视化工具(事实上,它的 3d 工具臭名昭著地使用 2d 渲染器导致奇怪的怪癖)。另一方面,PyVista 旨在可视化空间参考数据。如果您的 x
从 1 变为 9 而您的 z
从 1 变为 81 那么为什么它会挤压 z
轴?如果您沿每个坐标轴设置 1:1:1 纵横比,PyVista 显示的就是事实。
如果您不想要这个,您可以自行缩放:
import pyvista as pv
import numpy as np
# Define a simple linear surface
x = np.array([1,2,3,4,5,6,7,8,9])
y = np.array([1,2,3,4,5,6,7,8,9])
x, y = np.meshgrid(x, y)
z = x*y
# Create and plot structured grid
grid = pv.StructuredGrid(x, y, z)
plotter = pv.Plotter()
plotter.add_mesh(grid, scalars=grid.points[:, -1], show_edges=True,
scalar_bar_args={'vertical': True})
plotter.show_grid()
# scale plot to enforce 1:1:1 aspect ratio
plotter.set_scale(xscale=1, yscale=x.ptp()/y.ptp(), zscale=x.ptp()/z.ptp())
plotter.show()
如果您希望 PyVista 对您的数据撒谎,您必须告诉它这样做。
我需要一种使用数百万个数据点制作 3 维曲面图的方法,因此我开始查看 pyvista,它应该可以很好地完成这项工作。 不过pyvista对我来说有点难掌握。
我有 x,y,z 数据,其中 x 是时间,y 是不同的测量值,z 是这些测量值。 我只想让 pyvista 向我显示包含此信息的曲面图。
例如,如果我在 matplotlib 或其他带有曲面图的库中使用此数组:
X = np.array([1,2,3,4,5,6,7,8,9])
Y = np.array([1,2,3,4,5,6,7,8,9])
X, Y = np.meshgrid(X, Y)
Z = X*Y
我得到这个输出:
但是如果我在任何 pyvista 图上使用相同的数据,我会得到这样的结果:
import sys
# Setting the Qt bindings for QtPy
import os
os.environ["QT_API"] = "pyqt5"
from qtpy import QtWidgets
from qtpy.QtWidgets import QMainWindow
import numpy as np
import pyvista as pv
from pyvistaqt import QtInteractor
import pandas as pd
class MainWindow(QMainWindow):
def __init__(self, parent=None, show=True):
QtWidgets.QMainWindow.__init__(self, parent)
# create the frame
self.frame = QtWidgets.QFrame()
vlayout = QtWidgets.QVBoxLayout()
# add the pyvista interactor object
self.plotter = QtInteractor(self.frame)
vlayout.addWidget(self.plotter.interactor)
self.frame.setLayout(vlayout)
self.setCentralWidget(self.frame)
# simple menu to demo functions
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('File')
exitButton = QtWidgets.QAction('Exit', self)
exitButton.setShortcut('Ctrl+Q')
exitButton.triggered.connect(self.close)
fileMenu.addAction(exitButton)
# allow adding a sphere
meshMenu = mainMenu.addMenu('Mesh')
self.add_sphere_action = QtWidgets.QAction('Add Sphere', self)
self.add_sphere_action.triggered.connect(self.add_sphere)
meshMenu.addAction(self.add_sphere_action)
x = np.array([9,8,7,6,5,4,3,2,1])
y = np.array([9,8,7,6,5,4,3,2,1])
x, y = np.meshgrid(x, y)
z = x*y
# z[z < -10] = np.nan # get rid of missing data. pyvista needs you to do this
i_res = 2 # display every nth point
j_res = 2 # display every nth point
self.grid = pv.StructuredGrid(x[::i_res, ::j_res], y[::i_res, ::j_res], z[::i_res, ::j_res])
self.z = z
self.x = x
self.y = y
self.plotter.add_mesh(self.grid, scalars=self.grid.points[:, 2], lighting=True, specular=0.5, smooth_shading=True,
show_scalar_bar=True)
if show:
self.show()
def add_sphere(self): #changing resolution, not adding a sphere
i_res = 5 # display every nth point
j_res = 5 # display every nth point
self.grid = pv.StructuredGrid(self.x[::i_res, ::j_res], self.y[::i_res, ::j_res], self.z[::i_res, ::j_res])
self.plotter.update()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
import pyvista as pv
import numpy as np
# Define a simple Gaussian surface
x = np.array([1,2,3,4,5,6,7,8,9])
y = np.array([1,2,3,4,5,6,7,8,9])
x, y = np.meshgrid(x, y)
z = x*y
# Get the points as a 2D NumPy array (N by 3)
points = np.c_[x.reshape(-1), y.reshape(-1), z.reshape(-1)]
points[0:5, :]
# simply pass the numpy points to the PolyData constructor
cloud = pv.PolyData(points)
cloud.plot(point_size=15)
我使用这段代码设法得到了一些不同的东西:
import pandas as pd
import pyvista as pv
import numpy as np
# Load Excel sheet using Pandas
# Note - you may need to `pip install xlrd`
# x = np.array([1,2,3,4,5,6,7,8,9])
# y = np.array([1,2,3,4,5,6,7,8,9])
x = np.array([[1],[2],[3],[4],[5],[6],[7],[8],[9]])
y = np.array([[1],[2],[3],[4],[5],[6],[7],[8],[9]])
# # x, y = np.meshgrid(x, y)
z = x*y
coords = np.hstack((x,y,z))
# Make the structured surface manually
structured = pv.StructuredGrid()
# Set coordinates
structured.points = coords
# Set the dimensions of the structured grid
structured.dimensions = [1, 1, 9]
# Apply an Elevation filter
elevation = structured.elevation()
elevation.plot(show_edges=True, show_grid=True, notebook=False)
但它只提供一串数据。我无法让其他任何东西正常工作。
有谁知道为什么 x、y、z 数据在 pyvista 中做奇怪的事情以及我如何只提供一个正常的曲面图?非常感谢,因为我很困惑。
你的第一个版本是正确的。
PyVista 拥有出色的文档,其中一部分是大量示例。您需要名为 Creating a Structured Surface 的那个。这最终与您最初展示的代码几乎相同:
import pyvista as pv
import numpy as np
# Define a simple linear surface
x = np.array([1,2,3,4,5,6,7,8,9])
y = np.array([1,2,3,4,5,6,7,8,9])
x, y = np.meshgrid(x, y)
z = x*y
# Create and plot structured grid
grid = pv.StructuredGrid(x, y, z)
plotter = pv.Plotter()
plotter.add_mesh(grid, scalars=grid.points[:, -1], show_edges=True,
scalar_bar_args={'vertical': True})
plotter.show_grid()
plotter.show()
这是(正确的!)输出:
这看起来不同的原因是 matplotlib 不是 3d 可视化工具(事实上,它的 3d 工具臭名昭著地使用 2d 渲染器导致奇怪的怪癖)。另一方面,PyVista 旨在可视化空间参考数据。如果您的 x
从 1 变为 9 而您的 z
从 1 变为 81 那么为什么它会挤压 z
轴?如果您沿每个坐标轴设置 1:1:1 纵横比,PyVista 显示的就是事实。
如果您不想要这个,您可以自行缩放:
import pyvista as pv
import numpy as np
# Define a simple linear surface
x = np.array([1,2,3,4,5,6,7,8,9])
y = np.array([1,2,3,4,5,6,7,8,9])
x, y = np.meshgrid(x, y)
z = x*y
# Create and plot structured grid
grid = pv.StructuredGrid(x, y, z)
plotter = pv.Plotter()
plotter.add_mesh(grid, scalars=grid.points[:, -1], show_edges=True,
scalar_bar_args={'vertical': True})
plotter.show_grid()
# scale plot to enforce 1:1:1 aspect ratio
plotter.set_scale(xscale=1, yscale=x.ptp()/y.ptp(), zscale=x.ptp()/z.ptp())
plotter.show()
如果您希望 PyVista 对您的数据撒谎,您必须告诉它这样做。