Skip to content

Commit

Permalink
Fix show logic in pyplot visualizer (RobotLocomotion#12658)
Browse files Browse the repository at this point in the history
The show arguments passed into the recording methods were doing nothing (they were accidentally setting self.show instead of self._show).  And it was too late, anyhow, to prevent a window being drawn in the jupyter workflow.  This commit does the shenanigans necessary to avoid that extra plot.

Unfortunately, the drawing/not drawing is not something we currently test.
  • Loading branch information
RussTedrake authored Feb 2, 2020
1 parent 94925df commit f81df12
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 11 deletions.
8 changes: 6 additions & 2 deletions bindings/pydrake/systems/planar_scenegraph_visualizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
25 changes: 18 additions & 7 deletions bindings/pydrake/systems/pyplot_visualizer.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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')
Expand All @@ -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()
Expand Down Expand Up @@ -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.
Expand Down
21 changes: 19 additions & 2 deletions tutorials/pyplot_animation_multibody_plant.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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": {
Expand Down

0 comments on commit f81df12

Please sign in to comment.