diff --git a/tools/plot_task_level.py b/tools/plot_task_level.py
index 23e3ec878a2b8ef0f4d3c56d91ef75026e012de8..2fbe55c025db7f400aa009e488412475c9259630 100755
--- a/tools/plot_task_level.py
+++ b/tools/plot_task_level.py
@@ -1,47 +1,284 @@
-#!/usr/bin/python
-"""
+#!/usr/bin/env python3
+description = """
+Plot the number of tasks for each depth level and each type of task.
+
 Usage:
   ./plot_task_level.py task_level.txt
 
-Description:
-  Plot the number of tasks for each depth level and each type of task.
 """
 
 
 import pandas as pd
+import numpy as np
 import matplotlib.pyplot as plt
 import sys
+import argparse
+from os import path
+
+
+def parse_args():
+    """
+    Parses command line arguments.
+
+    Returns
+    -------
+
+    args: Namespace
+        Namespace returned by argparse.ArgumentParser.parse_args()
+        containing all arguments
+
+    files:
+        List of files parsed from the command line.
+
+    Raises
+    ------
+
+    FileNotFoundError
+        If the required filename provided on the command line doesn't exist
+    """
 
-# get filename
-filename = sys.argv[-1]
-
-# Column names
-names = ["type", "subtype", "depth", "count"]
-
-# read file
-data = pd.read_csv(filename, sep=" ", comment="#", names=names)
-
-# generate color map
-cmap = plt.get_cmap("hsv")
-N = data["depth"].max() + 5
-
-# plot data
-for i in range(data["depth"].max()):
-    ind = data["depth"] == i
-    label = "depth = %i" % i
-    c = cmap(i / N)
-    plt.plot(
-        data["type"][ind] + "_" + data["subtype"][ind],
-        data["count"][ind],
-        ".",
-        label=label,
-        color=c,
+    # description is string at the top of this file.
+    parser = argparse.ArgumentParser(description=description)
+
+    parser.add_argument(
+        "-c",
+        "--count",
+        dest="count_levels",
+        help="count on how many different levels the tasks can be found"
+        " and add it to the label",
+        action="store_true",
+    )
+
+    parser.add_argument(
+        "-d",
+        "--displace",
+        dest="displace",
+        help="attempt to displace overlapping point on the plot a bit"
+        " and try to make them visible",
+        action="store_true",
+    )
+
+    parser.add_argument(
+        "file",
+        type=str,
+        help="Required file name of .csv file(s) of the task levels "
+        "generated by swift.",
     )
 
-# modify figure parameters and show it
-plt.gca().set_yscale("log")
-plt.xticks(rotation=45)
-plt.ylabel("Number of Tasks")
-plt.gcf().subplots_adjust(bottom=0.15)
-plt.legend()
-plt.show()
+    args = parser.parse_args()
+    filename = args.file
+    print(filename)
+
+    if not path.exists(filename):
+        raise FileNotFoundError("File not found:'" + filename + "'")
+
+    return args, filename
+
+
+def read_data(filename):
+    """
+    Reads in data from the csv file.
+
+    Parameters
+    ----------
+
+    filename: str
+        filename to be read from
+
+
+    Returns
+    -------
+
+    data: pandas dataset
+        dataset containing read in data
+    """
+
+    # Column names
+    names = ["type", "subtype", "depth", "count"]
+
+    # read file
+    data = pd.read_csv(filename, sep=" ", comment="#", names=names)
+
+    return data
+
+
+def get_discrete_cmap(nentries):
+    """
+    Returns a discrete colormap.
+
+    Parameters
+    ----------
+
+    nentries: int
+        how many entries you want for your colormap
+
+
+    Returns
+    -------
+
+    cmap: list
+        list of colors
+
+
+    Raises
+    ------
+
+    IndexError:
+        When you want more entries than there are available.
+        Current maximum is 21.
+    """
+
+    fullcolorlist = [
+        "red",
+        "green",
+        "blue",
+        "gold",
+        "magenta",
+        "cyan",
+        "lime",
+        "saddlebrown",
+        "darkolivegreen",
+        "cornflowerblue",
+        "orange",
+        "dimgrey",
+        "navajowhite",
+        "darkslategray",
+        "mediumpurple",
+        "lightpink",
+        "mediumseagreen",
+        "maroon",
+        "midnightblue",
+        "silver",
+        "black",
+    ]
+
+    if nentries >= len(fullcolorlist) - 1:
+        raise IndexError(
+            "I can't handle more than 21 different colors."
+            "Add more manually in get_discrete_cmap() function"
+        )
+
+    return fullcolorlist[: nentries + 1]
+
+
+def add_levelcounts(data):
+    """
+    Adds a column to the data with the counts on how many levels a given task
+    is executed on.
+
+    Parameters
+    ----------
+
+    data: pandas dataframe
+        The dataframe to use
+
+    Returns
+    -------
+
+    data: pandas dataframe
+        the modified dataframe
+    """
+
+    # add new column
+    data["nlevels"] = ["1" for _ in range(data.shape[0])]
+
+    # count on how many levels each task exists
+    for i, (ttype, tsubtype) in enumerate(zip(data["type"], data["subtype"])):
+        istype = data["type"] == ttype
+        issubtype = data["subtype"] == tsubtype
+        isthis = np.logical_and(istype, issubtype)
+        count = np.count_nonzero(isthis)
+        data.at[i, "nlevels"] = str(count)
+
+    return data
+
+
+def add_displacement(data):
+    """
+    Add small displacements to the task number counts and try
+    to make them better visible
+
+    Parameters
+    ----------
+
+    data: pandas dataframe
+        the data to be modified
+
+
+    Returns
+    -------
+
+    data: pandas dataframe
+        the modified data
+    """
+    # add new column
+    data["yvals"] = data["count"] * 1.0
+    data["yval_modified"] = False
+    inds = np.arange(0, data.shape[0])
+
+    # count on how many levels each task exists
+    for i, (ttype, tsubtype) in enumerate(zip(data["type"], data["subtype"])):
+        if data["yval_modified"][i]:
+            continue
+        istype = data["type"] == ttype
+        issubtype = data["subtype"] == tsubtype
+        isthis = np.logical_and(istype, issubtype)
+        uniques = np.unique(data["count"][isthis])
+        for u in uniques:
+            occurances = np.count_nonzero(data["count"][isthis] == u)
+            for o in range(occurances):
+                thisind = inds[isthis][o]
+                step = 0.05 * max(int(np.log10(u) + 0.5), 1) * o * (-1) ** o
+                data.at[thisind, "yvals"] += step
+                data.at[thisind, "yval_modified"] = True
+
+    return data
+
+
+if __name__ == "__main__":
+
+    args, filename = parse_args()
+
+    data = read_data(filename)
+    cmap = get_discrete_cmap(data["depth"].max())
+
+    # are we counting the levels?
+    if args.count_levels:
+        data = add_levelcounts(data)
+
+    # are we displacing the particles on the y axis?
+    if args.displace:
+        data = add_displacement(data)
+
+    # plot data
+    for i in range(data["depth"].max() + 1):
+        ind = data["depth"] == i
+        label = "depth = {0:d}".format(i)
+
+        if args.count_levels:
+            xvals = (
+                data["type"][ind]
+                + "_"
+                + data["subtype"][ind]
+                + "["
+                + data["nlevels"][ind]
+                + "]"
+            )
+        else:
+            xvals = data["type"][ind] + "_" + data["subtype"][ind]
+
+        if args.displace:
+            yvals = data["yvals"][ind]
+        else:
+            yvals = data["count"][ind]
+        c = cmap[i]
+        plt.plot(xvals, yvals, "o", label=label, color=c, alpha=0.7)
+
+    # modify figure parameters and show it
+    plt.gca().set_yscale("log")
+    plt.xticks(rotation=90)
+    plt.ylabel("Number of Tasks")
+    plt.gcf().subplots_adjust(bottom=0.225)
+    plt.legend()
+    plt.grid()
+    plt.show()