【问题标题】:Plotting Average curve for points in gnuplot在gnuplot中绘制点的平均曲线
【发布时间】:2017-03-17 10:38:59
【问题描述】:

[当前]

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

这给了我情节:


[想要的]

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

【问题讨论】:

    标签: gnuplot average


    【解决方案1】:

    这是带有示例数据的仅 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
    

    这是结果:

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

    【讨论】:

    • 干得好。如果您的 x 轴只是普通整数,您可以通过plot "test.data" using ($1-n/2):(avg_n($2)) 重新定位平均曲线。请注意,为了使 @ 符号起作用,您可能需要在脚本顶部添加 set macros
    【解决方案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
    

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

    【讨论】:

      【解决方案3】:

      这是最佳答案的一些替换代码,这使得它也适用于 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))
      

      【讨论】:

        【解决方案4】:

        我想对 Franky_GT 发表评论,但不知何故 stackoverflow 不允许。

        但是,Franky_GT,您的回答很有效!

        如果您不添加以下行,请注意绘制 .xvg 文件(例如,在分析 MD 模拟之后):

        set datafile commentschars "#@&"
        

        Franky_GT 的移动平均代码会导致这个错误:

        unknown type in imag()
        

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

        【讨论】:

          【解决方案5】:

          对于 gnuplot >=5.2,可能最有效的解决方案是使用像 @Franky_GT 解决方案这样的数组。 但是,它使用伪列 0(请参阅 help pseudocolumns)。如果您的数据中有一些空行,$0 将被重置为 0,这最终可能会弄乱您的平均值。

          此解决方案使用索引t 来计算数据线和第二个数组X[],以防居中移动平均线需要。数据点不必在 x 中等距。 一开始没有足够的数据点用于N 点的中心平均值,因此对于 x 值,它将使用每隔一个点,另一个将是 NaN,这就是为什么需要 set datafile missing NaN 来绘制连接的行开头。

          代码:

          ### moving average over N points
          reset session
          
          # create some test data
          set print $Data
              y = 0
              do for [i=1:5000] {
                  print sprintf("%g %g", i, y=y+rand(0)*2-1) 
              }
          set print
          
          # average over N values
          N = 250
          array Avg[N]
          array X[N]
          
          MovAvg(col) = (Avg[(t-1)%N+1]=column(col), n = t<N ? t : N, t=t+1, (sum [i=1:n] Avg[i])/n)
          MovAvgCenterX(col) = (X[(t-1)%N+1]=column(col), n = t<N ? t%2 ? NaN : (t+1)/2 : ((t+1)-N/2)%N+1, n==n ? X[n] : NaN)   # be aware: gnuplot does integer division here
          
          set datafile missing NaN
          
          plot $Data u 1:2 w l ti "Data", \
               t=1 '' u 1:(MovAvg(2)) w l lc rgb "red" ti sprintf("Moving average over %d",N), \
               t=1 '' u (MovAvgCenterX(1)):(MovAvg(2)) w l lw 2 lc rgb "green" ti sprintf("Moving average centered over %d",N)
          
          ### end of code
          

          结果:

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-22
            • 2019-02-27
            • 2018-12-28
            • 1970-01-01
            • 1970-01-01
            • 2022-01-22
            相关资源
            最近更新 更多