diff --git a/bindings/pydrake/systems/planar_scenegraph_visualizer.py b/bindings/pydrake/systems/planar_scenegraph_visualizer.py index 61f4076d1c41..ad6fbe2bc6d6 100644 --- a/bindings/pydrake/systems/planar_scenegraph_visualizer.py +++ b/bindings/pydrake/systems/planar_scenegraph_visualizer.py @@ -72,7 +72,8 @@ def __init__(self, ylim=[-1, 1], facecolor=[1, 1, 1], use_random_colors=False, - ax=None): + ax=None, + show=None): """ Args: scene_graph: A SceneGraph object. @@ -90,13 +91,16 @@ def __init__(self, ax: If supplied, the visualizer will draw onto those axes instead of creating a new set of axes. The visualizer will still change the view range and figure size of those axes. + show: Opens a window during initialization / publish iff True. + Default is None, which implies show=True unless + matplotlib.get_backend() is 'template'. """ default_size = matplotlib.rcParams['figure.figsize'] scalefactor = (ylim[1]-ylim[0]) / (xlim[1]-xlim[0]) figsize = (default_size[0], default_size[0]*scalefactor) PyPlotVisualizer.__init__(self, facecolor=facecolor, figsize=figsize, - ax=ax, draw_period=draw_period) + ax=ax, draw_period=draw_period, show=show) self.set_name('planar_multibody_visualizer') self._scene_graph = scene_graph diff --git a/bindings/pydrake/systems/pyplot_visualizer.py b/bindings/pydrake/systems/pyplot_visualizer.py index f1bfba054a05..e0c359e17059 100644 --- a/bindings/pydrake/systems/pyplot_visualizer.py +++ b/bindings/pydrake/systems/pyplot_visualizer.py @@ -1,8 +1,8 @@ import matplotlib import matplotlib.animation as animation import matplotlib.pyplot as plt -from matplotlib.widgets import Slider import numpy as np +from warnings import warn from pydrake.systems.framework import LeafSystem, PublishEvent, TriggerType from pydrake.systems.primitives import SignalLogger @@ -26,7 +26,7 @@ class PyPlotVisualizer(LeafSystem): """ def __init__(self, draw_period=1./30, facecolor=[1, 1, 1], - figsize=None, ax=None): + figsize=None, ax=None, show=None): LeafSystem.__init__(self) self.set_name('pyplot_visualization') @@ -41,14 +41,22 @@ def __init__(self, draw_period=1./30, facecolor=[1, 1, 1], self.ax = ax self.fig = ax.get_figure() + if show is None: + show = (matplotlib.get_backend().lower() != 'template') + self._show = show + self.ax.axis('equal') self.ax.axis('off') + if not show: + # This is the preferred way to support the jupyter notebook + # animation workflow and the `inline` backend grabbing an + # extraneous render of the figure. + plt.close(self.fig) + self._is_recording = False self._recorded_contexts = [] - self._show = (matplotlib.get_backend().lower() != 'template') - def on_initialize(context, event): if self._show: self.fig.show() @@ -77,13 +85,16 @@ def draw(self, context): """ raise NotImplementedError - def start_recording(self, show=True): - self.show = show + def start_recording(self, show=None): + if show is not None: + warn("The `show` argument of this `start_recording()` method " + "actually never worked. Pass `show` to the class " + "constructor instead. This argument will be removed on or " + "after 2020-04-01.") self._is_recording = True def stop_recording(self): self._is_recording = False - self.show = (matplotlib.get_backend().lower() != 'template') def reset_recording(self): self._recorded_contexts = [] # Reset recorded data. diff --git a/tutorials/pyplot_animation_multibody_plant.ipynb b/tutorials/pyplot_animation_multibody_plant.ipynb index 595f0fb49d93..8ae2dff8211c 100644 --- a/tutorials/pyplot_animation_multibody_plant.ipynb +++ b/tutorials/pyplot_animation_multibody_plant.ipynb @@ -112,7 +112,7 @@ "metadata": {}, "outputs": [], "source": [ - "def run_pendulum_example(duration=1., playback=True):\n", + "def run_pendulum_example(duration=1., playback=True, show=True):\n", " \"\"\"\n", " Runs a simulation of a pendulum.\n", "\n", @@ -134,7 +134,7 @@ " [0., 0., 0., 1.]])\n", " visualizer = builder.AddSystem(PlanarSceneGraphVisualizer(\n", " scene_graph, T_VW=T_VW,\n", - " xlim=[-1.2, 1.2], ylim=[-1.2, 1.2]))\n", + " xlim=[-1.2, 1.2], ylim=[-1.2, 1.2], show=show))\n", " builder.Connect(pose_bundle_output_port, visualizer.get_input_port(0))\n", " if playback:\n", " visualizer.start_recording()\n", @@ -239,6 +239,23 @@ "if animation.writers.is_available(\"ffmpeg\"):\n", " display(HTML(ani.to_html5_video()))" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you do not want to render the image (only the animation), then pass `show=False` in to the constructor of `PlanarSceneGraphVisualizer()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ani = run_pendulum_example(playback=True, show=False)\n", + "HTML(ani.to_jshtml())" + ] } ], "metadata": {