Repository: PrefectHQ/prefect

Issue:
Visualizations with mapping is not represented correctly
## Description
Below is a `flow` with `mapping`  The results of the `map` are read into another function `munge_dfs`  That `edge` is not defined in the visualization when using `flow_state` to visualize-- It is represented as some id.  It makes reading the visualization confusing.  And even more so with multiple maps in a flow

![image](https://user-images.githubusercontent.com/16763201/70157305-f3c7cc00-167a-11ea-843e-db75476c7b99.png)

**However** visualizing the flow without running it outputs the expected visualization
![image](https://user-images.githubusercontent.com/16763201/70157690-a009b280-167b-11ea-9d0e-2de32cc959d7.png)

## Reproduction
```
from prefect import Flow, Parameter, Task, task, unmapped
from prefect.tasks.control_flow import ifelse, merge



@task
def sum_list(num_list):
    return sum(num_list)
@task
def add_some_num(x, y):
    return x + y

@task
def multiply_num(x):
    return x*2

@task
def handle_value_error(some_param):
    return some_param

with Flow("map viz") as map_viz:
    input_num = Parameter("input_num", default=5)
    
    multiplied_num = multiply_num(input_num)

    is_ten = multiplied_num.is_equal(10)
    
    # Nums to map if input value equals 10
    numbers = [1, 2, 3]
    
    added_nums = add_some_num.map(
        x = unmapped(input_num),
        y = numbers
    )

    final_num = handle_value_error(input_num)
    ifelse(
        is_ten,
        added_nums,
        final_num
    )
    summed_nums = sum_list(added_nums)
    final_num = merge(summed_nums, final_num)

flow_state = map_viz.run()
map_viz.visualize(flow_state=flow_state)
```




## Environment
*Any additional information about your environment*



Discussion:
Thank you for the very clear and reproducible example!

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
@@ -1138,6 +1138,22 @@ def get_color(task: Task, map_index: int = None) -> str:
                         e.key,
                         style=style,
                     )
+            ## this edge represents a "reduce" step from a mapped task -> normal task
+            elif flow_state and flow_state.result[e.upstream_task].is_mapped():
+                assert isinstance(flow_state.result, dict)  # mypy assert
+                up_state = flow_state.result[e.upstream_task]
+
+                for map_index, _ in enumerate(up_state.map_states):
+                    downstream_id = str(id(e.downstream_task))
+                    if any(edge.mapped for edge in self.edges_to(e.downstream_task)):
+                        downstream_id += str(map_index)
+
+                    graph.edge(
+                        str(id(e.upstream_task)) + str(map_index),
+                        downstream_id,
+                        e.key,
+                        style=style,
+                    )
             else:
                 graph.edge(
                     str(id(e.upstream_task)),


Test patch:
diff --git a/tests/core/test_flow.py b/tests/core/test_flow.py
--- a/tests/core/test_flow.py
+++ b/tests/core/test_flow.py
@@ -1140,6 +1140,38 @@ def test_viz_reflects_mapping_if_flow_state_provided(self):
         for index in [0, 1]:
             assert "{0} [label=x style=dashed]".format(index) in graph.source
 
+    def test_viz_reflects_reduce_mapping_states_if_flow_state_provided(self):
+        ipython = MagicMock(
+            get_ipython=lambda: MagicMock(config=dict(IPKernelApp=True))
+        )
+        add = AddTask(name="a_nice_task")
+        list_task = Task(name="a_list_task")
+        reduce_task = AddTask(name="reduce")
+
+        map_state = Mapped(map_states=[Success(), Failed(), Success(), Success()])
+
+        with patch.dict("sys.modules", IPython=ipython):
+            with Flow(name="test") as f:
+                res = add.map(x=list_task, y=8)
+                final = reduce_task(res, y=9)
+
+            graph = f.visualize(
+                flow_state=Success(
+                    result={res: map_state, list_task: Success(), final: Success()}
+                )
+            )
+
+        print(graph.source)
+
+        # one colored node for each mapped result from its upstream
+        for index in [0, 1, 2, 3]:
+            assert "{0} [label=x style=dashed]".format(index) in graph.source
+
+        # one edge for each mapped result to the reduce task
+        for index in [0, 1]:
+            edge_string = "[label=x]".format(index)
+            assert graph.source.count(edge_string) == 4
+
     def test_viz_reflects_multiple_mapping_if_flow_state_provided(self):
         ipython = MagicMock(
             get_ipython=lambda: MagicMock(config=dict(IPKernelApp=True))