@@ -70,9 +70,23 @@ def __init__(
7070 self .cam = mujoco .MjvCamera ()
7171 self .scn = mujoco .MjvScene (self .model , maxgeom = 10000 )
7272 self .pert = mujoco .MjvPerturb ()
73+
7374 self .ctx = mujoco .MjrContext (
7475 self .model , mujoco .mjtFontScale .mjFONTSCALE_150 .value )
7576
77+ width , height = glfw .get_framebuffer_size (self .window )
78+
79+ # figures for creating 2D plots
80+ max_num_figs = 3
81+ self .figs = []
82+ width_adjustment = width % 4
83+ fig_w , fig_h = int (width / 4 ), int (height / 4 )
84+ for idx in range (max_num_figs ):
85+ fig = mujoco .MjvFigure ()
86+ mujoco .mjv_defaultFigure (fig )
87+ fig .flg_extend = 1
88+ self .figs .append (fig )
89+
7690 # load camera from configuration (if available)
7791 pathlib .Path (
7892 self .CONFIG_PATH .parent ).mkdir (
@@ -118,6 +132,51 @@ def __init__(
118132 self ._overlay = {}
119133 self ._markers = []
120134
135+ def add_line_to_fig (self , line_name , fig_idx = 0 ):
136+ assert isinstance (line_name , str ), \
137+ "Line name must be a string."
138+
139+ fig = self .figs [fig_idx ]
140+ if line_name .encode ('utf8' ) == b'' :
141+ raise Exception (
142+ "Line name cannot be empty."
143+ )
144+ if line_name .encode ('utf8' ) in fig .linename :
145+ raise Exception (
146+ "Line name already exists in this plot."
147+ )
148+
149+ # this assumes all lines added by user have a non-empty name
150+ linecount = fig .linename .tolist ().index (b'' )
151+
152+ # we want to add the line after the last non-empty index
153+ fig .linename [linecount ] = line_name
154+
155+ # assign x values
156+ for i in range (mujoco .mjMAXLINEPNT ):
157+ fig .linedata [linecount ][2 * i ] = - float (i )
158+
159+ def add_data_to_line (self , line_name , line_data , fig_idx = 0 ):
160+ fig = self .figs [fig_idx ]
161+
162+ try :
163+ _line_name = line_name .encode ('utf8' )
164+ linenames = fig .linename .tolist ()
165+ line_idx = linenames .index (_line_name )
166+ except ValueError :
167+ raise Exception (
168+ "line name is not valid, add it to list before calling update"
169+ )
170+
171+ pnt = min (mujoco .mjMAXLINEPNT , fig .linepnt [line_idx ] + 1 )
172+ # shift data
173+ for i in range (pnt - 1 , 0 , - 1 ):
174+ fig .linedata [line_idx ][2 * i + 1 ] = fig .linedata [line_idx ][2 * i - 1 ]
175+
176+ # assign new
177+ fig .linepnt [line_idx ] = pnt ;
178+ fig .linedata [line_idx ][1 ] = line_data ;
179+
121180 def add_marker (self , ** marker_params ):
122181 self ._markers .append (marker_params )
123182
@@ -205,6 +264,10 @@ def add_overlay(gridpos, text1, text2):
205264 topleft ,
206265 "[J]oints" ,
207266 "On" if self ._joints else "Off" )
267+ add_overlay (
268+ topleft ,
269+ "[G]raph Viewer" ,
270+ "Off" if self ._hide_graph else "On" )
208271 add_overlay (
209272 topleft ,
210273 "[I]nertia" ,
@@ -295,7 +358,6 @@ def read_pixels(self, camid=None, depth=False):
295358 mujoco .mjr_render (self .viewport , self .scn , self .ctx )
296359 shape = glfw .get_framebuffer_size (self .window )
297360
298-
299361 if depth :
300362 rgb_img = np .zeros ((shape [1 ], shape [0 ], 3 ), dtype = np .uint8 )
301363 depth_img = np .zeros ((shape [1 ], shape [0 ], 1 ), dtype = np .float32 )
@@ -324,8 +386,10 @@ def update():
324386 self ._create_overlay ()
325387
326388 render_start = time .time ()
327- self .viewport .width , self .viewport .height = glfw .get_framebuffer_size (
328- self .window )
389+
390+ width , height = glfw .get_framebuffer_size (self .window )
391+ self .viewport .width , self .viewport .height = width , height
392+
329393 with self ._gui_lock :
330394 # update scene
331395 mujoco .mjv_updateScene (
@@ -355,6 +419,20 @@ def update():
355419 t1 ,
356420 t2 ,
357421 self .ctx )
422+
423+ # handle figures
424+ if not self ._hide_graph :
425+ for idx , fig in enumerate (self .figs ):
426+ width_adjustment = width % 4
427+ x = int (3 * width / 4 ) + width_adjustment
428+ y = idx * int (height / 4 )
429+ viewport = mujoco .MjrRect (
430+ x , y , int (width / 4 ), int (height / 4 ))
431+
432+ has_lines = len ([i for i in fig .linename if i != b'' ])
433+ if has_lines :
434+ mujoco .mjr_figure (viewport , fig , self .ctx )
435+
358436 glfw .swap_buffers (self .window )
359437 glfw .poll_events ()
360438 self ._time_per_render = 0.9 * self ._time_per_render + \
0 commit comments