Search code examples
graphgnuplot

Multiple graphs from a single data set with GNUPlot


I'm attempting to use gnuplot v5.4 to generate multiple graphs from one data set, though using select data from the set per graph.

I generate stats for a small program I'm developing, and write them to a CSV file:

(This CSV format is just what I've made the best progress with - I'm open to changing)

TotalPlayerCount,22
BluePlayerCount,10
RedPlayerCount,12
BluePlayerScoreTotal,50
RedPlayerScoreTotal,60

The following gives me the below graph:

cat <<"EOF" | gnuplot -p
$db <<DB
TotalPlayerCount,22
BluePlayerCount,10
RedPlayerCount,12
BluePlayerScoreTotal,50
RedPlayerScoreTotal,60
DB

set terminal windows size 2000,1000 enhanced font 'Arial,8'

set datafile separator ','
set yrange [0:100]
set boxwidth 0.1 relative
set style fill solid 1.0

plot $db using 2:xticlabel(1) notitle with boxes linestyle 1
EOF

enter image description here

I'm aiming for this:

enter image description here

which I have achieved using this:

cat <<"EOF" | gnuplot -p
$db <<DB
TotalPlayerCount,22
BluePlayerCount,10
RedPlayerCount,12
BluePlayerScoreTotal,50
RedPlayerScoreTotal,60
DB

set terminal windows size 2000,1000 enhanced font 'Arial,8'

set datafile separator ','
set yrange [0:100]
set boxwidth 0.1 relative
set style fill solid 1.0

set multiplot layout 1,2

plot $db using 2:xticlabel(1) every ::1::2 notitle with boxes linestyle 1
plot $db using 2:xticlabel(1) every ::3::4 notitle with boxes linestyle 1

unset multiplot
EOF

Is there a better or more idiomatic way to select from the data file what 'rows' to plot? These indices (in the every clause) work OK, but seem fragile.

I have previously used the trick where a ternary returning undefined in the using will cause gnuplot to ignore that row (e.g. maybe I could use it to select based on string compare) but that doesn't seem much more elegant either and I don't really enjoy how complex it makes the plot command.


Solution

  • One possibility that gives you a more "readable" syntax would be to use columnheaders, for which you would need to transpose your dataset. You don't necessarily need to use comma; spaces or tabs will do the trick as well:

    $db <<DB
    TotalPlayerCount BluePlayerCount RedPlayerCount BluePlayerScoreTotal RedPlayerScoreTotal
    22 10 12 50 60
    DB
    

    Set up the layout:

    set xrange [0:3]
    set yrange [0:100]
    set boxwidth 0.5
    set style fill solid 1.0
    

    Now you can select the column that you want to plot with column("string"), which will give you the correct y value. As for the x value, I simply took the constant number 1 for the first plot and 2 for the second one. In order to produce xticlabels one has to repeat the string:

    plot $db u (1):(column("BluePlayerCount")):xticlabels("BluePlayerCount") w boxes not, \
    $db u (2):(column("RedPlayerCount")):xticlabels("RedPlayerCount") w boxes not
    

    enter image description here

    Alternatively, you could delete the xticlabels part from the plot command and instead use: set xtics ("BluePlayerCount" 1, "RedPlayerCount" 2)

    You could also automate the plot even further:

    whattoplot_1 = "BluePlayerCount"
    whattoplot_2 = "RedPlayerCount"
    x_pos_1 = 1
    x_pos_2 = 2
    set xtics (whattoplot_1 x_pos_1, whattoplot_2 x_pos_2)
    plot $db u (x_pos_1):(column(whattoplot_1)) w boxes not, \
    $db u (x_pos_2):(column(whattoplot_2)) w boxes not
    

    Depending on what you want to achieve in the end, you might consider using arrays and iterate over the elements:

    array whattoplot[2] = ["BluePlayerCount", "RedPlayerCount"]
    plot for [i=1:|whattoplot|] $db u (i):(column(whattoplot[i])) w boxes not
    

    I hope this gives you some inspiration for how to proceed!