简体   繁体   English

使用新标量更新 PyVista 绘图仪

[英]Update PyVista plotter with new scalars

Trying to update the grid data with a new scalar I am not able to update the plot尝试用新标量更新网格数据我无法更新 plot

I have reported the issues to PyVista support as well: https://github.com/pyvista/pyvista-support/issues/501我也向 PyVista 支持报告了这些问题: https://github.com/pyvista/pyvista-support/issues/501

I am able to have a figure update by using this example: https://github.com/pyvista/pyvista-support/issues/68我可以使用此示例更新图形: https://github.com/pyvista/pyvista-support/issues/68

My example though does not work我的例子虽然不起作用

Example code below:示例代码如下:

import pyvista as pv
import pyvistaqt as pvqt
import numpy as np
import time

cmap='viridis'    
nx,ny,nz = 60, 40, 42
nc = nx*ny*nz

np.random.seed(0)
inidata = np.random.randint(1, 100, nc)

# generate random data for updating
data = [np.random.randint(1, 1000, nc), 
        np.random.randint(1, 1e4, nc),
        np.random.randint(1, 1e5, nc),
        np.random.randint(1, 1e6, nc)]

gridata = np.ones((nx,ny,nz))

mesh = pv.UniformGrid()
mesh.dimensions = np.array(gridata.shape) + 1 


mesh.origin = (0, 0, 0)  # The bottom left corner of the data set
mesh.spacing = (30, 30, 2.5)  # These are the cell sizes along each axis

mesh.cell_arrays["Data"] = inidata

plotter = pvqt.BackgroundPlotter()

# Add slices
xslice = mesh.slice(normal='x')
yslice = mesh.slice(normal='y')
zslice = mesh.slice(normal='z')
rslice = mesh.slice(normal=[1,1,0])

# Plot
plotter.add_mesh(mesh.outline(), color="k")
plotter.add_mesh(xslice, cmap=cmap)
plotter.add_mesh(yslice, cmap=cmap)
plotter.add_mesh(zslice, cmap=cmap)
plotter.add_mesh(rslice, cmap=cmap)

def update():
    for dat in data:
        plotter.update_scalars(dat, mesh=mesh)
        time.sleep(1)
        plotter.update()
        
plotter.add_callback(update, interval=100)

PyVista allows updating scene via setting new scalars to the loaded mesh. PyVista 允许通过为加载的网格设置新的标量来更新场景。 To do that, new data should be passed to the plotter:为此,应将新数据传递给绘图仪:

import numpy as np
import pyvista as pv

# Creating random data
N = 100
data = np.zeros((1, N, N))
data[:] = np.random.randint(0, 10000, data.shape)

# Creating a mesh from our data
g = pv.UniformGrid()
g.dimensions = np.array(data.shape) + 1
g.spacing = (10, 10, 10)
g.cell_data['data'] = data.flatten()
#Careful with threshold as it will turn your data into UnstructuredGrid
#g = g.threshold([0.0001, int(data.max())])

# Creating scene and loading the mesh
p = pv.Plotter()
p.add_mesh(g, opacity=0.5, name='data', cmap='gist_ncar')
p.show(interactive_update=True)

# Animation
for i in range(5, 1000):
    # Updating our data
    data[:] = np.random.randint(0, 10000, data.shape)
    # Updating scalars
    p.update_scalars(data.flatten())
    #p.mesh['data'] = data.flatten() # setting data to the specified mesh is also possible
    # Redrawing
    p.update()

Although, the shape (essentially the number of cells or points) of the data must stay the same.虽然,数据的形状(基本上是单元格或点的数量)必须保持不变。 This means that if data array size changes or data filtered through threshold changes it's number of cells, the loaded mesh will reject it.这意味着如果数据数组大小发生变化或通过阈值过滤的数据改变了它的单元格数量,则加载的网格将拒绝它。

A workaround is basically to load a new mesh into the Plotter every time your data is updated.解决方法基本上是在每次更新数据时将新网格加载到绘图仪中。

Swap #Animation section with this snippet and the plane will grow some volume:将#Animation 部分与此代码段交换,飞机将增加一些体积:

# Animation
for i in range(5, 1000):
    # Updating our data
    data = np.full((i, N, N),0)
    data[:] = np.random.randint(0,1000000, data.shape)
    
    # Recreating the mesh
    g = pv.UniformGrid()
    g.dimensions = np.array(data.shape) + 1
    g.spacing = (10, 10, 10)
    g.cell_data['data'] = data.flatten()

    # Reloading the mesh to the scene
    p.clear()
    p.add_mesh(g, opacity=0.5, name='data')

    # Redrawing
    p.update()

Note that scene is interactive only when its updating, so lowering update frequency will make scene pretty laggy请注意,场景仅在更新时才具有交互性,因此降低更新频率会使场景非常滞后

In my opinion, we should place the sections of #"Add Slices" and "#Plot" inside of the function update() to refresh the slices.在我看来,我们应该将 #"Add Slices" 和 "#Plot" 部分放在 function update() 中以刷新切片。

However, the scalar_bar_range will not update if the data range is smaller than the scalar_bar_range even though we force to update by plotter.update_scalar_bar_range.但是,如果数据范围小于 scalar_bar_range,即使我们通过 plotter.update_scalar_bar_range 强制更新,scalar_bar_range 也不会更新。

Therefore we have to refresh scalar_bar_range manually.因此我们必须手动刷新 scalar_bar_range。

def update():
    for dat in data:
        # Add slices
        xslice = mesh.slice(normal='x')
        yslice = mesh.slice(normal='y')
        zslice = mesh.slice(normal='z')
        rslice = mesh.slice(normal=[1,1,0])

        # Plot
        plotter.add_mesh(mesh.outline(), color="k")
        plotter.add_mesh(xslice, cmap=cmap)
        plotter.add_mesh(yslice, cmap=cmap)
        plotter.add_mesh(zslice, cmap=cmap)
        plotter.add_mesh(rslice, cmap=cmap)
        time.sleep(1)
    plotter.scalar_bars._scalar_bar_ranges = {mesh.active_scalars_name: [0, 0]}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM