Reputation: 164
I need to save still images of some pyvista renders from within jupyter. For whatever reason, when using the 'client' jupyter backend rather than the default backend the images look much better, respect the opacity arguments appropriately, respond to interaction much more quickly, etc, and so I would like to screenshot images produced using this backend.
However, when I attempt to screenshot images rendered using this backend with plotter.screenshot
, I get the following error:
AttributeError: This plotter has not yet been set up and rendered with ``show()``. Consider setting ``off_screen=True`` for off screen rendering.
An MRE that gives the same error is:
import pyvista as pv
# Setup trame server proxy
pv.global_theme.trame.server_proxy_enabled = True
pv.global_theme.trame.server_proxy_prefix = "/proxy/"
# Initialize plotter
plotter = pv.Plotter(off_screen=True)
# Add a mesh
bunny = pv.examples.download_bunny()
plotter.add_mesh(bunny)
# Show
plotter.show(auto_close=False, jupyter_backend='client')
# Wait for it to render, then run this line
plotter.screenshot('screenshot_path.png')
The root cause of this error seems to be that the plotter does not realize it has already rendered when using this backend, i.e. plotter._rendered
returns False even when I am looking at the rendered image in the output of the jupyter cell. I am able to screenshot in the expected way when using the default backend; this only happens with the jupyter_backend='client'
argument. I have also tried rendering using the default backend, then interactively changing to the client backend using the "Toggle rendering mode" button in the interactive window, but this screenshots the image produced by the default backend, not the client backend. Is the plotter._rendered
issue a bug or a known behavior? Either way, is there a workaround or are there other arguments I should be passing to either the Plotter
initialization or the call to show
that might make the Plotter
state sync appropriately?
Upvotes: 0
Views: 222
Reputation: 164
I've solved this via a hacky workaround: I can get to what I want by exporting the scene to HTML (which will necessarily use the client to render when opened), then rendering and screenshotting it using the shot-scraper package and a subprocess command. Done this way, you don't need to use the pyvista client backend at all. This also allows for dealing with the issue that, when screenshotted using the pyvista plotter, the screenshot sometimes happens before the scene is actually rendered and so is blank.
import pyvista as pv
import subprocess
# Setup trame server proxy
pv.global_theme.trame.server_proxy_enabled = True
pv.global_theme.trame.server_proxy_prefix = "/proxy/"
# Initialize plotter
plotter = pv.Plotter(off_screen=True)
# Add a mesh
bunny = pv.examples.download_bunny()
plotter.add_mesh(bunny)
# Show
plotter.show(auto_close=False)
# Export to HTML
plotter.export_html('/path/to/render.html')
# Use shot-scraper to render and screenshot this via a subprocess
# You can use the --wait flag to deal with screenshotting renders that take a while to render
subprocess.Popen("shot-scraper /path/to/render.html -o /path/to/screenshot.png --wait 2000".split(" "))
Upvotes: 0