diff --git a/tracer/defs.h b/tracer/defs.h
index 873292a70ca7cd39c9b84188838328aa3c472c37..483e42ae906389dc260ba752c1d3a5a81d90217e 100644
--- a/tracer/defs.h
+++ b/tracer/defs.h
@@ -5,11 +5,12 @@
 #define PLOT_VS_TIME   0
 #define PLOT_IQ_POINTS 1
 
-void *make_plot(int width, int height, int bufsize, char *title, int type);
-void plot_set(void *plot, float *data, int len, int pos);
-void iq_plot_set(void *plot, short *data, int len, int pos);
-void iq_plot_set_sized(void *_plot, short *data, int len);
-void iq_plot_add_point_loop(void *_plot, short i, short q);
+/* ... is { int count; int type; char *color; } for 'nplots' plots */
+void *make_plot(int width, int height, char *title, int nplots, ...);
+void plot_set(void *plot, float *data, int len, int pos, int pp);
+void iq_plot_set(void *plot, short *data, int len, int pos, int pp);
+void iq_plot_set_sized(void *_plot, short *data, int len, int pp);
+void iq_plot_add_point_loop(void *_plot, short i, short q, int pp);
 
 /* returns an opaque pointer - truly a 'database *', see t_data.c */
 void *parse_database(char *filename);
diff --git a/tracer/main.c b/tracer/main.c
index 853ed46fedf24a87500515f46ed7d326c93c74c0..0b529b132b21b96453d56e593a1623bfb27262c7 100644
--- a/tracer/main.c
+++ b/tracer/main.c
@@ -218,7 +218,7 @@ void get_message(int s)
 #endif
     if (size != 4 * 7680)
       {printf("bad T_ENB_INPUT_SIGNAL, only 7680 samples allowed\n");abort();}
-    if (ul_plot) iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680);
+    if (ul_plot) iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680, 0);
     break;
   }
   case T_ENB_UL_CHANNEL_ESTIMATE: {
@@ -235,7 +235,7 @@ void get_message(int s)
     if (size != 512*4)
       {printf("bad T_ENB_UL_CHANNEL_ESTIMATE, only 512 samples allowed\n");
        abort();}
-    if (chest_plot) iq_plot_set(chest_plot, (short*)buf, 512, 0);
+    if (chest_plot) iq_plot_set(chest_plot, (short*)buf, 512, 0, 0);
     break;
   }
   case T_PUSCH_IQ: {
@@ -260,7 +260,7 @@ void get_message(int s)
         src = (uint32_t*)buf + l * 12 * 25;
         for (i = 0; i < nb_rb*12; i++) *dst++ = *src++;
       }
-      iq_plot_set_sized(pusch_iq_plot, (short*)buf, nb_rb*12*14);
+      iq_plot_set_sized(pusch_iq_plot, (short*)buf, nb_rb*12*14, 0);
     }
     break;
   }
@@ -273,7 +273,7 @@ void get_message(int s)
     GET(s, &I, sizeof(int));
     GET(s, &Q, sizeof(int));
 printf("receiving %d %d\n", I, Q);
-    if (pucch_iq_plot) iq_plot_add_point_loop(pucch_iq_plot, I*10, Q*10);
+    if (pucch_iq_plot) iq_plot_add_point_loop(pucch_iq_plot, I*10, Q*10, 0);
     break;
   }
   case T_buf_test: {
@@ -385,11 +385,14 @@ int main(int n, char **v)
   if (do_dump_database) { dump_database(database); return 0; }
 
   if (do_xforms) {
-    ul_plot = make_plot(512, 100, 7680*10, "UL Input Signal", PLOT_VS_TIME);
-    chest_plot = make_plot(512, 100, 512, "UL Channel Estimate UE 0",
-                           PLOT_VS_TIME);
-    pusch_iq_plot = make_plot(100, 100, 12*25*14, "PUSCH IQ",PLOT_IQ_POINTS);
-    pucch_iq_plot = make_plot(100, 100, 1000, "PUCCH IQ", PLOT_IQ_POINTS);
+    ul_plot = make_plot(512, 100, "UL Input Signal", 1,
+                        7680*10, PLOT_VS_TIME, "blue");
+    chest_plot = make_plot(512, 100, "UL Channel Estimate UE 0", 1,
+                           512, PLOT_VS_TIME, "blue");
+    pusch_iq_plot = make_plot(100, 100, "PUSCH IQ", 1,
+                              12*25*14, PLOT_IQ_POINTS, "blue");
+    pucch_iq_plot = make_plot(100, 100, "PUCCH IQ", 1,
+                              1000, PLOT_IQ_POINTS, "blue");
   }
 
   for (i = 0; i < on_off_n; i++)
diff --git a/tracer/plot.c b/tracer/plot.c
index e13398ab5e5d7fee653a7ae0b89c6a63f0c1119a..bdb864f2954431b9a5d857b27fca325cf9f2be23 100644
--- a/tracer/plot.c
+++ b/tracer/plot.c
@@ -8,22 +8,30 @@
 #include <unistd.h>
 #include <pthread.h>
 #include <sys/select.h>
+#include <stdarg.h>
 
 typedef struct {
-  Display *d;
-  Window w;
-  Pixmap p;
-  int width;
-  int height;
   float *buf;
   short *iqbuf;
   int count;
   int type;
   volatile int iq_count;  /* for ULSCH IQ data */
   int iq_insert_pos;
+  GC g;
+} data;
+
+typedef struct {
+  Display *d;
+  Window w;
+  Pixmap px;
+  GC bg;
+  int width;
+  int height;
   pthread_mutex_t lock;
   float zoom;
   int timer_pipe[2];
+  data *p;             /* list of plots */
+  int nplots;
 } plot;
 
 static void *timer_thread(void *_p)
@@ -52,6 +60,7 @@ static void *plot_thread(void *_p)
   fd_set rset;
   int xfd = ConnectionNumber(p->d);
   int maxfd = xfd > p->timer_pipe[0] ? xfd : p->timer_pipe[0];
+  int pp;
 
   while (1) {
     while (XPending(p->d)) {
@@ -73,41 +82,31 @@ static void *plot_thread(void *_p)
       replot = 0;
       redraw = 1;
 
-      /* TODO: get white & black GCs at startup */
-      {
-        GC gc;
-        XGCValues v;
-        gc = DefaultGC(p->d, DefaultScreen(p->d));
-        v.foreground = WhitePixel(p->d, DefaultScreen(p->d));
-        XChangeGC(p->d, gc, GCForeground, &v);
-        XFillRectangle(p->d, p->p, gc, 0, 0, p->width, p->height);
-        v.foreground = BlackPixel(p->d, DefaultScreen(p->d));
-        XChangeGC(p->d, gc, GCForeground, &v);
-      }
-
       if (pthread_mutex_lock(&p->lock)) abort();
 
-      if (p->type == PLOT_VS_TIME) {
-        for (i = 0; i < p->count; i++)
-          p->buf[i] = 10*log10(1.0+(float)(p->iqbuf[2*i]*p->iqbuf[2*i]+
-                                           p->iqbuf[2*i+1]*p->iqbuf[2*i+1]));
-        s = p->buf;
-        for (i = 0; i < 512; i++) {
-          v = 0;
-          for (j = 0; j < p->count/512; j++, s++) v += *s;
-          v /= p->count/512;
-          XDrawLine(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)),
-                    i, 100, i, 100-v);
+      for (pp = 0; pp < p->nplots; pp++) {
+        XFillRectangle(p->d, p->px, p->bg, 0, 0, p->width, p->height);
+        if (p->p[pp].type == PLOT_VS_TIME) {
+          for (i = 0; i < p->p[pp].count; i++)
+            p->p[pp].buf[i] =
+                10*log10(1.0+(float)(p->p[pp].iqbuf[2*i]*p->p[pp].iqbuf[2*i]+
+                p->p[pp].iqbuf[2*i+1]*p->p[pp].iqbuf[2*i+1]));
+          s = p->p[pp].buf;
+          for (i = 0; i < 512; i++) {
+            v = 0;
+            for (j = 0; j < p->p[pp].count/512; j++, s++) v += *s;
+            v /= p->p[pp].count/512;
+            XDrawLine(p->d, p->px, p->p[pp].g, i, 100, i, 100-v);
+          }
+        } else if (p->p[pp].type == PLOT_IQ_POINTS) {
+          XPoint pts[p->p[pp].iq_count];
+          int count = p->p[pp].iq_count;
+          for (i = 0; i < count; i++) {
+            pts[i].x = p->p[pp].iqbuf[2*i]*p->zoom/20+50;
+            pts[i].y = -p->p[pp].iqbuf[2*i+1]*p->zoom/20+50;
+          }
+          XDrawPoints(p->d, p->px, p->p[pp].g, pts, count, CoordModeOrigin);
         }
-      } else if (p->type == PLOT_IQ_POINTS) {
-        XPoint pts[p->iq_count];
-        int count = p->iq_count;
-        for (i = 0; i < count; i++) {
-          pts[i].x = p->iqbuf[2*i]*p->zoom/20+50;
-          pts[i].y = -p->iqbuf[2*i+1]*p->zoom/20+50;
-        }
-        XDrawPoints(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)),
-                    pts, count, CoordModeOrigin);
       }
 
       if (pthread_mutex_unlock(&p->lock)) abort();
@@ -115,7 +114,7 @@ static void *plot_thread(void *_p)
 
     if (redraw) {
       redraw = 0;
-      XCopyArea(p->d, p->p, p->w, DefaultGC(p->d, DefaultScreen(p->d)),
+      XCopyArea(p->d, p->px, p->w, DefaultGC(p->d, DefaultScreen(p->d)),
                 0, 0, p->width, p->height, 0, 0);
     }
 
@@ -125,7 +124,7 @@ static void *plot_thread(void *_p)
     if (select(maxfd+1, &rset, NULL, NULL, NULL) == -1) abort();
     if (FD_ISSET(p->timer_pipe[0], &rset)) {
       char b[512];
-      read(p->timer_pipe[0], b, 512);
+      if (read(p->timer_pipe[0], b, 512) <= 0) abort();
       replot = 1;
     }
   }
@@ -150,12 +149,17 @@ static void new_thread(void *(*f)(void *), void *data)
     { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); }
 }
 
-void *make_plot(int width, int height, int count, char *title, int type)
+void *make_plot(int width, int height, char *title, int nplots, ...)
 {
   plot *p;
   Display *d;
   Window w;
   Pixmap pm;
+  int i;
+  va_list ap;
+  XGCValues gcv;
+
+  p = malloc(sizeof(*p)); if (p == NULL) abort();
 
   d = XOpenDisplay(0); if (d == NULL) abort();
   w = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, width, height,
@@ -163,31 +167,70 @@ void *make_plot(int width, int height, int count, char *title, int type)
   XSelectInput(d, w, ExposureMask | ButtonPressMask);
   XMapWindow(d, w);
 
+  {
+    XSetWindowAttributes att;
+    att.backing_store = Always;
+    XChangeWindowAttributes(d, w, CWBackingStore, &att);
+  }
+
   XStoreName(d, w, title);
 
+  p->bg = XCreateGC(d, w, 0, NULL);
+  XCopyGC(d, DefaultGC(d, DefaultScreen(d)), -1L, p->bg);
+  gcv.foreground = WhitePixel(d, DefaultScreen(d));
+  XChangeGC(d, p->bg, GCForeground, &gcv);
+
   pm = XCreatePixmap(d, w, width, height, DefaultDepth(d, DefaultScreen(d)));
 
-  p = malloc(sizeof(*p)); if (p == NULL) abort();
   p->width = width;
   p->height = height;
-  if (type == PLOT_VS_TIME) {
-    p->buf = malloc(sizeof(float) * count); if (p->buf == NULL) abort();
-    p->iqbuf = malloc(sizeof(short) * count * 2); if(p->iqbuf==NULL)abort();
-  } else {
-    p->buf = NULL;
-    p->iqbuf = malloc(sizeof(short) * count * 2); if(p->iqbuf==NULL)abort();
+  p->p = malloc(nplots * sizeof(data)); if (p->p == NULL) abort();
+
+  va_start(ap, nplots);
+  for (i = 0; i < nplots; i++) {
+    int count;
+    int type;
+    char *color;
+    XColor rcol, scol;
+
+    count = va_arg(ap, int);
+    type = va_arg(ap, int);
+    color = va_arg(ap, char *);
+
+    p->p[i].g = XCreateGC(d, w, 0, NULL);
+    XCopyGC(d, DefaultGC(d, DefaultScreen(d)), -1L, p->p[i].g);
+    if (XAllocNamedColor(d, DefaultColormap(d, DefaultScreen(d)),
+                         color, &scol, &rcol)) {
+      gcv.foreground = scol.pixel;
+      XChangeGC(d, p->p[i].g, GCForeground, &gcv);
+    } else {
+      printf("could not allocate color '%s'\n", color);
+      abort();
+    }
+
+    if (type == PLOT_VS_TIME) {
+      p->p[i].buf = malloc(sizeof(float) * count);
+      if (p->p[i].buf == NULL) abort();
+      p->p[i].iqbuf = malloc(sizeof(short) * count * 2);
+      if(p->p[i].iqbuf==NULL)abort();
+    } else {
+      p->p[i].buf = NULL;
+      p->p[i].iqbuf = malloc(sizeof(short) * count * 2);
+      if(p->p[i].iqbuf==NULL)abort();
+    }
+    p->p[i].count = count;
+    p->p[i].type = type;
+    p->p[i].iq_count = 0;
+    p->p[i].iq_insert_pos = 0;
   }
-  p->count = count;
+  va_end(ap);
 
   p->d = d;
   p->w = w;
-  p->p = pm;
-  p->type = type;
-
-  p->iq_count = 0;
-  p->iq_insert_pos = 0;
+  p->px = pm;
 
   p->zoom = 1;
+  p->nplots = nplots;
 
   pthread_mutex_init(&p->lock, NULL);
 
@@ -199,39 +242,39 @@ void *make_plot(int width, int height, int count, char *title, int type)
   return p;
 }
 
-void plot_set(void *_plot, float *data, int len, int pos)
+void plot_set(void *_plot, float *data, int len, int pos, int pp)
 {
   plot *p = _plot;
   if (pthread_mutex_lock(&p->lock)) abort();
-  memcpy(p->buf + pos, data, len * sizeof(float));
+  memcpy(p->p[pp].buf + pos, data, len * sizeof(float));
   if (pthread_mutex_unlock(&p->lock)) abort();
 }
 
-void iq_plot_set(void *_plot, short *data, int count, int pos)
+void iq_plot_set(void *_plot, short *data, int count, int pos, int pp)
 {
   plot *p = _plot;
   if (pthread_mutex_lock(&p->lock)) abort();
-  memcpy(p->iqbuf + pos * 2, data, count * 2 * sizeof(short));
+  memcpy(p->p[pp].iqbuf + pos * 2, data, count * 2 * sizeof(short));
   if (pthread_mutex_unlock(&p->lock)) abort();
 }
 
-void iq_plot_set_sized(void *_plot, short *data, int count)
+void iq_plot_set_sized(void *_plot, short *data, int count, int pp)
 {
   plot *p = _plot;
   if (pthread_mutex_lock(&p->lock)) abort();
-  memcpy(p->iqbuf, data, count * 2 * sizeof(short));
-  p->iq_count = count;
+  memcpy(p->p[pp].iqbuf, data, count * 2 * sizeof(short));
+  p->p[pp].iq_count = count;
   if (pthread_mutex_unlock(&p->lock)) abort();
 }
 
-void iq_plot_add_point_loop(void *_plot, short i, short q)
+void iq_plot_add_point_loop(void *_plot, short i, short q, int pp)
 {
   plot *p = _plot;
   if (pthread_mutex_lock(&p->lock)) abort();
-  p->iqbuf[p->iq_insert_pos*2] = i;
-  p->iqbuf[p->iq_insert_pos*2+1] = q;
-  if (p->iq_count != p->count) p->iq_count++;
-  p->iq_insert_pos++;
-  if (p->iq_insert_pos == p->count) p->iq_insert_pos = 0;
+  p->p[pp].iqbuf[p->p[pp].iq_insert_pos*2] = i;
+  p->p[pp].iqbuf[p->p[pp].iq_insert_pos*2+1] = q;
+  if (p->p[pp].iq_count != p->p[pp].count) p->p[pp].iq_count++;
+  p->p[pp].iq_insert_pos++;
+  if (p->p[pp].iq_insert_pos == p->p[pp].count) p->p[pp].iq_insert_pos = 0;
   if (pthread_mutex_unlock(&p->lock)) abort();
 }