pyvista-support
pyvista-support copied to clipboard
Screenshots and headless plotting
Hi,
Thank you for the great library.
Is there a way to save the current mesh not as an image saved to disk, but to return a numpy array (or other type of arrays) instead, that I can handle after.
Thank you in advance!
Hello,
A mesh in pyvista
can be saved as numpy
arrays by first extracting and then saving these arrays. For example:
import numpy as np
import pyvista as pv
# save the mesh as a npz file
mesh = pv.Sphere()
np.savez('mesh.npz', points=mesh.points, faces=mesh.faces)
You can then reconstruct the mesh by loading in the points and faces:
np_mesh = np.load('mesh.npz')
points = np_mesh['points']
faces = np_mesh['faces']
# recreate the pyvista mesh
mesh = pv.PolyData(points, face)
You could also just save the mesh as a vtk file to disk with:
mesh.save('mesh.vtk')
# this can then be loaded using pyvista with
loaded_mesh = pv.load('mesh.vtk')
If I were you, I'd just keep the mesh in the vtk format if you wish to save it to file. There are many attributes to the mesh that would take substantial work to save to disk. This way you can just save one file and then access the data directly from the mesh instance.
Hi @akaszynski ,
Thanks for the detailed response.
However, I'm not interested in saving the vertices and and faces of the mesh but rather the rendering. In fact, I want to save how the mesh is looking as an image, and I don't want to save this image to the disk, but to have it as a numpy array, i.e get the result of plotter.show(screenshot='name.png')
as a numpy array.
Is there a way to do this?
Thank you.
Ok, sorry about that. What you're looking for then is:
import pyvista as pv
pl = pv.Plotter()
pl.add_mesh(pv.Sphere())
pl.show(auto_close=False)
image = pl.screenshot(None, return_img=True)
pl.close()
print(type(image))
<class 'numpy.ndarray'>
Hi @akaszynski ,
Thank you for the clear response.
So If I understand correctly, it is always necessary to show the image pl.show
before getting the array. In fact, I want to know if I can do this in a headless way, because I'm running the code on a server, and I cannot render the image before getting the array.
Thank you!
You can save an image on a headless display using:
import pyvista as pv
pl = pv.Plotter(off_screen=True)
pl.add_mesh(pv.Sphere())
image = pl.screenshot(None, return_img=True)
Be sure to read the headless display section in the pyansys docs for help setting up a headless display.
Hi @akaszynski !
Thank you for your quick and detailed response.
However, when I try your solution in a python interactive shell, it works well, but when I use in a script python, I got a segmentation fault (core dumped)
error, without any further information. when debugging, I found that image = pl.screenshot(None, return_img=True)
is the source of the problem, and even when encapsulating it in try except
, the error always happens.
Can you give me direction on how to solve this?
Thank you!
@pvnieo, please share a report:
import pyvista as pv
print(pv.Report())
@banesullivan
Python 3.6.10 |Anaconda, Inc.| (default, May 8 2020, 02:54:21)
[GCC 7.3.0] on linux
>>> import pyvista as pv
>>> print(pv.Report())
Fatal Python error: Segmentation fault
Current thread 0x00007ffb18854700 (most recent call first):
File "~/miniconda3/envs/cfca/lib/python3.6/site-packages/pyvista/plotting/plotting.py", line 766 in render
File "~miniconda3/envs/cfca/lib/python3.6/site-packages/pyvista/plotting/plotting.py", line 4099 in show
File "~/miniconda3/envs/cfca/lib/python3.6/site-packages/pyvista/utilities/errors.py", line 117 in get_gpu_info
File "~/miniconda3/envs/cfca/lib/python3.6/site-packages/pyvista/utilities/errors.py", line 130 in __init__
File "~/miniconda3/envs/cfca/lib/python3.6/site-packages/pyvista/utilities/errors.py", line 227 in __init__
File "<stdin>", line 1 in <module>
Segmentation fault
When there's a segfault, it means that there's no virtual framebuffer. Please see the section on setting up a virtual framebuffer.
Ok, sorry about that. What you're looking for then is:
import pyvista as pv pl = pv.Plotter() pl.add_mesh(pv.Sphere()) pl.show(auto_close=False) image = pl.screenshot(None, return_img=True) pl.close() print(type(image))
<class 'numpy.ndarray'>
Hi @akaszynski , I've tried this in Jupyter but I'm getting the following error:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/var/folders/ny/l87wbxgj4hd84n0q43vlh94c0000gn/T/ipykernel_66644/3492255545.py in <module>
4 pl.camera.position = (0, 0, 250)
5 pl.show(auto_close=False)
----> 6 img = pl.screenshot(None, return_img=True)
7 pl.close()
~/miniconda3/envs/t21-pyvista/lib/python3.7/site-packages/pyvista/plotting/plotting.py in screenshot(self, filename, transparent_background, return_img, window_size)
4490 self.render()
4491
-> 4492 return self._save_image(self.image, filename, return_img)
4493
4494 @wraps(Renderers.set_background)
~/miniconda3/envs/t21-pyvista/lib/python3.7/site-packages/pyvista/plotting/plotting.py in image(self)
1451 return self.last_image
1452
-> 1453 self._check_rendered()
1454 self._check_has_ren_win()
1455
~/miniconda3/envs/t21-pyvista/lib/python3.7/site-packages/pyvista/plotting/plotting.py in _check_rendered(self)
1425 if not self._rendered:
1426 raise AttributeError(
-> 1427 '\nThis plotter has not yet been set up and rendered '
1428 'with ``show()``.\n'
1429 'Consider setting ``off_screen=True`` '
AttributeError:
This plotter has not yet been set up and rendered with ``show()``.
Consider setting ``off_screen=True`` for off screen rendering.
My code is:
pl = pv.Plotter()
pl.add_mesh(mesh, color="lightblue", opacity=0.5)
pl.add_mesh(screw_mesh.translate((15, -15, 0), inplace=False), color=True, opacity=0.5)
pl.camera.position = (0, 0, 250)
pl.show(auto_close=False)
img = pl.screenshot(None, return_img=True)
pl.close()
You may want to use pv.start_xvfb()
to create a virtual display