Using matplotlib in a ros node in docker

asked 2020-01-18 02:52:44 -0600

roboticslife gravatar image

updated 2022-01-22 16:10:15 -0600

Evgeny gravatar image

Hello,

I am running a ros node (melodic) inside docker with python3, and I am having trouble with matplotlib.

tl;dr: I cannot get the TkAgg backend for matplotlib to work inside the rosnode. Switching to the Agg backend avoids an error but does not display the plot.

More details / what I have tried:

My node subscribes to several topics, does some processing on them, and then updates a plot with the values. It is similar to the accepted answer in https://answers.ros.org/question/2647....

My first attempt I used import matplotlib.pyplot as plt and after creating the plot called plt.show(). The opened the plot window, but later when I tried to use plt.draw() and plt.pause(0.00000000001) to update nothing happened.

I though it must be because the show command is blocking, so I tried changing it to plt.show(block=False). However, this gave me the following error:

[ERROR] [1579336272.270732, 1573680615.824510]: bad callback: <bound method plot_6dof.ado_pose_gt_cb of <__main__.plot_6dof object at 0x7ff551d299b0>>
Traceback (most recent call last):
  File "/opt/ros/melodic/lib/python2.7/dist-packages/rospy/topics.py", line 750, in _invoke_callback cb(msg)
  File "/root/msl_raptor_ws/src/msl_raptor/src/viz_tools/plot_6dof.py", line 78, in ado_pose_gt_cb self.update_plot()
  File "/root/msl_raptor_ws/src/msl_raptor/src/viz_tools/plot_6dof.py", line 150, in update_plot plt.pause(0.0000001)
  File "/usr/local/lib/python3.6/dist-packages/matplotlib/pyplot.py", line 295, in pause show(block=False)
  File "/usr/local/lib/python3.6/dist-packages/matplotlib/pyplot.py", line 253, in show return _show(*args, **kw)
  File "/usr/local/lib/python3.6/dist-packages/matplotlib/backend_bases.py", line 192, in show manager.show()
  File "/usr/local/lib/python3.6/dist-packages/matplotlib/backends/_backend_tk.py", line 551, in show ile "/usr/lib/python3.6/tkinter/__init__.py", line 1788, in wm_attributes return self.tk.call(args)
RuntimeError: main thread is not in main loop

After some googling I came across a link about using matplotlib in a virtualenv https://www.pyimagesearch.com/2015/08... and I thought I had the answer. I changed my backend to Agg, and this did mean I stopped getting the error but no plot ever appears (for plt.show() or plt.show(block=False)).

When using the bash in the container, I tried a quick test of running the python3 interpreter, importing matplotlib.pyplot as plt and making a simple plot. Using the TkAgg backend I can display a plot with blocking or without. Using the Agg backend I cannot get any plot to display.

Thanks in advance for the help!

edit retag flag offensive close merge delete

Comments

I am running a ros node (melodic) inside docker with python3,

did you build Melodic for use with Python 3? Because the traceback shows mixing of Python 2 and 3 modules, which is usually not a good idea.

gvdhoorn gravatar image gvdhoorn  ( 2020-01-18 04:25:03 -0600 )edit

I did build using python3. I noticed the 2.7 in the traceback which might indicate the issue. I am going to try to recreate the problem in a new docker / melodic container now using python 2 to see if I still have an issue.

EDIT: I am still having trouble with the plotting, even in my dummy docker container using just python2. I am thinking the issue is not the python 2 in the traceback, especially since everything else about the ros install seems to work.

roboticslife gravatar image roboticslife  ( 2020-01-18 11:39:17 -0600 )edit

Mixing Py2 and Py3 like that is still not a good idea, regardless of whether things seem to work or not.

In any case: it could be the TkAgg backend requires access to a display server, and your Docker container doesn't provide it.

How are you starting your container?

gvdhoorn gravatar image gvdhoorn  ( 2020-01-20 02:36:11 -0600 )edit

I am starting docker with the following command

docker run -it --gpus all --privileged --env-file /docker/.env --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" -env="XAUTHORITY=$XAUTH" --volume="$XAUTH:$XAUTH" --runtime=nvidia --network host my_docker_file:latest bash

I can confirm my .env file sets the DISPLAY variable correctly and that QT_X11_NO_MITSHM is set to 1. I was following this link for gui stuff (https://wiki.ros.org/docker/Tutorials...). Other applications (like xclock & rviz) work correctly. The pyplot window even appears when I run it from the interpreter. It is only the combination of ros & plotting that doesn't work.

roboticslife gravatar image roboticslife  ( 2020-01-20 10:22:41 -0600 )edit