绘制gnuplot中点的平均曲线

问题描述 投票:1回答:4

[当前]

我正在导入一个文本文件,其中第一列有模拟时间(0~150),第二列有延迟(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

这给了我情节:Instantanous Delay in Seconds


[希望]

我需要在其上绘制一条平均线,如下图所示:

Average red line

gnuplot average
4个回答
4
投票

这是一个仅包含gnuplot的解决方案,包含样本数据:

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

你应该查看gnuplot demo页面的平均值。我将在动态构建函数方面概括这个演示。这样可以更容易地更改平均值中包含的点数。

这是脚本:

# 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

这是结果:

moving average

平均值远远落后于算法预期的数据点。也许50分太多了。或者,可以考虑实施居中的移动平均线,但这超出了这个问题的范围。而且,我也认为你对外部程序更灵活:)


2
投票

编辑

更新的问题是关于moving average

根据this demo的说法,你可以单独用gnuplot以有限的方式做到这一点。

但在我看来,使用pythonruby等编程语言预处理数据会更灵活,并为您需要的任何移动平均值添加额外的列。

原始答案保留如下:


你可以使用fit。看起来你想要适应恒定的功能。像这样:

f(x) = c

fit f(x) 'S1_delay_120_LT100_LU15_MU5.txt' using 1:2 every 5 via c

然后你可以绘制它们。

plot 'S1_delay_120_LT100_LU15_MU5.txt' using 1:2 every 5, \
f(x) with lines

请注意,这种技术可以与任意函数一起使用,而不仅仅是常量函数或线性函数。


1
投票

这里有一些顶级答案的替代代码,这使得它也可以工作1000+点,速度更快。仅适用于gnuplot 5.2及更高版本

# number of points in moving average
n = 5000

array A[n]

samples(x) = $0 > (n-1) ? n : int($0+1)
mod(x) = int(x) % n
avg_n(x) = (A[mod($0)+1]=x, (sum [i=1:samples($0)] A[i]) / samples($0))

1
投票

我想评论Franky_GT,但不知何故stackoverflow没有让我。

但是,Franky_GT,你的答案很棒!

人们在绘制.xvg文件时的注释(例如,在对MD模拟进行分析之后),如果您不添加以下行:

set datafile commentschars "#@&"

Franky_GT的移动平均代码将导致此错误:

unknown type in imag()

我希望这对任何人都有用。


0
投票

这是我的建议。它还需要gnuplot> = 5.2,因为它使用数据块和数组。它类似于@Franky_GT的答案,但也描述了如何将数据从数据块转换为数组。如果需要将文件中的数据导入数据块,可以使用:gnuplot: load datafile 1:1 into datablock。此外,可以选择用于平均的点数N,并且它们居中并且x值不必是整数或等距。在我的旧电脑上需要约。 5000个数据点0.35秒,平均值超过250。

码:

### centered average over n values
reset session
set key top left

# create some test data
DataPoints = 5000
set print $Data
    y0=0; x0=0
    do for [i=1:DataPoints] { print sprintf("%g %g",x0=x0+rand(0),y0=y0+rand(0)-0.5) }
set print

TimeStart = time(0.0)                   # get start time

# put y-data into array
array A[|$Data|]                        # define size of array 
set table $Dummy
    plot $Data u (A[$0+1]=$2) w table   # define array elements
unset table
print sprintf("Duration: %.3f sec",time(0.0)-TimeStart)   # print elapsed time

N=250                                   # average over N datapoints
Start(n) = (start=int(n-N/2)) < 1 ? 1 : start
End(n) =  (end=int(n+N/2)) > |$Data| ? |$Data| : end
Count(n) = End(n)-Start(n)+1

plot \
    $Data u 1:2 w l title "Data curve", \
    $Data u 1:((sum [i=Start($0+1):End($0+1)] A[i])/Count($0+1)) \
    w l lw 2 lc rgb "red" t sprintf("Average over %d",N)

print sprintf("Duration: %.3f sec",time(0.0)-TimeStart)   # print elapsed time
### end of code

结果:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.