calling graph_draw with SVG format and inline=True throws expat error

Bug report

  • Are you running the latest graph-tool version?
  • Do you observe the problem with the current git version?
  • Are you using Macports or Homebrew?
  • Did you compile graph-tool manually?
  • If you answered yes above, did you use the exact same compiler to build graph-tool, boost-python and Python?

Problem

When calling graph_draw(...) with SVG output and inline=True (e.g. when running inside a Jupyter notebook), there is an ExpatError. It seems that IPython receives an empty string (see sections below). It works fine for other formats (PNG,PDF,PS).

System Information

  • OS: Ubuntu bionic
  • Python version: 3.6.5
  • gcc version: 7.3.0
  • boost version: 1.65.1
  • expat version: 2.2.5-3
  • graph-tool master branch

Steps to reproduce

Run the filter example from Quickstart in a Jupyter notebook:

g, pos = triangulation(random((500, 2)) * 4, type="delaunay")
tree = min_spanning_tree(g)
graph_draw(g, pos=pos, edge_color=tree, output="min_tree.svg")

Error log

ExpatError                                Traceback (most recent call last)
<ipython-input-20-4117cea68eac> in <module>()
      1 g, pos = triangulation(random((500, 2)) * 4, type="delaunay")
      2 tree = min_spanning_tree(g)
----> 3 graph_draw(g, pos=pos, edge_color=tree, output="min_tree.svg")

/usr/lib/python3/dist-packages/graph_tool/draw/cairo_draw.py in graph_draw(g, pos, vprops, eprops, vorder, eorder, nodesfirst, output_size, fit_view, inline, mplfig, output, fmt, **kwargs)
   1195                 img = IPython.display.Image(data=out.getvalue())
   1196             if fmt == "svg":
-> 1197                 img = IPython.display.SVG(data=out.getvalue())
   1198             if img is None:
   1199                 inl_out = io.BytesIO()

/usr/local/lib/python3.6/dist-packages/IPython/core/display.py in __init__(self, data, url, filename, metadata)
    598                 data = None
    599 
--> 600         self.data = data
    601         self.url = url
    602         self.filename = filename

/usr/local/lib/python3.6/dist-packages/IPython/core/display.py in data(self, svg)
    719         # parse into dom object
    720         from xml.dom import minidom
--> 721         x = minidom.parseString(svg)
    722         # get svg tag (should be 1)
    723         found_svg = x.getElementsByTagName('svg')

/usr/lib/python3.6/xml/dom/minidom.py in parseString(string, parser)
   1966     if parser is None:
   1967         from xml.dom import expatbuilder
-> 1968         return expatbuilder.parseString(string)
   1969     else:
   1970         from xml.dom import pulldom

/usr/lib/python3.6/xml/dom/expatbuilder.py in parseString(string, namespaces)
    923     else:
    924         builder = ExpatBuilder()
--> 925     return builder.parseString(string)
    926 
    927 

/usr/lib/python3.6/xml/dom/expatbuilder.py in parseString(self, string)
    221         parser = self.getParser()
    222         try:
--> 223             parser.Parse(string, True)
    224             self._setup_subset(string)
    225         except ParseEscape:

ExpatError: no element found: line 1, column 0

Possible reason

As the log describes, the problem is that the issue resides on line 1197 of cairo_draw.py. I've reproduced the same error message by sending an empty string: Screenshot_20180515_183127

Conversely, it does not fail by sending a well-formed SVG string: Screenshot_20180515_182918