Search code examples
gnuplot

Smoothing a line with Gnuplot not working as expected when using different colors depending on data value


This is the config I have and that works as intended to color the temperature curve blue if it is under 20C and red if it is 20C or above.

set datafile separator ","
set title "CO2,  Temp"
set key bottom right

set linetype 11 linecolor rgb "red"
set linetype 12 linecolor rgb "blue"

unset grid
set grid x
set grid y2

set ylabel "ppm"
set y2label "°C"

set xdata time
set timefmt "%Y-%m-%d %H:%M:%S"
set format x "%H:%M"  

set y2tics 
set y2range [15:30]  # range for temp


plot "minimonlog.csv" using 1:2 with lines smooth bezier axes x1y1 title "Co2", \
     "minimonlog.csv" using 1:3:($3 < 20 ? 12 : 11) linecolor variable with lines axes x1y2 title "Temp" 

done = 0
bind all 'd' 'done = 1'
while(!done) {
    replot
    pause 5      # waiting time in seconds
}

The csv contains data like this:

2023-10-25 14:10:40,   505,  20.35
2023-10-25 14:10:50,   506,  20.35
2023-10-25 14:11:00,   506,  20.35
2023-10-25 14:11:10,   506,  20.48

I tried adding in "smooth bezier" expecting it to smooth the temperature line, but this did not work. The line got smooth, but the color difference disappeared.

plot "minimonlog.csv" using 1:2 with lines smooth bezier axes x1y1 title "Co2", \
     "minimonlog.csv" using 1:3:($3 < 20 ? 12 : 11) linecolor variable with lines smooth bezier axes x1y2 title 

The error I get:

"minimon.gp" line 24: warning: extra columns ignored by smoothing option
"minimon.gp" line 29: warning: extra columns ignored by smoothing option
"minimon.gp" line 30: warning: extra columns ignored by smoothing option
"minimon.gp" line 30: warning: extra columns ignored by smoothing option
"minimon.gp" line 33: internal error : STRING operator applied to undefined or non-STRING variable

Solution

  • As I understand, smooth bezier does not accept more than 2 columns.

    A possible workaround would be the following:

    • plot your data using smooth bezier into a table/datablock
    • plot this datablock with conditional color

    Script:

    ### plot smooth bezier curve with conditional color
    reset session
    
    # create some test data
    set table $Data
        plot '+' u 1:(20+sin(x)+rand(0)-0.5) w table
    unset table
    
    myColor(v) = v<20 ? 0x0000ff : 0xff0000
    set key noautotitle
    set grid x,y
    
    set multiplot layout 2,1
    
        plot $Data u 1:2:(myColor($2)) w lp pt 7 lc rgb var
    
        set table $Smooth
            set samples 50
            plot $Data u 1:2 smooth bezier
        unset table
        plot $Smooth u 1:2:(myColor($2)) w lp pt 7 lc rgb var
    
    unset multiplot
    ### end of script
    

    Result:

    enter image description here

    Addition: (example for timedata)

    Actually, I noticed that time data and comma separated data will be trickier in your case:

    • plotting to a datablock using smooth and with table do not work together
    • when plotting to a datablock without with table, apparently you cannot set separator comma. So, you have to switch to separator whitespace.
    • plotting timedata to a datablock puts the timedata into quotes. As a consequence you cannot plot your timedata later as plot $Data u 1:2, but have to use plot $Data u (strptime(myTimeFmt,strcol(1))):2.

    Maybe somebody has some suggestions to simplify.

    Script:

    ### plot smooth bezier *timedata* curve with conditional color
    reset session
    
    myTimeFmt = "%Y-%m-%d %H:%M:%S"
    set xdata time
    set timefmt myTimeFmt
    
    # create some test data
    set table $Data separator comma
        plot '+' u (strftime(myTimeFmt,time(0)+$0*3600)):(20+sin(x)+rand(0)-0.5) w table
    unset table
    
    myColor(v) = v<=20 ? 0x0000ff : 0xff0000
    set key noautotitle
    set grid x,y
    
    set multiplot layout 2,1
    
        set datafile separator comma
        set format x "%Y\n%m-%d\n%H:%M" timedate
        plot $Data u 1:2:(myColor($2)) w lp pt 7 lc rgb var
    
        set table $Smooth
            set samples 50
            set format x myTimeFmt timedate
            plot $Data u 1:2 smooth bezier
        unset table
        set datafile separator whitespace
        set format x "%Y\n%m-%d\n%H:%M" timedate
        plot $Smooth u (strptime(myTimeFmt,strcol(1))):2:(myColor($2)) w lp pt 7 lc rgb var
    
    unset multiplot
    ### end of script
    

    Result:

    enter image description here

    Addition 2: (example with real data)

    Ok, a few more specialities with your data.

    • your data contains some nan
    • NaN will "mess up" smooth. In order to avoid that you need to set datafile missing NaN

    In the example below I don't use the systax set xdata time, but then you need in the plot command e.g. (timecolumn(1,myTimeFmt)).

    • when plotting to the datablocks $CO2 and $Temp I am using format "%.0f" numeric which are seconds passed since Jan, 1st 1970.
    • when plotting the format x is set to "%Y\n%m-%d\n%H:%M" timedate and you can simply plot, e.g. plot $CO2 u 1:2 ....

    Plotting time/date data can be a bit confusing.

    Script:

    ### plot smooth bezier *timedata* curve with conditional color
    reset session
    
    FILE = "SO77359398.csv"
    set datafile separator comma
    set datafile missing NaN
    
    myTimeFmt = "%Y-%m-%d %H:%M:%S"
    set ylabel  "CO_2 / ppm"
    set ytics  nomirror
    set y2label "Temperature / °C"
    set y2tics nomirror
    
    myColor(v) = v<20 ?  0x0000ff : 0xff0000
    set key noautotitle top center
    
    set multiplot layout 2,1
    
        set format x "%Y\n%m-%d\n%H:%M" timedate
        plot FILE u (timecolumn(1,myTimeFmt)):2 w l lc "dark-grey" axes x1y1 ti "CO_2", \
               '' u (timecolumn(1,myTimeFmt)):3:(myColor($3)) w l lc rgb var axes x1y2 ti "Temperature"
               
        set samples 500
        set format x "%.0f" numeric
        set table $CO2
            plot FILE u (timecolumn(1,myTimeFmt)):2 smooth bezier
        set table $Temp
            plot FILE u (timecolumn(1,myTimeFmt)):3 smooth bezier
        unset table
        set datafile separator whitespace
        set format x "%Y\n%m-%d\n%H:%M" timedate
        plot $CO2 u 1:2 w l lc "dark-grey" axes x1y1 ti "CO_2", \
            $Temp u 1:2:(myColor($2)) w l lc rgb var axis x1y2 ti "Temperature"
    unset multiplot
    ### end of script
    

    Result:

    enter image description here