Plotting Average curve for points in gnuplot

saif picture saif · Mar 17, 2017 · Viewed 13.2k times · Source

[Current]

I am importing a text file in which the first column has simulation time (0~150) the second column has the delay (0.01~0.02).

1.000000 0.010007
1.000000 0.010010
2.000000 0.010013
2.000000 0.010016
.
.
.
149.000000 0.010045
149.000000 0.010048
150.000000 0.010052
150.000000 0.010055

which gives me the plot: Instantanous Delay in Seconds


[Desired]

I need to plot an average line on it like shown in the following image with red line:

Average red line

Answer

maij picture maij · Mar 17, 2017

Here is a gnuplot only solution with sample data:

set table "test.data"
set samples 1000
plot rand(0)+sin(x)
unset table

You should check the gnuplot demo page for a running average. I'm going to generalize this demo in terms of dynamically building the functions. This makes it much easier to change the number of points include in the average.

This is the script:

# number of points in moving average
n = 50

# initialize the variables
do for [i=1:n] {
    eval(sprintf("back%d=0", i))
}

# build shift function (back_n = back_n-1, ..., back1=x)
shift = "("
do for [i=n:2:-1] {
    shift = sprintf("%sback%d = back%d, ", shift, i, i-1)
} 
shift = shift."back1 = x)"
# uncomment the next line for a check
# print shift

# build sum function (back1 + ... + backn)
sum = "(back1"
do for [i=2:n] {
    sum = sprintf("%s+back%d", sum, i)
}
sum = sum.")"
# uncomment the next line for a check
# print sum

# define the functions like in the gnuplot demo
# use macro expansion for turning the strings into real functions
samples(x) = $0 > (n-1) ? n : ($0+1)
avg_n(x) = (shift_n(x), @sum/samples($0))
shift_n(x) = @shift

# the final plot command looks quite simple
set terminal pngcairo
set output "moving_average.png"
plot "test.data" using 1:2 w l notitle, \
     "test.data" using 1:(avg_n($2)) w l lc rgb "red" lw 3 title "avg\\_".n

This is the result:

moving average

The average lags quite a bit behind the datapoints as expected from the algorithm. Maybe 50 points are too many. Alternatively, one could think about implementing a centered moving average, but this is beyond the scope of this question. And, I also think that you are more flexible with an external program :)