diff --git a/scripts/ztplot.py b/scripts/ztplot.py
new file mode 100755
index 0000000000000000000000000000000000000000..36cea5d2d2734eee54212334a59497a6957ceac6
--- /dev/null
+++ b/scripts/ztplot.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+# coding=utf-8
+# vim: ts=4 sw=4 et
+"""
+Creates z-t-plots for every DU.
+
+Usage:
+    ztplot.py [options]
+    ztplot.py (-h | --help)
+
+Options:
+    -l LIGIER_IP    The IP of the ligier [default: 127.0.0.1].
+    -p LIGIER_PORT  The port of the ligier [default: 5553].
+    -d DET_ID       Detector ID [default: 29].
+    -o PLOT_DIR     The directory to save the plot [default: plots].
+    -h --help       Show this screen.
+
+"""
+from __future__ import division
+
+from datetime import datetime
+from collections import deque
+import os
+import queue
+import shutil
+import time
+import threading
+
+import matplotlib
+# Force matplotlib to not use any Xwindows backend.
+matplotlib.use('Agg')
+import matplotlib.pyplot as plt
+import matplotlib.dates as md
+import matplotlib.ticker as ticker
+from matplotlib.colors import LogNorm
+import numpy as np
+
+import km3pipe as kp
+from km3pipe import Pipeline, Module
+from km3pipe.calib import Calibration
+from km3pipe.hardware import Detector
+from km3pipe.io import CHPump
+from km3pipe.io.daq import (DAQProcessor, DAQPreamble, DAQSummaryslice,
+                            DAQEvent)
+import km3pipe.style
+km3pipe.style.use('km3pipe')
+
+from km3pipe.logger import logging
+
+# for logger_name, logger in logging.Logger.manager.loggerDict.iteritems():
+#     if logger_name.startswith('km3pipe.'):
+#         print("Setting log level to debug for '{0}'".format(logger_name))
+#         logger.setLevel("DEBUG")
+
+# xfmt = md.DateFormatter('%Y-%m-%d %H:%M')
+lock = threading.Lock()
+
+
+class ZTPlot(Module):
+    def configure(self):
+        self.plots_path = self.require('plots_path')
+        det_id = self.require('det_id')
+        self.calib = kp.calib.Calibration(det_id=det_id)
+
+        self.run = True
+        self.max_queue = 3
+        self.queue = queue.Queue()
+        self.thread = threading.Thread(target=self.plot)
+        self.thread.start()
+
+    def process(self, blob):
+        if 'Hits' not in blob:
+            return blob
+
+        hits = blob['Hits'].serialise(to='pandas')
+        hits = self.calib.apply(hits)
+        event_info = blob['EventInfo']
+
+        if len(np.unique(hits[hits.triggered == True].du)) < 2:
+            print("Skipping...")
+            return blob
+
+        print("OK")
+        # print("Event queue size: {0}".format(self.queue.qsize()))
+        if self.queue.qsize() < self.max_queue:
+            self.queue.put((event_info, hits))
+
+        return blob
+
+    def plot(self):
+        while self.run:
+            try:
+                event_info, hits = self.queue.get(timeout=50)
+            except queue.Empty:
+                continue
+            with lock:
+                self.create_plot(event_info, hits)
+
+    def create_plot(self, event_info, hits):
+        print(self.__class__.__name__ + ": updating plot.")
+        dus = set(hits.du)
+
+        n_plots = len(dus)
+        n_cols = int(np.ceil(np.sqrt(n_plots)))
+        n_rows = int(n_plots / n_cols) + (n_plots % n_cols > 0)
+        fig, axes = plt.subplots(
+            ncols=n_cols,
+            nrows=n_rows,
+            sharex=True,
+            sharey=True,
+            figsize=(16, 8))
+
+        for ax, (du, du_hits) in zip(axes.flat, hits.groupby("du")):
+            trig_hits = du_hits[du_hits.triggered == True]
+
+            ax.scatter(du_hits.time, du_hits.pos_z, c='#09A9DE', label='hit')
+            ax.scatter(
+                trig_hits.time,
+                trig_hits.pos_z,
+                c='#FF6363',
+                label='triggered hit')
+            ax.set_title('DU{0}'.format(du), fontsize=16, fontweight='bold')
+
+        for ax in axes.flat:
+            ax.tick_params(labelsize=16)
+            ax.yaxis.set_major_locator(ticker.MultipleLocator(200))
+            xlabels = ax.get_xticklabels()
+            for label in xlabels:
+                label.set_rotation(45)
+
+        plt.suptitle(
+            "FrameIndex {0}, TriggerCounter {1}\n{2} UTC".format(
+                event_info.frame_index, event_info.trigger_counter,
+                datetime.utcfromtimestamp(event_info.utc_seconds)),
+            fontsize=16)
+        fig.text(0.5, 0.01, 'time [ns]', ha='center')
+        fig.text(0.08, 0.5, 'z [m]', va='center', rotation='vertical')
+        #        plt.tight_layout()
+
+        filename = 'ztplot'
+        f = os.path.join(self.plots_path, filename + '.png')
+        f_tmp = os.path.join(self.plots_path, filename + '_tmp.png')
+        plt.savefig(f_tmp, dpi=120, bbox_inches="tight")
+        plt.close('all')
+        shutil.move(f_tmp, f)
+
+    def finish(self):
+        self.run = False
+        if self.thread is not None:
+            self.thread.stop()
+
+
+def main():
+    from docopt import docopt
+    args = docopt(__doc__)
+
+    det_id = int(args['-d'])
+    plots_path = args['-o']
+    ligier_ip = args['-l']
+    ligier_port = int(args['-p'])
+
+    pipe = kp.Pipeline()
+    pipe.attach(
+        kp.io.ch.CHPump,
+        host=ligier_ip,
+        port=ligier_port,
+        tags='IO_EVT, IO_SUM',
+        timeout=60 * 60 * 24 * 7,
+        max_queue=2000)
+    pipe.attach(kp.io.daq.DAQProcessor)
+    pipe.attach(ZTPlot, det_id=det_id, plots_path=plots_path)
+    pipe.drain()
+
+
+if __name__ == '__main__':
+    main()