1

尝试使用新标量更新网格数据我无法更新绘图

我也向 PyVista 支持报告了这些问题:https ://github.com/pyvista/pyvista-support/issues/501

我可以使用此示例进行图形更新:https ://github.com/pyvista/pyvista-support/issues/68

我的例子虽然不起作用

下面的示例代码:

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)
4

2 回答 2

2

PyVista allows updating scene via setting new scalars to the loaded mesh. 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
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

于 2021-10-01T18:47:23.117 回答
0

在我看来,我们应该将#"Add Slices" 和"#Plot" 的部分放在函数 update() 中来刷新切片。

但是,如果数据范围小于 scalar_bar_range,则 scalar_bar_range 不会更新,即使我们通过 plotter.update_scalar_bar_range 强制更新。

因此我们必须手动刷新 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]}
于 2021-09-26T12:03:51.737 回答