Repository: dask/dask

Issue:
Consider better node label representation of dot_graph
Even after #556, `DataFrame` ops name is little long because of hash id. Thus, `dot_graph` output is little difficult to read. How about adding an keyword option to `dot_graph` which limit the max character length of nodes.
#### Current output (DataFrame.groupby().mean() with 2 partitions.

![index](https://cloud.githubusercontent.com/assets/1696302/9155154/84ceb97a-3ee9-11e5-800d-da57d86fa66c.png)

Would like to ask what the kw name and its default should be. My idea is  `label_length`, and its default is 20. It only touches operation name leaving partition number as it is.



Discussion:
We could also identify hash strings (match `[0-9a-f]{32}`) and replace them with a symbol like `#`.

I vote for replacing the hash with `#`. The only (potential) downside is that keys will repeat themselves in the graph if the same function is done more than once. But the shape of the graph is the important part.

I can take care of this tomorrow if no one beats me too it.  Looks like we call `str(dep)` at one point.  This should probably be a more interesting function.

Yes, replacing hash looks better idea than splitting by length.


Resolving patch:
diff --git a/dask/base.py b/dask/base.py
--- a/dask/base.py
+++ b/dask/base.py
@@ -9,7 +9,7 @@
 class Base(object):
     """Base class for dask collections"""
 
-    def visualize(self, filename=None, optimize_graph=False):
+    def visualize(self, filename='mydask', optimize_graph=False):
         from dask.dot import dot_graph
         if optimize_graph:
             dsk = self._optimize(self.dask, self._keys())
@@ -17,7 +17,7 @@ def visualize(self, filename=None, optimize_graph=False):
             dsk = self.dask
         return dot_graph(dsk, filename=filename)
 
-    def _visualize(self, filename=None, optimize_graph=False):
+    def _visualize(self, filename='mydask', optimize_graph=False):
         warn = DeprecationWarning("``_visualize`` is deprecated, use "
                                   "``visualize`` instead.")
         warnings.warn(warn)
diff --git a/dask/dot.py b/dask/dot.py
--- a/dask/dot.py
+++ b/dask/dot.py
@@ -1,5 +1,6 @@
 from __future__ import absolute_import, division, print_function
 
+import re
 from subprocess import check_call
 
 from graphviz import Digraph
@@ -55,6 +56,27 @@ def name(x):
     except TypeError:
         return str(hash(str(x)))
 
+def label(x):
+    """
+
+    >>> label('x')
+    'x'
+
+    >>> label(('x', 1))
+    "('x', 1)"
+
+    >>> from hashlib import md5
+    >>> x = 'x-%s-hello' % md5(b'1234').hexdigest()
+    >>> x
+    'x-81dc9bdb52d04dc20036dbd8313ed055-hello'
+
+    >>> label(x)
+    'x-#-hello'
+    """
+    s = str(x)
+    s = re.sub('[0-9a-z]{32}', '#', s)
+    return s
+
 
 def to_graphviz(dsk, data_attributes=None, function_attributes=None):
     if data_attributes is None:
@@ -70,7 +92,7 @@ def to_graphviz(dsk, data_attributes=None, function_attributes=None):
         k_name = name(k)
         if k_name not in seen:
             seen.add(k_name)
-            g.node(k_name, label=str(k), shape='box',
+            g.node(k_name, label=label(k), shape='box',
                    **data_attributes.get(k, {}))
 
         if istask(v):
@@ -85,7 +107,7 @@ def to_graphviz(dsk, data_attributes=None, function_attributes=None):
                 dep_name = name(dep)
                 if dep_name not in seen:
                     seen.add(dep_name)
-                    g.node(dep_name, label=str(dep), shape='box',
+                    g.node(dep_name, label=label(dep), shape='box',
                            **data_attributes.get(dep, {}))
                 g.edge(dep_name, func_name)
         elif ishashable(v) and v in dsk:


Test patch: