diff --git a/doc/reference.rst b/doc/reference.rst
index a1cb0efab031476bd469cbacea8b7112603e37d9..f2dad9056d2085213af6458c8eb2aac9b9fa78ca 100644
--- a/doc/reference.rst
+++ b/doc/reference.rst
@@ -374,6 +374,8 @@ following always works::
 
 .. autofunction:: get_dot_dependency_graph
 
+.. autofunction:: show_dependency_graph
+
 Flags
 -----
 
diff --git a/loopy/__init__.py b/loopy/__init__.py
index e1819f1f994969f29b545a0272016867bcc48f9b..301fae4d0c113c6e063b10cd4412233cf4221b8a 100644
--- a/loopy/__init__.py
+++ b/loopy/__init__.py
@@ -57,6 +57,7 @@ from loopy.kernel.data import (
 from loopy.kernel import LoopKernel
 from loopy.kernel.tools import (
         get_dot_dependency_graph,
+        show_dependency_graph,
         add_dtypes,
         add_and_infer_dtypes)
 from loopy.kernel.creation import make_kernel, UniqueName
@@ -95,7 +96,9 @@ __all__ = [
         "precompute",
         "split_arg_axis", "find_padding_multiple", "add_padding",
 
-        "get_dot_dependency_graph", "add_dtypes",
+        "get_dot_dependency_graph",
+        "show_dependency_graph",
+        "add_dtypes",
         "infer_argument_dtypes", "add_and_infer_dtypes",
 
         "preprocess_kernel", "realize_reduction", "infer_unknown_types",
diff --git a/loopy/kernel/__init__.py b/loopy/kernel/__init__.py
index 1ced7f2d66705467db7514fbbbb333ec49708680..a07d1b6107110b039e4ccd9a0605a9b51cfd0101 100644
--- a/loopy/kernel/__init__.py
+++ b/loopy/kernel/__init__.py
@@ -908,7 +908,8 @@ class LoopKernel(Record):
                 dep_lines.append("%s : %s" % (insn.id, ",".join(insn.insn_deps)))
         if dep_lines:
             lines.append(sep)
-            lines.append("DEPENDENCIES:")
+            lines.append("DEPENDENCIES: "
+                    "(use loopy.show_dependency_graph to visualize)")
             lines.extend(dep_lines)
 
         lines.append(sep)
diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py
index 57ca8890c29a3736da6db49905ebc6894a333504..b875cf117ba98ecf3e1af4d7ba1dbcec05822527 100644
--- a/loopy/kernel/tools.py
+++ b/loopy/kernel/tools.py
@@ -27,6 +27,7 @@ THE SOFTWARE.
 
 import numpy as np
 from islpy import dim_type
+from loopy.diagnostic import LoopyError
 
 import logging
 logger = logging.getLogger(__name__)
@@ -324,25 +325,106 @@ class DomainChanger:
 
 # {{{ graphviz / dot export
 
-def get_dot_dependency_graph(kernel, iname_cluster=False, iname_edge=True):
+def get_dot_dependency_graph(kernel, iname_cluster=True, use_insn_id=False):
+    """Return a string in the `dot <http://graphviz.org/>`_ language depicting
+    dependencies among kernel instructions.
+    """
+
+    # make sure all automatically added stuff shows up
+    from loopy import preprocess_kernel
+    kernel = preprocess_kernel(kernel)
+
+    if iname_cluster and not kernel.schedule:
+        from loopy.schedule import get_one_scheduled_kernel
+        kernel = get_one_scheduled_kernel(kernel)
+
+    dep_graph = {}
     lines = []
     for insn in kernel.instructions:
-        lines.append("%s [shape=\"box\"];" % insn.id)
+        if use_insn_id:
+            insn_label = insn.id
+        else:
+            insn_label = "%s <- %s" % (insn.assignee, insn.expression)
+
+        lines.append("\"%s\" [label=\"%s\",shape=\"box\",tooltip=\"%s\"];"
+                % (insn.id, repr(insn_label)[1:-1], insn.id))
         for dep in insn.insn_deps:
-            lines.append("%s -> %s;" % (dep, insn.id))
+            dep_graph.setdefault(insn.id, set()).add(dep)
+
+    # {{{ O(n^3) transitive reduction
+
+    # first, compute transitive closure by fixed point iteration
+    while True:
+        changed_something = False
+
+        for insn_1 in dep_graph:
+            for insn_2 in dep_graph.get(insn_1, set()).copy():
+                for insn_3 in dep_graph.get(insn_2, set()).copy():
+                    if insn_3 not in dep_graph.get(insn_1, set()):
+                        changed_something = True
+                        dep_graph[insn_1].add(insn_3)
+
+        if not changed_something:
+            break
 
-        if iname_edge:
-            for iname in kernel.insn_inames(insn):
-                lines.append("%s -> %s [style=\"dotted\"];" % (iname, insn.id))
+    for insn_1 in dep_graph:
+        for insn_2 in dep_graph.get(insn_1, set()).copy():
+            for insn_3 in dep_graph.get(insn_2, set()).copy():
+                if insn_3 in dep_graph.get(insn_1, set()):
+                    dep_graph[insn_1].remove(insn_3)
+
+    # }}}
+
+    for insn_1 in dep_graph:
+        for insn_2 in dep_graph.get(insn_1, set()):
+            lines.append("%s -> %s" % (insn_2, insn_1))
 
     if iname_cluster:
-        for iname in kernel.all_inames():
-            lines.append("subgraph cluster_%s { label=\"%s\" %s }" % (iname, iname,
-                " ".join(insn.id for insn in kernel.instructions
-                    if iname in kernel.insn_inames(insn))))
+        from loopy.schedule import EnterLoop, LeaveLoop, RunInstruction, Barrier
+
+        for sched_item in kernel.schedule:
+            if isinstance(sched_item, EnterLoop):
+                lines.append("subgraph cluster_%s { label=\"%s\""
+                        % (sched_item.iname, sched_item.iname))
+            elif isinstance(sched_item, LeaveLoop):
+                lines.append("}")
+            elif isinstance(sched_item, RunInstruction):
+                lines.append(sched_item.insn_id)
+            elif isinstance(sched_item, Barrier):
+                pass
+            else:
+                raise LoopyError("schedule item not unterstood: %r" % sched_item)
 
     return "digraph loopy_deps {\n%s\n}" % "\n".join(lines)
 
+
+def show_dependency_graph(*args, **kwargs):
+    """Show the dependency graph generated by :func:`get_dot_dependency_graph`
+    in a browser. Accepts the same arguments as that function.
+    """
+
+    dot = get_dot_dependency_graph(*args, **kwargs)
+
+    from tempfile import mkdtemp
+    temp_dir = mkdtemp(prefix="tmp_loppy_dot")
+
+    dot_file_name = "loopy.dot"
+
+    from os.path import join
+    with open(join(temp_dir, dot_file_name), "w") as dotf:
+        dotf.write(dot)
+
+    svg_file_name = "loopy.svg"
+    from subprocess import check_call
+    check_call(["dot", "-Tsvg", "-o", svg_file_name, dot_file_name],
+            cwd=temp_dir)
+
+    full_svg_file_name = join(temp_dir, svg_file_name)
+    logger.info("show_dot_dependency_graph: svg written to '%s'")
+
+    from webbrowser import open as browser_open
+    browser_open("file://" + full_svg_file_name)
+
 # }}}