Search code examples
gnuplotaxis-labels

How to control how many xlabels are printed in gnuplot?


I'm working on a heatmap style of displaying daily activity using Gnuplot's colorbox with a matrix of data: enter image description here

A sample part of the data file:

Week commencing,29 Jun 2020,06 Jul 2020,13 Jul 2020,20 Jul 2020,27 Jul 2020,03 Aug 2020,10 Aug 2020,17 Aug 2020,24 Aug 2020,31 Aug 2020,07 Sep 2020,14 Sep 2020,21 Sep 2020,28 Sep 2020,05 Oct 2020,12 Oct 2020,19 Oct 2020,26 Oct 2020,02 Nov 2020,09 Nov 2020
Mon,11,6,0,4,4,9,10,7,5,0,22,10,9,8,9,2,4,11,11,7
Tues,3,5,0,6,3,4,11,3,6,12,6,3,4,4,9,12,2,1,8,2
Weds,10,1,0,9,4,1,6,5,6,3,2,5,1,5,7,5,8,10,2,12
Thurs,6,3,0,8,3,2,7,14,10,12,14,8,1,3,19,11,8,16,3,7
Fri,16,1,2,5,10,3,0,1,10,1,13,10,0,10,6,10,7,4,9,5
Sat,6,6,8,21,2,7,0,11,0,7,2,23,2,8,11,11,5,3,12,0
Sun,8,7,3,1,8,2,8,2,2,2,6,6,3,3,2,2,4,5,8,0

With this script:

DATAFILE="done_tasks_matrix.csv"
set term png size 800, 300 font "Avenir,9"
set datafile separator comma columnheaders
set palette rgbformula -9,2,-9
set cbrange [0:*]
set cblabel "Completed tasks (Goals + Projects + Other)"
unset cbtics
set xrange writeback
set yrange [6.5:-0.5] writeback # to get it displaying Mon->Sun not Sun->Mon down the page
set xdata time
set timefmt "%d %b %Y" # format of the dates in the input
set format x "%d %b" # format of dates to show
set output "/Users/jonathan/Dropbox/NPSummaries/done_tasks_heatmap.png"
plot DATAFILE matrix rowheaders columnheaders using 1:2:3 with image, \
     DATAFILE matrix rowheaders columnheaders using 1:2:($3 == 0 ? "" : sprintf("%g",$3) ) with labels font ",8" tc rgb "#22BB22"

As I gather more data the xlabels are overlapping. I can't find a way to have it show only 1 in n labels. However, on simpler line graphs with dates as the xlabel Gnuplot seems to drop labels automatically to make sure they don't overlap.

Is it possible to drop some of the xlabels, or do I need to alter the input data so that some are blank?

Bonus question: why does the output include the second plot line as text, as well as obeying its instructions?


Solution

  • As @Tom Solid already pointed out, the easiest is probably to just rotate the xtic labels. Your "bonus question" can also be answered with inserting a line: unset key.

    By the way set xdata time, set timefmt "%d %b %Y", etc. in your code has no effect. The columnheaders will just be used as text for the xtic labels.

    A different (and bit more complex) suggestion would be to convert the dates into calendar weeks. This will save space. But keep in mind there are different definitions when the week starts (Sun or Mon?) and what calendar week 1 is.

    Code:

    ### schedule with calendar weeks
    reset session
    
    $Data <<EOD
    Week commencing,29 Jun 2020,06 Jul 2020,13 Jul 2020,20 Jul 2020,27 Jul 2020,03 Aug 2020,10 Aug 2020,17 Aug 2020,24 Aug 2020,31 Aug 2020,07 Sep 2020,14 Sep 2020,21 Sep 2020,28 Sep 2020,05 Oct 2020,12 Oct 2020,19 Oct 2020,26 Oct 2020,02 Nov 2020,09 Nov 2020
    Mon,11,6,0,4,4,9,10,7,5,0,22,10,9,8,9,2,4,11,11,7
    Tue,3,5,0,6,3,4,11,3,6,12,6,3,4,4,9,12,2,1,8,2
    Wed,10,1,0,9,4,1,6,5,6,3,2,5,1,5,7,5,8,10,2,12
    Thu,6,3,0,8,3,2,7,14,10,12,14,8,1,3,19,11,8,16,3,7
    Fri,16,1,2,5,10,3,0,1,10,1,13,10,0,10,6,10,7,4,9,5
    Sat,6,6,8,21,2,7,0,11,0,7,2,23,2,8,11,11,5,3,12,0
    Sun,8,7,3,1,8,2,8,2,2,2,6,6,3,3,2,2,4,5,8,0
    EOD
    
    set datafile separator comma
    unset key
    
    set palette rgbformula -9,2,-9
    set cbrange [0:*]
    set cblabel "Completed tasks (Goals + Projects + Other)"
    unset cbtics
    set style fill solid 1.0
    
    set locale "English_US"    # if not already set, to correctly interpret the month abbreviations
    set xlabel "Calendar week"
    
    myCW(col) = sprintf("%s",strftime("%W",strptime("%d %b %Y",strcol(col))))  # date --> calendar week
    stats [*:*][*:*] $Data u 2 skip 1 nooutput  # get the number of columns
    MaxCol = STATS_columns
    set xrange [-0.5:MaxCol-1.5] 
    set yrange [6.5:-0.5]
    
    plot $Data matrix rowheaders using 1:2:3 skip 1 with image, \
         $Data matrix rowheaders using 1:2:($3==0 ? "" : sprintf("%g",$3) ) skip 1 with labels font ",8" tc rgb "#22BB22", \
         for [i=2:MaxCol] $Data u (i-2):(NaN):xtic(myCW(i)) every ::0::0 
    ### end of code
    

    Result:

    enter image description here

    Addition:

    @JGC, that's the advantage of gnuplot, somehow there will be a solution, sometimes a bit cumbersome but mostly some workaround exists.

    Typically, I consider data as a given and fixed. In some cases you might have the possibility to change the data format already while creating it and adapt it to gnuplot's "special needs" to achieve your special wishes.

    As I mentioned, your labels are too long. plot ... matrix columnheaders will just use them all as text labels. I'm not aware that you can directly skip a few. But this is gnuplot, ... so, there is a workaround.

    1. you need to know how many columns you have. This, you can find out using stats. However, gnuplot doesn't recognize columns if the first line are headers or strings, that's why you have to skip the first line, i.e. skip 1. Although there is the syntax plot for [i=2:*] u 1:(column(i)) ... which should loop all columns, I experienced that this can lead to gnuplot hanging or crashing (I haven't found out yet why this is and how to reproduce it regularly).

    2. with the following construct you can select how many of the xtic labels you want to have shown: for [i=2+Noffset:MaxCol:Nxtic] $Data u (i-2):(NaN):xtic(strcol(i)) every ::0::0. Here: every Nxtic=4 label with an offset of Noffset=1. Furthermore, I would consider it important to have some xtic marks visible, especially if your xtic label is rather long. Otherwise you wouldn't know which column the date actually belongs to.

    Code:

    ### schedule from matrix with every nth label only
    reset session
    
    $Data <<EOD
    Week commencing,29 Jun 2020,06 Jul 2020,13 Jul 2020,20 Jul 2020,27 Jul 2020,03 Aug 2020,10 Aug 2020,17 Aug 2020,24 Aug 2020,31 Aug 2020,07 Sep 2020,14 Sep 2020,21 Sep 2020,28 Sep 2020,05 Oct 2020,12 Oct 2020,19 Oct 2020,26 Oct 2020,02 Nov 2020,09 Nov 2020
    Mon,11,6,0,4,4,9,10,7,5,0,22,10,9,8,9,2,4,11,11,7
    Tue,3,5,0,6,3,4,11,3,6,12,6,3,4,4,9,12,2,1,8,2
    Wed,10,1,0,9,4,1,6,5,6,3,2,5,1,5,7,5,8,10,2,12
    Thu,6,3,0,8,3,2,7,14,10,12,14,8,1,3,19,11,8,16,3,7
    Fri,16,1,2,5,10,3,0,1,10,1,13,10,0,10,6,10,7,4,9,5
    Sat,6,6,8,21,2,7,0,11,0,7,2,23,2,8,11,11,5,3,12,0
    Sun,8,7,3,1,8,2,8,2,2,2,6,6,3,3,2,2,4,5,8,0
    EOD
    
    set datafile separator comma
    unset key
    set palette rgbformula -9,2,-9
    set cbrange [0:*]
    set cblabel "Completed tasks (Goals + Projects + Other)"
    unset cbtics
    set style fill solid 1.0
    stats [*:*][*:*] $Data u 2 skip 1 nooutput    # get the number of columns
    MaxCol = STATS_columns
    Nxtic = 4
    Noffset = 1
    set xtics out
    set yrange [6.5:-0.5]
    
    plot $Data matrix rowheaders using 1:2:3 skip 1 with image, \
         $Data matrix rowheaders using 1:2:($3==0 ? "" : sprintf("%g",$3) ) skip 1 with labels font ",8" tc rgb "#22BB22", \
         for [i=2+Noffset:MaxCol:Nxtic] $Data u (i-2):(NaN):xtic(i) every ::0::0
    ### end of code
    

    Result:

    enter image description here