Repository: PrefectHQ/prefect

Issue:
Flow visualize optionally color by state
For local debugging, it could be useful for `flow.visualize()` to _optionally_ accept a flow state object, which will then be used to try and color the task-nodes (grey if a task state isn't available).  This is useful when understanding how / why / if certain triggers / states were propagated as expected.


Discussion:
This is a great idea
How do we feel about these colors?
```python
colors = {"Retrying": "#FFFF0080",                                                
                "CachedState": "orange",                                             
                "Pending": "lightgrey",                                              
                "Skipped": "honeydew",                                               
                "Success": "#00800080",                                              
                "Failed": "#FF0000BF",                                                     
                "TriggerFailed": "#F0808080",
                "Unknown": "#00000080",
            }
```
<img width="1284" alt="screen shot 2018-09-17 at 5 47 44 pm" src="https://user-images.githubusercontent.com/13255838/45658055-d15f8800-baa1-11e8-9a1c-9885c8939e95.png">

Great!

Resolving patch:
diff --git a/src/prefect/core/flow.py b/src/prefect/core/flow.py
--- a/src/prefect/core/flow.py
+++ b/src/prefect/core/flow.py
@@ -778,10 +778,12 @@ def run(
 
     # Visualization ------------------------------------------------------------
 
-    def visualize(self):
+    def visualize(self, flow_state=None):
         """
         Creates graphviz object for representing the current flow
 
+        Args:
+            - flow_state (State, optional): flow state object used to optionally color the nodes
         Raises:
             - ImportError: if `graphviz` is not installed
         """
@@ -795,13 +797,35 @@ def visualize(self):
             )
             raise ImportError(msg)
 
+        def get_color(task):
+            colors = {
+                "Retrying": "#FFFF0080",
+                "CachedState": "orange",
+                "Pending": "lightgrey",
+                "Skipped": "honeydew",
+                "Success": "#00800080",
+                "Failed": "#FF0000BF",
+                "TriggerFailed": "#F0808080",
+                "Unknown": "#00000080",
+            }
+            try:
+                state = flow_state.result.get(task)
+                return colors.get(type(state).__name__, "#00000080")
+            except:
+                return "#00000080"
+
         graph = graphviz.Digraph()
 
         for t in self.tasks:
             is_mapped = any(edge.mapped for edge in self.edges_to(t))
             shape = "box" if is_mapped else "ellipse"
             name = "{} <map>".format(t.name) if is_mapped else t.name
-            graph.node(str(id(t)), name, shape=shape)
+            kwargs = (
+                {}
+                if not flow_state
+                else dict(color=get_color(t), style="filled", colorscheme="svg")
+            )
+            graph.node(str(id(t)), name, shape=shape, **kwargs)
 
         for e in self.edges:
             style = "dashed" if e.mapped else None


Test patch: