diff --git a/bob/extension/scripts/__init__.py b/bob/extension/scripts/__init__.py
index 60b3f6d43e89d1f4dfbe246105d1e47f1a23021c..4b9f68dec6a521b9d90c5e3f5b9f38a7e8561580 100644
--- a/bob/extension/scripts/__init__.py
+++ b/bob/extension/scripts/__init__.py
@@ -1,4 +1,5 @@
 from .new_version import main as new_version
+from .dependency_graph import main as dependency_graph
 
 # gets sphinx autodoc done right - don't remove it
 __all__ = [_ for _ in dir() if not _.startswith('_')]
diff --git a/bob/extension/scripts/dependency_graph.py b/bob/extension/scripts/dependency_graph.py
new file mode 100644
index 0000000000000000000000000000000000000000..792e1817d1f7e1c243e7e154ec765775aedde4a3
--- /dev/null
+++ b/bob/extension/scripts/dependency_graph.py
@@ -0,0 +1,127 @@
+#!../bin/python
+
+
+#!/usr/bin/env python
+
+from __future__ import print_function
+import subprocess
+import pkg_resources
+import tempfile, os
+
+import argparse
+
+def main(command_line_options = None):
+  """
+  This script will generate a dependency graph of the given bob package(s) using the external tool ``dot``.
+  Packages can be either specified as a list of ``--packages`` or read from (several) ``--package-files``.
+  The latter option is mostly useful to generate a dot graph for all Bob packages.
+  
+  The output is written to the given ``--output-file``, writing either the specified intermediate ``--dot-file``, or a temporary file.
+  When the ``--plot-external-dependencies`` is selected, also external (Python-)dependencies will be plotted as well, in red ellipses.
+  """
+
+  parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
+
+  parser.add_argument("--packages", '-p', nargs = '+', default = [], help = "Which packages do you want to have dependencies for?")
+  parser.add_argument("--package-files", '-P', nargs = '+', default = [], help = "Read packages from the given files (usually requirement?.txt files of bob).")
+  parser.add_argument("--dot-file", "-W", help = "If specified, the .dot file is written to the given file.")
+  parser.add_argument("--output-file", "-w", default="dependencies.png", help = "Specify the (.png) file to write.")
+  parser.add_argument("--limit-packages", '-l', nargs = '+', default = ['bob', 'facereclib', 'antispoofing'], help = "Limit packages read from --package-files to the given namespaces")
+  parser.add_argument("--plot-external-dependencies", '-X', action='store_true', help = "Include external dependencies into the plot?")
+  parser.add_argument("--rank-base-tools-same", '-R', action = 'store_true', help = "Set the rank of packages bob.extension, bob.core and bob.blitz at the same size")
+  parser.add_argument("--vertical", '-V', action = 'store_true', help = "Display the dot graph in vertical direction")
+  parser.add_argument("--verbose", '-v', action = 'store_true', help = "Print more information")
+
+  args = parser.parse_args(command_line_options)
+
+
+  # collect packages
+  packages = args.packages[:]
+  for package_file in args.package_files:
+    for line in open(package_file):
+      splits = line.rstrip().split()
+      packages.extend([p for p in splits if p not in packages and p.startswith(tuple(args.limit_packages))])
+      
+  # generate dependencies
+  dependencies = {}
+  has_parents = set()
+
+  # function to add dependencies of packages recursively
+  def _add_recursive(p):
+    # check if package already parsed
+    if p not in dependencies:
+      if args.verbose:
+        print("Checking %s" % p)
+      deps = pkg_resources.require(p)
+      dependencies[p] = [d.key for d in deps[1:]]
+      for d in dependencies[p]:
+        has_parents.add(d)
+        _add_recursive(d)
+    
+  for package in packages:
+    _add_recursive(package)
+
+  # prune dependencies
+  pruned_dependencies = {}
+  for package in dependencies:
+    indirect_dependencies = set(d for i in [dependencies[dep] for dep in dependencies[package] if dep in dependencies] for d in i)
+    pruned_dependencies[package] = [dep for dep in dependencies[package] if dep not in indirect_dependencies]
+
+  # split all dependencies that are from bob (i.e., that belong to the --limit-packages) or not
+  bob = set(package for package in pruned_dependencies if package.startswith(tuple(args.limit_packages)))
+  non_bob = set(dep for package in bob for dep in pruned_dependencies[package] if not dep.startswith(tuple(args.limit_packages)))
+  final = set(package for package in bob if package not in has_parents)
+  
+
+  # function to return a name for the package that can serve as a dot variable
+  def _n(p):
+    return p.replace(".", "_").replace("-","_")
+
+  # write dependency graph
+  dot_file = args.dot_file if args.dot_file is not None else tempfile.mkstemp(suffix='.dot')[1]
+  with open(dot_file, 'w') as f:
+    # open plot
+    f.write("digraph Bob {\n")
+    if not args.vertical:
+      f.write("\trankdir=LR;\n")
+    # write bob packages in squares
+    for package in bob:
+      f.write('\t%s [label="%s",shape=box,group=%s,style=filled,color=%s];\n' % (_n(package), package, "_".join(package.split('.')[:2]), 'green' if package in final else 'lightblue'))
+
+    # write non-bob packages in squares
+    if args.plot_external_dependencies:
+      for package in non_bob:
+        f.write('\t%s [label="%s",color=red];\n' % (_n(package), package))
+
+    # write dependencies
+    for package in bob:
+      for dep in pruned_dependencies[package]:
+        if dep in bob:
+          f.write('\t%s -> %s [color=blue];\n' % (_n(package), _n(dep)))
+        elif args.plot_external_dependencies:
+          f.write('\t%s -> %s [color=red,style=dashed];\n' % (_n(package), _n(dep)))
+        
+    # rank all externals at the same level
+    if args.plot_external_dependencies:
+      f.write('\t{rank=same; %s }\n' % " ".join([_n(p) for p in non_bob]))
+    # rank base tools at the same level
+    if args.rank_base_tools_same:
+      f.write('\t{rank=same; bob_extension bob_core bob_blitz}\n')
+    f.write("}\n")
+  
+  if args.verbose and args.dot_file is not None:
+    print("Wrote dot file %s" % dot_file)
+    
+  # call dot
+  call = ["dot",  '-y', '-o', args.output_file, '-Tpng:cairo:gd', dot_file]
+  if args.verbose:
+    call[1:1] = ['-v']
+    print("Calling dot: '%s'" % " ".join(call))
+  subprocess.call(call)
+  
+  if args.verbose:
+    print("\nWrote file %s" % args.output_file)
+  
+  # clean-up
+  if args.dot_file is None:
+    os.remove(dot_file)
diff --git a/setup.py b/setup.py
index 88d940683f273e6e8d23b8b65cc88383e94bd2e0..5c389e3d37f5d8b88da7ca44e0fb7fd03cf786a8 100644
--- a/setup.py
+++ b/setup.py
@@ -40,6 +40,7 @@ setup(
     entry_points = {
       'console_scripts': [
         'bob_new_version.py = bob.extension.scripts:new_version',
+        'bob_dependecy_graph.py = bob.extension.scripts:dependency_graph',
       ],
     },