Skip to content

Commit 743977d

Browse files
committed
Simplify implementation, allow multiple figs for 2D plots
1 parent 1b0573b commit 743977d

File tree

1 file changed

+62
-60
lines changed

1 file changed

+62
-60
lines changed

mujoco_viewer/mujoco_viewer.py

Lines changed: 62 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,28 @@ def __init__(
7070
self.cam = mujoco.MjvCamera()
7171
self.scn = mujoco.MjvScene(self.model, maxgeom=10000)
7272
self.pert = mujoco.MjvPerturb()
73-
self.fig = mujoco.MjvFigure()
74-
mujoco.mjv_defaultFigure(self.fig)
75-
76-
# Counter for number of lines added to plot
77-
self._line_counter = 0
7873

7974
self.ctx = mujoco.MjrContext(
8075
self.model, mujoco.mjtFontScale.mjFONTSCALE_150.value)
8176

82-
# Adjust placement and size of graph
8377
width, height = glfw.get_framebuffer_size(self.window)
78+
79+
# figures for creating 2D plots
80+
max_num_figs = 3
81+
self.figs = []
82+
self.figs_viewport = []
8483
width_adjustment = width % 4
85-
self.graph_viewport = mujoco.MjrRect(
86-
int(3 * width / 4) + width_adjustment,
87-
0,
88-
int(width / 4),
89-
int(height / 4),
90-
)
91-
mujoco.mjr_figure(self.graph_viewport, self.fig, self.ctx)
92-
self.fig.flg_extend = 1
93-
self.fig.flg_symmetric = 0
84+
fig_w, fig_h = int(width / 4), int(height / 4)
85+
for idx in range(max_num_figs):
86+
fig = mujoco.MjvFigure()
87+
mujoco.mjv_defaultFigure(fig)
88+
fig.flg_extend = 1
89+
self.figs.append(fig)
90+
91+
x = int(3 * width / 4) + width_adjustment
92+
y = idx*fig_h
93+
vp = mujoco.MjrRect(x, y, fig_w, fig_h)
94+
self.figs_viewport.append(vp)
9495

9596
# load camera from configuration (if available)
9697
pathlib.Path(
@@ -137,59 +138,50 @@ def __init__(
137138
self._overlay = {}
138139
self._markers = []
139140

140-
def add_graph_line(self, line_name):
141-
assert (
142-
type(line_name) == str
143-
), f"Line_name is not a string: {type(line_name)}"
144-
if line_name in []:
141+
def add_line_to_fig(self, line_name, fig_idx = 0):
142+
assert isinstance(line_name, str), \
143+
"Line name must be a string."
144+
145+
fig = self.figs[fig_idx]
146+
if line_name.encode('utf8') == b'':
147+
raise Exception(
148+
"Line name cannot be empty."
149+
)
150+
if line_name.encode('utf8') in fig.linename:
145151
raise Exception(
146-
"line name already exists"
152+
"Line name already exists in this plot."
147153
)
148154

149-
self.fig.linename[self._line_counter] = line_name
155+
# this assumes all lines added by user have a non-empty name
156+
linecount = fig.linename.tolist().index(b'')
157+
158+
# we want to add the line after the last non-empty index
159+
fig.linename[linecount] = line_name
160+
161+
# assign x values
150162
for i in range(mujoco.mjMAXLINEPNT):
151-
self.fig.linedata[self._line_counter][2*i] = float(i)
152-
self.fig.linepnt[self._line_counter] = 0
153-
self._line_counter+=1
163+
fig.linedata[linecount][2*i] = -float(i)
164+
165+
def add_data_to_line(self, line_name, line_data, fig_idx = 0):
166+
fig = self.figs[fig_idx]
154167

155-
def update_graph_line(self, line_name, line_data):
156168
try:
157169
_line_name = line_name.encode('utf8')
158-
linenames = self.fig.linename.tolist()
170+
linenames = fig.linename.tolist()
159171
line_idx = linenames.index(_line_name)
160172
except ValueError:
161173
raise Exception(
162174
"line name is not valid, add it to list before calling update"
163175
)
164176

165-
_x = self.fig.linepnt[line_idx]
166-
167-
if _x < mujoco.mjMAXLINEPNT:
168-
self.fig.linedata[line_idx][2*_x] = _x
169-
self.fig.linedata[line_idx][2*_x + 1] = float(line_data)
170-
self.fig.linepnt[line_idx] += 1
171-
else:
172-
for i in range(mujoco.mjMAXLINEPNT-1):
173-
self.fig.linedata[line_idx][2*i+1] = self.fig.linedata[line_idx][2*(i+1)+1]
174-
self.fig.linedata[line_idx][-1] = float(line_data)
175-
176-
def update_graph_size(self, size_div_x=None, size_div_y=None):
177-
if size_div_x is None and size_div_y is None:
178-
width, height = glfw.get_framebuffer_size(self.window)
179-
width_adjustment = width % 3
180-
self.graph_viewport.left = int(2 * width / 3) + width_adjustment
181-
self.graph_viewport.width = int(width / 3)
182-
self.graph_viewport.height = int(height / 3)
177+
pnt = min(201, fig.linepnt[line_idx] + 1)
178+
# shift data
179+
for i in range(pnt-1, 0, -1):
180+
fig.linedata[line_idx][2*i + 1] = fig.linedata[line_idx][2*i - 1]
183181

184-
else:
185-
assert size_div_x is not None and size_div_y is None, ""
186-
width, height = glfw.get_framebuffer_size(self.window)
187-
width_adjustment = width % size_div_x
188-
self.graph_viewport.left = (
189-
int((size_div_x - 1) * width / size_div_x) + width_adjustment
190-
)
191-
self.graph_viewport.width = int(width / size_div_x)
192-
self.graph_viewport.height = int(height / size_div_x)
182+
# assign new
183+
fig.linepnt[line_idx] = pnt;
184+
fig.linedata[line_idx][1] = line_data;
193185

194186
def add_marker(self, **marker_params):
195187
self._markers.append(marker_params)
@@ -400,8 +392,18 @@ def update():
400392
self._create_overlay()
401393

402394
render_start = time.time()
403-
self.viewport.width, self.viewport.height = glfw.get_framebuffer_size(
404-
self.window)
395+
396+
width, height = glfw.get_framebuffer_size(self.window)
397+
self.viewport.width, self.viewport.height = width, height
398+
399+
fig_w, fig_h = int(width / 4), int(height / 4)
400+
width_adjustment = width % 4
401+
for idx in range(len(self.figs_viewport)):
402+
x = int(3 * width / 4) + width_adjustment
403+
y = idx*fig_h
404+
vp = mujoco.MjrRect(x, y, fig_w, fig_h)
405+
self.figs_viewport[idx] = vp
406+
405407
with self._gui_lock:
406408
# update scene
407409
mujoco.mjv_updateScene(
@@ -434,10 +436,10 @@ def update():
434436

435437
# Handle graph and pausing interactions
436438
if not self._hide_graph:
437-
mujoco.mjr_figure(
438-
self.graph_viewport, self.fig, self.ctx
439-
)
440-
self.update_graph_size()
439+
for fig, viewport in zip(self.figs, self.figs_viewport):
440+
has_lines = len([i for i in fig.linename if i!=b''])
441+
if has_lines:
442+
mujoco.mjr_figure(viewport, fig, self.ctx)
441443

442444
glfw.swap_buffers(self.window)
443445
glfw.poll_events()

0 commit comments

Comments
 (0)