Repository: dask/dask

Issue:
dot_graph writes empty png
Following Jake VDP's [tutorial blog post](https://jakevdp.github.io/blog/2015/08/14/out-of-core-dataframes-in-python/), I am attempting to plot a dask graph. However, `dot_graph` plots an empty png. [Here is the example](https://gist.github.com/102830057075818bec2b). The resulting png file is zero bytes in size. As you can see, there is no exception raised.

Using dask 0.7.5 built from master on OS X 10.11, Anaconda Python 3.5. I've installed graphviz and pydot2 from pip.



Discussion:
@fonnesbeck can you verify that your graphviz system library works correctly?  E.g. can you try writing out a `.dot` file and then using the `dot` command line utility directly?

``` python
>>> # dot_graph(b2_min.dask, filename='b2_min.dot')
>>> b2_min.visualize(filename='b2_min.dot')  # perhaps nicer syntax
```

```
$ dot -Tpng b2_min.dot -o b2_min.png
```

Or, an alternative test would be to install graphviz with a tool like brew.

I have GV installed via brew:

```
$ brew install graphviz
Warning: graphviz-2.38.0 already installed
```

I mention the tests above because, when others ran into problems like this (cc @Carreau) it was because the system graphviz library was not compiled with libpng, and so the `dot` application failed on png files.  Perhaps you're running into a different problem though.  My intention with the questions above was to determine if this was the same issue.

You could also try visualizing with svg, which, if it works, would corroborate this theory.

``` python
import dask.array as da
da.ones(5, chunks=2).visualize(filename='foo.svg')
```

When I did export to a .dot file, I had the following in the terminal:

```
dyld: Library not loaded: /usr/lib/libltdl.7.dylib
  Referenced from: /Users/fonnescj/anaconda3/bin/dot
  Reason: image not found
```

Your `visualize` example fails with the following:

```
---------------------------------------------------------------------------
ExpatError                                Traceback (most recent call last)
<ipython-input-9-01f98d3386e3> in <module>()
      1 import dask.array as da
----> 2 da.ones(5, chunks=2).visualize(filename='foo.svg')

/Users/fonnescj/anaconda3/lib/python3.5/site-packages/dask/base.py in visualize(self, filename, format, optimize_graph, **kwargs)
     25                   **kwargs):
     26         return visualize(self, filename=filename, format=format,
---> 27                          optimize_graph=optimize_graph, **kwargs)
     28 
     29     def _visualize(self, filename='mydask', format=None, optimize_graph=False):

/Users/fonnescj/anaconda3/lib/python3.5/site-packages/dask/base.py in visualize(*args, **kwargs)
    125     dsk = merge(dsks)
    126 
--> 127     return dot_graph(dsk, filename=filename, **kwargs)
    128 
    129 

/Users/fonnescj/anaconda3/lib/python3.5/site-packages/dask/dot.py in dot_graph(dsk, filename, format, **kwargs)
    218         f.write(data)
    219 
--> 220     return _get_display_cls(format)(filename=full_filename)

/Users/fonnescj/anaconda3/lib/python3.5/site-packages/IPython/core/display.py in __init__(self, data, url, filename)
    384         self.filename = None if filename is None else unicode_type(filename)
    385 
--> 386         self.reload()
    387         self._check_data()
    388 

/Users/fonnescj/anaconda3/lib/python3.5/site-packages/IPython/core/display.py in reload(self)
    403         if self.filename is not None:
    404             with open(self.filename, self._read_flags) as f:
--> 405                 self.data = f.read()
    406         elif self.url is not None:
    407             try:

/Users/fonnescj/anaconda3/lib/python3.5/site-packages/IPython/core/display.py in data(self, svg)
    488         from xml.dom import minidom
    489         svg = cast_bytes_py2(svg)
--> 490         x = minidom.parseString(svg)
    491         # get svg tag (should be 1)
    492         found_svg = x.getElementsByTagName('svg')

/Users/fonnescj/anaconda3/lib/python3.5/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

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

/Users/fonnescj/anaconda3/lib/python3.5/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
```

I suspect that the graphviz executables in anaconda are broken (note that the python graphviz library is probably fine.)  I recommend uninstalling it and going with what brew would install.  Will raise an issue with Anaconda folk.

```
conda remove graphviz
```

Yup, that is the issue. Removing conda's graphviz fixed all the examples.

OK, sorry for the runaround.  If you have the time, a quick mention from you in the anaconda-issue linked above might help to get this issue resolved upstream.

Great, thanks for troubleshooting.

We should probably raise an informative error message if this occurs.


Resolving patch:
diff --git a/dask/dot.py b/dask/dot.py
--- a/dask/dot.py
+++ b/dask/dot.py
@@ -208,6 +208,13 @@ def dot_graph(dsk, filename='mydask', format=None, **kwargs):
         format = 'png'
 
     data = g.pipe(format=format)
+    if not data:
+        raise RuntimeError("Graphviz failed to properly produce an image. "
+                           "This probably means your installation of graphviz "
+                           "is missing png support. See: "
+                           "https://github.com/ContinuumIO/anaconda-issues/"
+                           "issues/485 for more information.")
+
     display_cls = _get_display_cls(format)
 
     if not filename:
@@ -217,4 +224,4 @@ def dot_graph(dsk, filename='mydask', format=None, **kwargs):
     with open(full_filename, 'wb') as f:
         f.write(data)
 
-    return _get_display_cls(format)(filename=full_filename)
+    return display_cls(filename=full_filename)


Test patch: