Skip to content

Displaying GraphViz dotfile of robot description fails in jupyter notebook #505

@siggmo

Description

@siggmo

Describe the bug
First of all, thanks a lot for this fantastic toolbox! I just found out about the possibility to generate dotfiles and visualize the structure of a robot. I tried this notebook from the official GitHub: https://github.com/petercorke/robotics-toolbox-python/blob/master/notebooks/branched-robot.ipynb. However, displaying the generated SVG file fails unfortunately.

It happens here:

from IPython.core.display import SVG

robot.dotfile('planar_y.dot')
!dot -Tsvg planar_y.dot -x > planar_y.svg
display(SVG(filename='planar_y.svg'))

I'm not very familiar with XML in python, but claude.ai says: The roboticstoolbox appears to be monkey-patching or overriding XML writing functionality, but it's using an outdated call signature for _write_data(). In newer versions of Python's minidom, _write_data() expects three arguments, but the code is only providing two.

An alternative way to display the SVG works:

from IPython.display import display, HTML
with open('planar_y.svg', 'r') as f:
    svg_content = f.read()
display(HTML(svg_content))

So it's not a big deal at all, I just wanted to document it here, maybe someone is facing it as well.

Version information
I installed the toolbox using pip.

Python version: 3.13.7
rbt version: 1.1.1
numpy version: 1.26.4

To Reproduce
Steps to reproduce the behavior:
Create a new venv:

python -m venv .venv
. .venv/Scripts/activate
pip install numpy==1.26.4 roboticstoolbox-python
  1. The shortest, complete, Python script that exhibits the bug.
    In JupyterLab or VS Code, create a new notebook with this code:
import roboticstoolbox as rtb
from IPython.core.display import SVG

robot = rtb.models.ETS.Planar_Y()
robot.dotfile('planar_y.dot')
!dot -Tsvg planar_y.dot -x > planar_y.svg
SVG(filename='planar_y.svg')
  1. The script output, including error messages.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[1], line 7
      5 robot.dotfile('planar_y.dot')
      6 get_ipython().system('dot -Tsvg planar_y.dot -x > planar_y.svg')
----> 7 SVG(filename='planar_y.svg')

File c:\Data\rbt_bugreport\.venv\Lib\site-packages\IPython\core\display.py:343, in DisplayObject.__init__(self, data, url, filename, metadata)
    340 elif self.metadata is None:
    341     self.metadata = {}
--> 343 self.reload()
    344 self._check_data()

File c:\Data\rbt_bugreport\.venv\Lib\site-packages\IPython\core\display.py:370, in DisplayObject.reload(self)
    368     encoding = None if "b" in self._read_flags else "utf-8"
    369     with open(self.filename, self._read_flags, encoding=encoding) as f:
--> 370         self.data = f.read()
    371 elif self.url is not None:
    372     # Deferred import
    373     from urllib.request import urlopen

File c:\Data\rbt_bugreport\.venv\Lib\site-packages\IPython\core\display.py:511, in SVG.data(self, svg)
    509 found_svg = x.getElementsByTagName('svg')
    510 if found_svg:
--> 511     svg = found_svg[0].toxml()
    512 else:
    513     # fallback on the input, trust the user
    514     # but this is probably an error.
    515     pass

File ~\scoop\apps\python\current\Lib\xml\dom\minidom.py:47, in Node.toxml(self, encoding, standalone)
     46 def toxml(self, encoding=None, standalone=None):
---> 47     return self.toprettyxml("", "", encoding, standalone)

File ~\scoop\apps\python\current\Lib\xml\dom\minidom.py:62, in Node.toprettyxml(self, indent, newl, encoding, standalone)
     60     self.writexml(writer, "", indent, newl, encoding, standalone)
     61 else:
---> 62     self.writexml(writer, "", indent, newl)
     63 if encoding is None:
     64     return writer.getvalue()

File c:\Data\rbt_bugreport\.venv\Lib\site-packages\roboticstoolbox\tools\xacro\xmlutils.py:124, in fixed_writexml(self, writer, indent, addindent, newl)
    122 for a_name in a_names:
    123     writer.write(" %s=\"" % a_name)
--> 124     xml.dom.minidom._write_data(writer, attrs[a_name].value)
    125     writer.write("\"")
    126 if self.childNodes:

TypeError: _write_data() missing 1 required positional argument: 'attr'

Expected behavior
The SVG should be displayed in the notebook. The is nothing wrong with the SVG file itself, you can verify it using this alternative displaying method:

from IPython.display import display, HTML
with open('planar_y.svg', 'r') as f:
    svg_content = f.read()
display(HTML(svg_content))

Environment (please complete the following information):

  • Windows 11
  • Python 3.13.7

Additional context
Here is the full output of pip freeze:

ansitable==0.11.4
asttokens==3.0.0
cfgv==3.4.0
colorama==0.4.6
colored==2.3.1
comm==0.2.3
contourpy==1.3.3
cycler==0.12.1
debugpy==1.8.17
decorator==5.2.1
distlib==0.4.0
executing==2.2.1
filelock==3.20.0
fonttools==4.60.1
identify==2.6.15
ipykernel==7.1.0
ipython==9.7.0
ipython_pygments_lexers==1.1.1
jedi==0.19.2
jupyter_client==8.6.3
jupyter_core==5.9.1
kiwisolver==1.4.9
matplotlib==3.10.7
matplotlib-inline==0.2.1
nest-asyncio==1.6.0
nodeenv==1.9.1
numpy==1.26.4
packaging==25.0
parso==0.8.5
pgraph-python==0.6.3
pillow==12.0.0
platformdirs==4.5.0
pre_commit==4.4.0
progress==1.6.1
prompt_toolkit==3.0.52
psutil==7.1.3
pure_eval==0.2.3
Pygments==2.19.2
pyparsing==3.2.5
python-dateutil==2.9.0.post0
PyYAML==6.0.3
pyzmq==27.1.0
roboticstoolbox-python==1.1.1
rtb-data==1.0.1
scipy==1.16.3
six==1.17.0
spatialgeometry==1.1.0
spatialmath-python==1.1.15
stack-data==0.6.3
swift-sim==1.1.0
tornado==6.5.2
traitlets==5.14.3
typing_extensions==4.15.0
virtualenv==20.35.4
wcwidth==0.2.14
websockets==15.0.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions