pyvista-support icon indicating copy to clipboard operation
pyvista-support copied to clipboard

Screenshots and headless plotting

Open pvnieo opened this issue 3 years ago • 10 comments

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!

pvnieo avatar Aug 06 '20 02:08 pvnieo

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.

akaszynski avatar Aug 06 '20 04:08 akaszynski

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.

pvnieo avatar Aug 06 '20 08:08 pvnieo

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'>

akaszynski avatar Aug 06 '20 16:08 akaszynski

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!

pvnieo avatar Aug 06 '20 16:08 pvnieo

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.

akaszynski avatar Aug 06 '20 18:08 akaszynski

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 avatar Aug 07 '20 02:08 pvnieo

@pvnieo, please share a report:

import pyvista as pv
print(pv.Report())

banesullivan avatar Aug 11 '20 02:08 banesullivan

@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

adizhol avatar Jan 20 '21 16:01 adizhol

When there's a segfault, it means that there's no virtual framebuffer. Please see the section on setting up a virtual framebuffer.

akaszynski avatar Jan 21 '21 04:01 akaszynski

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

leo2r avatar Aug 11 '22 09:08 leo2r

You may want to use pv.start_xvfb() to create a virtual display

ducha-aiki avatar Mar 29 '24 11:03 ducha-aiki