Apocalypse Mystic
Apocalypse Mystic

Reputation: 23

Iterate over all datasets AND all columns in gnuplot

I have a datafile with an arbitrary number of datasets, each with an arbitrary number of columns. Every column starts with a header that I would like to use as a title. This is an example datafile, "gp.dat":

a b
2 3
4 9
16 27


c
4
16
64

I would like to generate a plot using gnuplot (gnuplot 5.4 patchlevel 2) that interprets every column in every dataset as an independent line, each labeled with its column header. For the above dataset, this would do the trick:

plot for [d=0:*] for [i=1:2] "gp.dat" index d using i title columnheader with linespoints

Resulting in the following plot:

Sample plot of multiple datasets and columns

However, when I try to specify ALL datasets AND ALL columns, the "c" line vanishes:

plot for [d=0:*] for [i=1:*] "gp.dat" index d using i title columnheader with linespoints

Sample bad plot

This seems to hold for any index I supply for the column number above 2, so this produces the same bad plot:

plot for [d=0:*] for [i=1:3] "gp.dat" index d using i title columnheader with linespoints

How can I specify ALL datasets and ALL columns and guarantee that everything will be plotted?

Upvotes: 1

Views: 123

Answers (1)

theozh
theozh

Reputation: 26200

In the past, I made other strange observations using the * in such "self (de-/non-)terminating loops". I guess gnuplot determines the number of columns from the last block, but is probably not prepared to have variable number of columns.

Here is a somewhat awkward but straightforward procedure to plot all blocks and all columns. This example works as long as your column separator is whitespace.

  • determine the number of blocks using stats (check help stats)
  • set the column separator temporarily to "\n", i.e. strcol(1) will be the whole line
  • extract the number of columns from the first row of each block using words (check help words) and write it to a datablock $ColMax (check help table).
  • reset the column separator to whitespace again
  • use the variable number of columns for each block

Maybe there are shorter and smarter solutions.

Script:

### plot all blocks and all columns (variable number of columns in blocks)
reset session

$Data <<EOD
a  b
2   3
4   9
16 27


c
4
16
64


d   e   f
5   6   7
33  44  55
77  88  99
EOD

stats $Data u 0 nooutput
set datafile separator "\n"
set table $ColMax
    plot for [b=0:STATS_blocks-1] $Data u (words(strcol(1))) index b every ::::0 w table
unset table
set datafile separator whitespace

set key top center

plot for [b=0:STATS_blocks-1] for [c=1:$ColMax[b+1]] $Data u 0:c index b w lp pt 7 ti columnhead
### end of script

Result:

enter image description here

Addition:

Here is a bit shorter solution which does not use reading from or plotting to a table/datablock (which works only for gnuplot>5.0). The following should also work for later versions of 4.x if you read the data from a file.

Script:

### plot all blocks and all columns (variable number of columns in blocks)
reset

FILE = 'myFile.dat'

set datafile separator "\n"  # or any character which is not in the data
B    = 0
Cols = ''
stats FILE u (column(-2)==B ? (B=B+1, Cols=Cols.' '.words(strcol(1))):0) every ::1::1 nooutput
set datafile separator whitespace

set key top center

plot for [b=0:B-1] for [c=1:word(Cols,b+1)] FILE u 0:c index b w lp pt 7 ti columnhead
### end of script

Upvotes: 0

Related Questions