3
votes

I need create a parallel plot with lines and points using gnuplot. Unfortunately either using

set style line 1 lc rgb 'blue' lt 1 lw 2 pt 7 ps 0.75 pi 5

or by setting pt ps and pi in plot command

Gnuplot do not insert any point.

I need to insert points to distinguish two line with the same color. They have to be the same color since they are of the same "family". Therefore, I can not simply change the colors :(

How can I do that?

Thanks

1
Gnuplot simply cannot do this. In general, this would also crowd your axes since the points would all lay on the axes. So you'll need to think of a different kind of visualization (use dark blue and bright blue to distinguish them). But without knowing the actual use case, this is only some guess.Christoph

1 Answers

3
votes

It is unfortunately true that Gnuplot does not support this feature "out of the box", nevertheless should you need this just for some quick one-time production plot then there is a slightly dirty way how to do this. To be more specific, one can get the current source code of Gnuplot, in a more or less satisfactory way introduce this feature and generate the desired figure with the modified version of Gnuplot.

To illustrate the idea, let's assume that we want to parallel-plot following data file data.dat consisting of merely three "sets":

1 2 3
2 1 1
3 3 3

Inspired by the default Gnuplot demo parallel.dem, one would probably try to achieve this with a script test.gpl like this:

set title "Parallel Axis Plot" font ",15"

set terminal pdf
set output 'test.pdf'

set border 0
unset key
set xrange [] noextend
unset ytics

# use x-axis tic positions to label the axes
set xtics 1 format "axis %g" scale 0,0

# turn on axis tics for the parallel axes
set for [i=1:3] paxis i tics

plot 'data.dat' using 1:2:3 with parallel

However, this produces plot which will probably resemble: enter image description here

Here, all lines are of the same type and color which is rather confusing. As a small upgrade, let's modify our input data file as follows:

1 2 3 5
2 1 1 6
3 3 3 7

and use slightly different plotting command

plot 'data.dat' using 1:2:3:4 with parallel lc var

This yields

enter image description here

The resulting figure looks a bit better but let's say that we do insist on having a plot with points. Simply adding something like pt 1 does not work. Moreover, it produces a warning message: "test.gpl", line 17: warning: No pointtype specifier allowed, here suggesting that parallel style does not like any point specification at all.

Dirty fix

To partially improve upon this, let's proceed as follows:

cd ${HOME}

#prepare a sand box directory
mkdir gpl
cd gpl

#download the latest version
wget -O gnuplot_latest.tgz http://sourceforge.net/projects/gnuplot/files/latest/download?source=files
tar -xzvf gnuplot_latest.tgz

cd gnuplot-5.0.0
./configure --prefix=${HOME}/gpl/local
make && make install

Here, we are assuming that our system already has all the necessary prerequisites for a successful build. For example on Ubuntu, this minimal-case scenario should probably require just the development packages of libpango and libreadline.

Now, we need to play a little bit with some of the source files stored in ${HOME}/gpl/gnuplot-5.0.0/src. Namely, we have to

  1. convince Gnuplot that the plotting style parallel likes points. For this it is sufficient to modify line 114 in gp_types.h and replace

    PARALLELPLOT = 32*PLOT_STYLE_BITS + PLOT_STYLE_HAS_LINE
    

    with

    PARALLELPLOT = 32*PLOT_STYLE_BITS + PLOT_STYLE_HAS_LINE + PLOT_STYLE_HAS_POINT
    
  2. introduce the ability to plot points within the parallel style. To this end, one has to locate the function plot_parallel in file graphics.c. By default it looks like this:

    static void
    plot_parallel(struct curve_points *plot)
    {
        int i, j;
        int x0, y0, x1, y1;
    
        for (i = 0; i < plot->p_count; i++) {
    
        /* rgb variable  -  color read from data column */
        check_for_variable_color(plot, &plot->varcolor[i]);
    
        x0 = map_x(1.0);
        y0 = AXIS_MAP(PARALLEL_AXES+0, plot->z_n[0][i]);
        for (j = 1; j < plot->n_par_axes; j++) {
            x1 = map_x((double)(j+1));
            y1 = AXIS_MAP(PARALLEL_AXES+j, plot->z_n[j][i]);
            draw_clip_line(x0, y0, x1, y1);
            x0 = x1;
            y0 = y1;
        }
    
        }
    }
    

    Let's pimp it up a little bit:

    static void
    plot_parallel(struct curve_points *plot)
    {
        int i, j;
        int x0, y0, x1, y1;
    
        int point_type;
        struct termentry *t = term;
    
        for (i = 0; i < plot->p_count; i++) {
    
        /* rgb variable  -  color read from data column */
        check_for_variable_color(plot, &plot->varcolor[i]);
        point_type = plot->varcolor?((int)plot->varcolor[i]-1):plot->lp_properties.p_type;
    
        x0 = map_x(1.0);
        y0 = AXIS_MAP(PARALLEL_AXES+0, plot->z_n[0][i]);
    
       (*t->pointsize)(plot->lp_properties.p_size);
       (*t->point)(x0, y0, point_type);
    
        for (j = 1; j < plot->n_par_axes; j++) {
            x1 = map_x((double)(j+1));
            y1 = AXIS_MAP(PARALLEL_AXES+j, plot->z_n[j][i]);
            draw_clip_line(x0, y0, x1, y1);
            (*t->point)(x1, y1, point_type);
            x0 = x1;
            y0 = y1;
        }
    
        }
    }
    
  3. and that's it! Now compile Gnuplot again with make && make install (invoked from directory ${HOME}/gpl/gnuplot-5.0.0). The output generated with ${HOME}/gpl/local/bin/gnuplot ${HOME}/gpl/test.gpl (using plotting command plot 'data.dat' using 1:2:3:4 with parallel lc var ps 1.5) should resemble this:

enter image description here

Explanation

  1. modification in gp_types.h ensured that the point size specification ps 3 used in the final plot is not ignored (and is accessible in the plot_parallel function)
  2. in the plot_parallel function, we need to introduce a pointer to the global terminal variable, i.e., struct termentry *t = term;. This is then used later for the actual plotting of points.
  3. in the for loop which iterates over individual lines in the input data file, we determine the corresponding point type with

    `point_type = plot->varcolor?((int)plot->varcolor[i]-1):plot->lp_properties.p_type;`
    

    This ensures that if we don't use lc var then the point type is determined by pt (or default). If lc var is active, the point type is taken from the corresponding data column in the input data file.

  4. call (*t->pointsize)(plot->lp_properties.p_size); sets the desired point size specified with ps (or default).
  5. finally, calls of the type (*t->point)(x0, y0, point_type); augment individual line segments with the points.