每个 DataSet 包含允许您访问底层数值数据的属性。此数值数据可能与点、单元关联,或者不与点或单元关联并一般附加到网格。
为了说明 PyVista 中的数据数组,让我们首先构建一个比我们之前示例稍微复杂一点的网格。这里,我们通过从 ImageData 开始然后将其强制转换为 UnstructuredGrid 使用 cast_to_unstructured_grid() 来创建一个包含四个等距单元的简单网格。
>>> grid = pv.ImageData(dimensions=(3, 3, 1))
>>> ugrid = grid.cast_to_unstructured_grid()
>>> ugrid
让我们也绘制这个基本网格:
pl = pv.Plotter()
pl.add_mesh(ugrid, show_edges=True, line_width=5)
label_coords = ugrid.points + [0, 0, 0.02]
point_labels = [f'Point {i}' for i in range(ugrid.n_points)]
pl.add_point_labels(
label_coords, point_labels, font_size=25, point_size=20
)
cell_labels = [f'Cell {i}' for i in range(ugrid.n_cells)]
pl.add_point_labels(ugrid.cell_centers(), cell_labels, font_size=25)
pl.camera_position = 'xy'
pl.show()
现在我们有一个简单的网格可以使用,我们可以开始为它分配数据。可以关联到网格的主要有两种数据:标量数据和向量数据。标量数据是单一或多组件的非定向数据,可能包括温度值,或者在多组件数据的情况下,RGBA 值。向量数据具有幅度和方向,表示为每个数据点包含三个组件的数组。
绘制时,我们可以轻松显示标量数据,但此数据必须“关联”到点或单元。例如,我们可能希望为我们示例网格的单元分配值,我们可以通过访问网格的 cell_data 属性来实现。
单元数据
向 DataSet 添加标量数据的最简单方法是使用 [] 运算符。继续我们上面的示例,让我们为每个单元分配一个整数。我们可以使用 Python list 并使其与 UnstructuredGrid 中的单元数长度相同来完成此操作。或者作为更简单的示例,使用适当长度的 range。这里我们创建范围,将其添加到 cell_data,然后使用 [] 运算符访问它。
>>> simple_range = range(ugrid.n_cells)
>>> ugrid.cell_data['my-data'] = simple_range
>>> ugrid.cell_data['my-data']
pyvista_ndarray([0, 1, 2, 3])
注意我们如何返回 pyvista.pyvista_ndarray。由于 VTK 需要 C 数组,PyVista 将在内部包装或转换所有输入为 C 数组。然后我们可以使用以下方式绘制它:
ugrid.plot(cpos='xy', show_edges=True)
注意我们不必指定要绘制哪个单元数据,因为 [] 运算符自动设置活动标量:
>>> ugrid.cell_data
pyvista DataSetAttributes
Association : CELL
Active Scalars : my-data
Active Vectors : None
Active Texture : None
Active Normals : None
Contains arrays :
my-data int64(4,) SCALARS
我们还可以向绘图添加标签以显示哪些单元分配了哪些标量。注意这与我们分配的标量顺序相同。
pl = pv.Plotter()
pl.add_mesh(ugrid, show_edges=True, line_width=5)
cell_labels = [f'Cell {i}' for i in range(ugrid.n_cells)]
pl.add_point_labels(ugrid.cell_centers(), cell_labels, font_size=25)
pl.camera_position = 'xy'
pl.show()
我们可以继续使用 [] 运算符向我们的 DataSet 分配单元数据,但如果您不希望新数组成为活动数组,可以使用 set_array() 添加它
>>> data = np.linspace(0, 1, ugrid.n_cells)
>>> ugrid.cell_data.set_array(data, 'my-cell-data')
>>> ugrid.cell_data
pyvista DataSetAttributes
Association : CELL
Active Scalars : my-data
Active Vectors : None
Active Texture : None
Active Normals : None
Contains arrays :
my-data int64(4,) SCALARS
my-cell-data float64(4,)
现在,ugrid 包含两个数组,其中一个是“活动”标量。这组活动标量将是在 add_mesh() 或 pyvista.plot() 中未设置 scalars 时默认自动绘制的。这使得可以拥有许多与数据集关联的单元数组,并跟踪哪个将默认绘制为活动单元标量。
活动标量也可以通过 active_scalars 访问,活动标量数组的名称可以通过 active_scalars_name 访问或设置。
>>> ugrid.cell_data.active_scalars_name = 'my-cell-data'
>>> ugrid.cell_data
pyvista DataSetAttributes
Association : CELL
Active Scalars : my-cell-data
Active Vectors : None
Active Texture : None
Active Normals : None
Contains arrays :
my-data int64(4,)
my-cell-data float64(4,) SCALARS
点数据
数据可以以与单元数据相同的方式关联到点。point_data 属性允许您将数据关联到 DataSet 的点。这里,我们将使用 [] 运算符将简单列表关联到点。
>>> simple_list = list(range(ugrid.n_points))
>>> ugrid.point_data['my-data'] = simple_list
>>> ugrid.point_data['my-data']
pyvista_ndarray([0, 1, 2, 3, 4, 5, 6, 7, 8])
同样,这些值是默认通过 [] 运算符成为点数组中的活动标量:
>>> ugrid.point_data
pyvista DataSetAttributes
Association : POINT
Active Scalars : my-data
Active Vectors : None
Active Texture : None
Active Normals : None
Contains arrays :
my-data int64(9,) SCALARS
让我们绘制点数据。注意这与单元数据图不同;每个单独的点被分配一个标量值,该值在单元上插值以在点 0 的最低值和点 8 的最高值之间创建平滑的颜色映射。
pl = pv.Plotter()
pl.add_mesh(ugrid, show_edges=True, line_width=5)
label_coords = ugrid.points + [0, 0, 0.02]
point_labels = [f'Point {i}' for i in range(ugrid.n_points)]
pl.add_point_labels(
label_coords, point_labels, font_size=25, point_size=20
)
pl.camera_position = 'xy'
pl.show()
如在单元数据中,我们可以使用 set_array() 向 point_data 分配多个数组。
>>> data = np.linspace(0, 1, ugrid.n_points)
>>> ugrid.point_data.set_array(data, 'my-point-data')
>>> ugrid.point_data
pyvista DataSetAttributes
Association : POINT
Active Scalars : my-data
Active Vectors : None
Active Texture : None
Active Normals : None
Contains arrays :
my-data int64(9,) SCALARS
my-point-data float64(9,)
同样,这里现在有两个数组关联到该点数据,并且只有一个是“活动”标量数组。如同在单元数据中,我们可以使用 active_scalars 检索它,活动标量数组的名称可以通过 active_scalars_name 访问或设置。
>>> ugrid.point_data.active_scalars_name = 'my-point-data'
>>> ugrid.point_data
pyvista DataSetAttributes
Association : POINT
Active Scalars : my-point-data
Active Vectors : None
Active Texture : None
Active Normals : None
Contains arrays :
my-data int64(9,)
my-point-data float64(9,) SCALARS
数据集活动标量
从前面的部分继续,我们的 ugrid 数据集现在包含点和单元数据:
>>> ugrid.point_data
pyvista DataSetAttributes
Association : POINT
Active Scalars : my-point-data
Active Vectors : None
Active Texture : None
Active Normals : None
Contains arrays :
my-data int64(9,)
my-point-data float64(9,) SCALARS
>>> ugrid.cell_data
pyvista DataSetAttributes
Association : CELL
Active Scalars : my-cell-data
Active Vectors : None
Active Texture : None
Active Normals : None
Contains arrays :
my-data int64(4,)
my-cell-data float64(4,) SCALARS
在点和单元数据中都有活动标量,但在数据集级别只能有一个类型的标量为“活动”。原因是只有一种标量类型(无论是点还是单元)可以一次绘制,并且可以从 active_scalars_info 获取此数据:
>>> ugrid.active_scalars_info
ActiveArrayInfoTuple(association=<FieldAssociation.POINT: 0>, name='my-point-data')
注意活动标量默认是点标量。您可以通过使用 set_active_scalars() 设置活动标量来更改它。注意,如果您想设置活动标量并且点和单元数据都具有相同名称的数组,则必须指定偏好:
>>> ugrid.set_active_scalars('my-data', preference='cell')
>>> ugrid.active_scalars_info
ActiveArrayInfoTuple(association=<FieldAssociation.CELL: 1>, name='my-data')
这也可以在绘制时使用 add_mesh() 或 pyvista.plot() 中的 preference 参数设置。
字段数据
字段数组与 point_data 和 cell_data 不同,因为它们不与 DataSet 的几何关联。这意味着虽然不可能将字段数据指定为活动标量或向量,但您可以使用它来“附加”任何形状的数组。您甚至可以在字段数据中添加字符串数组:
>>> ugrid.field_data['my-field-data'] = ['hello', 'world']
>>> ugrid.field_data['my-field-data']
pyvista_ndarray(['hello', 'world'], dtype='<U5')
注意字段数据自动传输到 VTK C 风格数组,然后表示为 numpy 数据格式。
列出当前字段数据时,注意关联为“NONE”:
>>> ugrid.field_data
pyvista DataSetAttributes
Association : NONE
Contains arrays :
my-field-data <U5(2,)
这是因为数据不与点或单元关联,并且不能如此,因为字段数据预计不匹配单元或点的数量。因此,它也不能被绘制。
向量、纹理坐标和法线属性
单元和点数据都可以存储以下“特殊”属性以及 active_scalars:
活动法线
active_normals 数组是一个特殊数组,指定网格的局部法线方向。它用于创建基于物理的渲染、使用 Phong 插值渲染平滑着色、按标量扭曲等。如果在以 smooth_shading=True 或 pbr=True 绘制时未设置此数组,它将被计算。
活动纹理坐标
active_texture_coordinates 数组用于渲染纹理。有关使用此数组的示例,请参阅应用纹理。
活动向量
active_vectors 是包含具有幅度和方向(具体地,三个组件)的数量的数组。例如,包含在各个坐标处的风速的向量场。这与 active_scalars 不同,因为标量预期为非定向的,即使它们包含多个组件(如 RGB 数据的情况)。
向量在使用 transform() 过滤器执行转换时,在 VTK 中的处理方式与标量不同。与标量数组不同,向量数组将与几何一起转换,因为这些向量表示具有方向的数量。
注意
VTK 只允许一个“活动”向量。如果您有多个希望转换的向量数组,请在 transform() 中设置 transform_all_input_vectors=True。请注意,这将转换任何具有三个组件的数组,因此在转换后必须丢弃像 RGB 数组这样的多组件标量数组。