diff --git a/scripts/tsplot.py b/scripts/tsplot.py
index 7cf0dcf744a933cdf59d2262a160a6cec9636a4d..3a811da152bc086c47ef7a971d9ace7dc6ab383f 100755
--- a/scripts/tsplot.py
+++ b/scripts/tsplot.py
@@ -28,12 +28,14 @@ def parse_clargs():
     P.add_argument('-t', '--abscissae', metavar='RANGE', dest='trange',
                    type=parse_range_spec, 
                    help='restrict time axis to RANGE (see below)')
-    P.add_argument('-g', '--group', metavar='KEY,...',  dest='groupby',
+    P.add_argument('-g', '--group', metavar='KEY,...', dest='groupby',
                    type=lambda s: s.split(','), 
                    help='plot series with same KEYs on the same axes')
-
-    P.add_argument('-o', '--out', metavar='FILE',  dest='outfile',
+    P.add_argument('-o', '--out', metavar='FILE', dest='outfile',
                    help='save plot to file FILE')
+    P.add_argument('-x', '--exclude', metavar='NUM', dest='exclude',
+                   type=float,
+                   help='remove extreme points outside NUM times the 0.9-interquantile range of the median')
 
     P.epilog =  'A range is specifed by a pair of floating point numbers min,max where '
     P.epilog += 'either may be omitted to indicate the minimum or maximum of the corresponding '
@@ -61,11 +63,31 @@ class TimeSeries:
         self.y[:ny] = ys[:ny]
 
         self.meta = dict(kwargs)
+        self.ex_ts = None
 
-    def tclip(self, bounds):
+    def trestrict(self, bounds):
         clip = range_meet(self.trange(), bounds)
         self.t = np.ma.masked_outside(self.t, v1=clip[0], v2=clip[1])
-        self.y = np.ma.masked_where(np.ma.getmask(self.t), self.y)
+        self.y = np.ma.masked_array(self.y, mask=self.t.mask)
+
+    def exclude_outliers(self, iqr_factor):
+        yfinite = np.ma.masked_invalid(self.y).compressed()
+        l_, lq, median, uq, u_ = np.percentile(yfinite, [0, 5.0, 50.0, 95.0, 100])
+        lb = median - iqr_factor*(uq-lq)
+        ub = median + iqr_factor*(uq-lq)
+        
+        np_err_save = np.seterr(all='ignore')
+        yex = np.ma.masked_where(np.isfinite(self.y)&(self.y<=ub)&(self.y>=lb), self.y)
+        np.seterr(**np_err_save)
+
+        tex = np.ma.masked_array(self.t, mask=yex.mask)
+        self.ex_ts = TimeSeries(tex.compressed(), yex.compressed())
+        self.ex_ts.meta = dict(self.meta)
+
+        self.y = np.ma.filled(np.ma.masked_array(self.y, mask=~yex.mask), np.nan)
+
+    def excluded(self):
+        return self.ex_ts
 
     def name(self):
         return self.meta.get('name',"")   # value of 'name' attribute in source
@@ -287,7 +309,12 @@ def plot_plots(plot_groups, save=None):
             colours = cycle(palette[ui])
             line = next(lines)
             for s, l in series_by_unit[ui]:
-                plot.plot(s.t, s.y, color=next(colours), ls=line, label=l)
+                c = next(colours)
+                plot.plot(s.t, s.y, color=c, ls=line, label=l)
+                # treat exluded points especially
+                ex = s.excluded()
+                ymin, ymax = s.yrange()
+                plot.plot(ex.t, np.clip(ex.y, ymin, ymax), marker='x', ls='', color=c)
 
             if first_plot:
                 plot.legend(loc=2, fontsize='small')
@@ -313,7 +340,11 @@ for filename in args.inputs:
 
 if args.trange:
     for ts in tss:
-        ts.tclip(args.trange)
+        ts.trestrict(args.trange)
+
+if args.exclude:
+    for ts in tss:
+        ts.exclude_outliers(args.exclude)
 
 groupby = args.groupby if args.groupby else []
 plots = gather_ts_plots(tss, groupby)