Pyvista官方文档:https://qtdocs.pyvista.org/index.html
下面的代码是本人查看官方文档API之后编写的,里面含有对官方API的翻译。注释写的很详细,作者就不多赘述了。
三维云图绘制效果:
表面:
表面+网格:
网格线:
表面点+右键选中显示数据:
高斯点+右键选中显示数据:
鼠标右键单击选中点,进行其数据值的显示
切片和裁剪
盒子裁剪:
盒子所在的六面体,可以对每个面进行法向拖动,也可以旋转、移动盒子
平面裁剪:
箭头为法线所在的平面对模型进行裁剪,既可以拖动箭头和箭尾对平面的角度进行改变,也可以法向拖动平面
平面切片:
箭头为法线所在的平面对模型进行切片,既可以拖动箭头和箭尾对平面的角度进行改变,也可以法向拖动平面
三平面切片:
三个互相垂直的平面,均可在其法向拖动,进行切片
曲面切片:
小球组成的线所在的曲面进行切片,小球可以随意拖动
数据阈值裁剪:
拖动滑块改变阈值,默认滑块右侧(>=滑块值)的数据部分显示出来,可以反向
import numpy as np
import pyvista as pv
from pyvista.plotting.opts import PickerType
vtu_filename = "../Data/cylinderdemo4_out.vtu"
# 读取 VTK 文件
mesh = pv.read(vtu_filename)
# 读取节点数据
node_data_name = "Temperature" # 替换为您的节点数据名称
node_data = mesh.point_data[node_data_name]
plotter = pv.Plotter(shape="1|1") # TODO shape="3|1", 分隔绘图窗口,左边3个,右边一个
print(plotter)
plotter.subplot(0, 0) # TODO 第1个框里绘制
cylinder = plotter.add_mesh(mesh, scalars=node_data, cmap="coolwarm",
# show_scalar_bar=False,
scalar_bar_args={'title': 'Temperature',
"vertical":"False",
"height":0.65,
"position_x":0.85,
"position_y":0.1},
# show_vertices=True, # TODO 显示点
point_size=3, # TODO 点的大小
# style='points_gaussian',
# show_edges=True, # TODO 显示网格
style='surface', # TODO 显示样式默认:'surface'表面,'wireframe'线条,'points'表面的点配合point_size设置大小,
) # TODO 圆柱
_ = plotter.add_axes( # TODO 左下角坐标轴
line_width=5,
cone_radius=0.6,
shaft_length=0.7,
tip_length=0.3,
ambient=0.5,
label_size=(0.4, 0.16),
)
plotter.subplot(1, 0)
# TODO 添加切片盒子裁剪网格 剪裁的网格保存到plotter.box_clipped_meshes的属性
# plotter.add_mesh_clip_box(mesh,
# interaction_event='end', # TODO 什么时候触发改变,'start'刚开始拖动, 'end'拖动松开, 'always'一直变
# show_scalar_bar=False,
# cmap="coolwarm",
# ) # TODO 切片
actor =plotter.add_mesh_clip_box(mesh,
invert=False, # TODO 是否翻转/反转剪辑的标志
rotation_enabled=True, # TODO 如果False,框小部件不能旋转,并且严格正交于笛卡尔轴
widget_color=None, # TODO 小工具的颜色。字符串、RGB序列或十六进制颜色字符串,as color='white'
outline_translation=True, # TODO 如果False,平面小部件不能被转换,并且被严格地放置在给定的边界内
merge_points=True, # TODO 如果True(默认),独立定义的网格元素的重合点将被合并
crinkle=False, # TODO 通过沿剪辑提取整个单元格来使剪辑起皱
interaction_event='end', # TODO 什么时候触发改变,'start'刚开始拖动, 'end'拖动松开, 'always'一直变
# **kwargs # TODO 所有add_mesh()的参数都可以用
cmap="coolwarm",
)
# print(type(actor))
# print(actor)
# clip = plotter.box_clipped_meshes
# print(type(clip))
# TODO 使用平面裁剪网格 保留剩下的三维网格 剪裁的网格保存到plotter.plane_clipped_meshes的属性
# plotter.add_mesh_clip_plane(mesh,
# normal='x', # TODO 平面的起始法向量
# invert=False, # TODO 是否翻转/反转剪辑的标志
# widget_color=None, # TODO 组件的颜色 字符串、RGB列表或十六进制颜色字符串
# value=0.0, # TODO 沿法线方向设置剪裁值。默认值为0.0
# assign_to_axis=None, # TODO 指定平面的法线与给定的轴平行。选项有(0, 'x'), (1, 'y'),或者(2, 'z')
# tubing=False, # TODO 当使用隐式平面wiget时,这将控制是否在平面边界周围显示管状体
# origin_translation=True, # TODO 如果False,平面小部件不能通过其原点平移,而是严格放置在给定的原点。仅在使用隐式平面时有效
# outline_translation=False, # TODO 如果False时,box小部件不能被翻译,并且被严格地放置在给定的边界内。
# implicit=True, # TODO 当为True时,使用vtkImplicitPlaneWidget,当为False时,使用vtkPlaneWidget。
# normal_rotation=True, # TODO 设置法向量箭头的不透明度为0,这样它就被有效地禁用了。这可以防止用户旋转法线。当设置assign_to_axis时,该值强制为False。
# crinkle=False, # TODO 通过沿剪辑提取整个单元格来使剪辑起皱
# interaction_event='end', # TODO 什么时候触发改变,'start'刚开始拖动, 'end'拖动松开, 'always'一直变
# origin=None, # TODO 平面中心的起始坐标
# # **kwargs # TODO 所有add_mesh()的参数都可以用
# cmap="coolwarm",
# )
# TODO 使用平面裁剪网格 保留平面所在的二维网格 切片网格被保存到plotter.plane_sliced_meshes的属性
# plotter.add_mesh_slice(mesh,
# normal='x', # TODO 平面的起始法向量
# generate_triangles=False, # TODO 如果这被启用(False默认情况下),输出将是三角形,否则,输出将是相交多边形
# widget_color=None, # TODO 平面组件的颜色 字符串、RGB序列或十六进制颜色字符串。默认为'white'
# assign_to_axis=None, # TODO 指定平面的法线与给定的轴平行:选项有(0,' x ')、(1,' y ')或(2,' z ')
# tubing=False, # TODO 当使用隐式平面wiget时,这将控制是否在平面边界周围显示管状体
# origin_translation=True, # TODO 如果False,平面小部件不能通过其原点平移,而是严格放置在给定的原点。仅在使用隐式平面时有效
# outline_translation=False, # TODO 如果为False,则无法翻译框小部件,并严格放置在给定的边界上。
# implicit=True, # TODO 当为True时,使用vtkImplicitPlanewidget,当为False时,使用vtkPlaneWidget。
# normal_rotation=True, # TODO 设置法向量箭头的不透明度为0,这样它就被有效地禁用了。这可以防止用户旋转法线。当设置assign_to_axis时,该值强制为False。
# interaction_event="end", # TODO 什么时候触发(事件id)45:结束交互 44:拖动时
# origin=None, # TODO 平面中心的起始坐标。
# # **kwargs # TODO 所有add_mesh()的参数都可以用
# cmap="coolwarm",
# )
# TODO 用三个相互垂直的平面切割网格 保留三个平面所在的二维网格
# plotter.add_mesh_slice_orthogonal(mesh,
# generate_triangles=False, # TODO 如果这被启用(False默认情况下),输出将是三角形,否则,输出将是相交多边形
# widget_color=None, # TODO 小工具的颜色。字符串、RGB序列或十六进制颜色字符串,as color='white'
# tubing=False, # TODO 当使用隐式平面wiget时,这将控制是否在平面边界周围显示管状体
# interaction_event='end', # TODO 什么时候触发改变,'start'刚开始拖动, 'end'拖动松开, 'always'一直变
# # **kwargs # TODO 所有add_mesh()的参数都可以用
# cmap="coolwarm",
# )
# TODO 使用样条线小部件(多点可拖动线)切割网格 保留线所组成的平面、曲面的网格 切片网格被保存到plotter.spline_sliced_meshes的属性
# plotter.add_mesh_slice_spline(mesh,
# generate_triangles=False, # TODO 如果这被启用(False默认情况下),输出将是三角形,否则,输出将是相交多边形
# n_handles=5, # TODO 控制样条曲线参数函数的交互球体的数量
# resolution=25, # TODO 要在样条上生成的点数
# widget_color=None, # TODO 小工具的颜色。字符串、RGB序列或十六进制颜色字符串,as color='white'
# show_ribbon=True, # TODO 如果True,也将显示用于切片的多边形平面
# ribbon_color='pink', # TODO 丝带的颜色。字符串、RGB序列或十六进制颜色字符串
# ribbon_opacity=0.5, # TODO 色带的不透明度。默认值为1.0,必须介于[0, 1]
# initial_points=None, # TODO 初始化小部件位置的点。必须具有与相同数量的元素n_handles。如果第一个点和最后一个点相同,这将是一个封闭环样条
# closed=False, # TODO 使样条曲线成为闭合环
# interaction_event=44, # TODO 什么时候触发(事件id)45:结束交互 44:拖动时
# # **kwargs # TODO 所有add_mesh()的参数都可以用
# cmap="coolwarm",
# )
# TODO 使用滑块在网格上应用阈值
# plotter.add_mesh_threshold(mesh,
# show_scalar_bar=False,
# cmap="coolwarm",
# ) # TODO
# plotter.add_mesh_threshold(mesh,
# scalars=None, # TODO 要设定阈值和显示的网格上标量的字符串名称
# invert=False, # TODO 反转阈值结果。也就是说,此选项关闭时输出中的像元将被排除,而输出中的像元将被包括
# widget_color=None, # TODO 小工具的颜色。字符串、RGB序列或十六进制颜色字符串。as color='white'
# preference='cell', # TODO 该参数设置标量如何映射到网格。默认'cell',导致标量与网格单元相关联。可以是'point'或者'cell'
# title=None, # TODO 滑块小工具的字符串标签
# pointa=(0.4, 0.9), # TODO 显示端口上滑块左侧点的相对坐标
# pointb=(0.9, 0.9),# TODO 显示端口上滑块右点的相对坐标
# continuous=False, # TODO 如果启用了此选项(默认为False),使用连续音程[minimum cell scalar, maximum cell scalar]与阈值边界相交,而不是与顶点的离散标量值集合相交
# all_scalars=False, # TODO 如果使用点数据的标量,当该值为True时,单元中的所有点必须满足阈值。当False的时候,具有满足阈值标准的标量值的像元的任何点将提取像元。使用单元格数据时无效
# method='upper', # TODO 为单值设置阈值方法,定义要使用的阈值界限。如果value是一个范围,此参数将被忽略,提取两个值之间的数据。对于单个值,'lower'将提取低于value. 'upper'将提取大于value.
# # **kwargs # TODO 所有add_mesh()的参数都可以用
# cmap="coolwarm",
# )
# TODO 对指定点 添加 label标签 后期可以尝试鼠标点击某个点 为其添加 值的标签
# point_A = pv.pyvista_ndarray([mesh.points[0]])
# label_A = pv.pyvista_ndarray([node_data[0]])
# print(point_A)
# print(type(point_A))
# plotter.add_point_labels(points=point_A, labels=label_A)
# TODO 将轮廓添加到场景中 可以在切割的时候使用,方便观察
# plotter.add_silhouette(mesh,
# color=None, # TODO 轮廓线条的颜色
# line_width=None, # TODO 轮廓线条宽度
# opacity=None, # TODO 之间的线条透明度0和1
# feature_angle=None, # TODO 如果设置,显示超过该角度的锐边
# decimate=None, # TODO 之间的抽取级别0和1。抽取将提高渲染性能。一个好的经验法则是尝试0.9直到达到所需的渲染性能
# )
# plotter.subplot(1, 0) # TODO 第2个框里绘制
# plotter.add_mesh(mesh, scalars=node_data, cmap="coolwarm",
# show_scalar_bar=False,
# # scalar_bar_args={
# # 'title': '',
# # "vertical":"False",
# # "height":0.65,
# # "position_x":0.85,
# # "position_y":0.1},
# # show_vertices=True, # TODO 显示点
# # point_size=5, # TODO 点的大小
# # style='points_gaussian',
# show_edges=True, # TODO 显示网格
#
# ) # TODO 圆柱
#
# _ = plotter.add_axes( # TODO 左下角坐标轴
# line_width=5,
# cone_radius=0.6,
# shaft_length=0.7,
# tip_length=0.3,
# ambient=0.5,
# label_size=(0.4, 0.16),
# )
# plotter.subplot(2, 0) # TODO 第3个框里绘制
# plotter.add_mesh(mesh, scalars=node_data, cmap="coolwarm",
# show_scalar_bar=False,
# # scalar_bar_args={
# # 'title': 't',
# # "vertical":"False",
# # "height":0.65,
# # "position_x":0.85,
# # "position_y":0.1},
# show_vertices=True, # TODO 显示点
# # point_size=5, # TODO 点的大小
# # style='points_gaussian',
# # show_edges=True, # TODO 显示网格
#
# ) # TODO 圆柱
#
# _ = plotter.add_axes( # TODO 左下角坐标轴
# line_width=5,
# cone_radius=0.6,
# shaft_length=0.7,
# tip_length=0.3,
# ambient=0.5,
# label_size=(0.4, 0.16),
# )
# plotter.subplot(3, 0) # TODO 第4个框里绘制
# # TODO 绘制高斯点
# plotter.add_mesh(pv.PolyData(mesh.points),scalars=node_data, cmap='coolwarm',
# scalar_bar_args={
# 'title': 'Temperature',
# "vertical": "False",
# "height": 0.65,
# "position_x": 0.85,
# "position_y": 0.1},
# show_edges=False)
def fun_pick(point):
points = mesh.points
# 计算点与数组中每个点的距离
distances = np.linalg.norm(points - point, axis=1)
# 找到距离最接近的点的索引
index = np.argmin(distances)
plotter.add_point_labels(np.array([points[index]]), np.array([node_data[index]]),
point_color='black',
point_size=10,
font_size=20,
name='point_1' # TODO 添加的参与者的名称,以便于更新。如果此名称的参与者已经存在于呈现窗口中,它将被新参与者替换。
)
# TODO 拾取点
plotter.enable_point_picking(callback=fun_pick, # TODO 回调函数,第一个参数是被点击的点坐标 [-33.262 -27.3781 -22.936]
tolerance=0.025, # TODO 拾取的误差,按照屏幕百分比
left_clicking=False, # TODO 默认鼠标右键选取,True则鼠标左键
picker=PickerType.POINT, # TODO 选取的类型 hardware、cell、point、volume
show_message=True, # TODO 显示关于如何使用点拾取工具的消息。如果这是一个字符串,那将是显示的消息。
font_size=18, # TODO 设置消息的大小。
color='black', # TODO 显示被选中后的颜色。
point_size=10, # TODO 如果' show_point ' '为' True',则所选点的大小。
show_point=True, # TODO 点击后显示选中点。
use_picker=False, # TODO 当' ' True ' '时,回调函数也将被传递给选择器。
pickable_window=False, # TODO 当“True”并且所选拾取器支持它时,3D窗口中的点是可拾取的。
clear_on_no_selection=True, # TODO 当没有选择任何点时清除所选内容。
# **kwargs, # TODO
)
cent = np.random.random((1, 3))
direction = np.random.random((1, 3))
print(cent)
print(direction)
# _ = plotter.add_arrows(cent, direction, mag=1) # TODO 箭头
_ = plotter.add_axes( # TODO 左下角坐标轴
line_width=5,
cone_radius=0.6,
shaft_length=0.7,
tip_length=0.3,
ambient=0.5,
label_size=(0.4, 0.16),
)
# _ = plotter.add_axes_at_origin() # TODO 中心位置添加坐标轴
_ = plotter.add_camera_orientation_widget() # TODO 右上角坐标轴带负轴
chart = pv.Chart2D() # TODO 图表
_ = chart.plot(range(10), range(10))
# plotter.add_chart(chart)
# mesh = pyvista.Sphere()
# actor = plotter.add_mesh(mesh)
# def toggle_vis(flag):
# actor.SetVisibility(flag)
# _ = plotter.add_checkbox_button_widget(toggle_vis, value=True) # TODO 左下角添加一个复选框CheckBox
# _ = plotter.add_cursor() # TODO 添加光标 框起来 不是鼠标
# _ = plotter.add_legend(bcolor='w', face=None)
plotter.show()