gnuplot,计算和绘制月平均值

时间:2016-03-19 23:49:57

标签: plot gnuplot average

我有一个包含几个月分钟数据的数据文件,其中包含" 2016-02-02 13:21(\ t)值(\ n)"。

我需要绘制数据(没有问题)并计算+绘制每个月的平均值。

是否可以在gnuplot中使用?

我可以使用

获得整体平均值
    fit a "datafile" using 1:3 via a

我还可以使用

指定适合的某个时间范围
    fit [now_secs-3600*24*31:now_secs] b "datafile" using 1:3 via b

...然后用

绘制它们
    plot a t "Total average",b t "Last 31 days"

但不知道如何计算和绘制每个月的平均值(=显示每个月平均值的一个阶梯线)

2 个答案:

答案 0 :(得分:2)

这是一种纯粹在gnuplot中完成它的方法。可以调整此方法(用不少的努力)来处理跨越一年边界或跨越一年以上的文件。如果数据从1月开始,它可以正常工作。它计算每个月的普通平均值(算术平均值),将每个数据点视为该月的一个值。通过一些重大修改,它也可以用于加权平均值。

这大大使用了stats函数来计算值。这有点长,部分是因为我对它进行了大量评论。它使用5.0功能(NaN用于未定义的值和内存数据块而不是临时文件),但注释注意如何更改早期版本的这些。

注意:此脚本必须在 设置时间模式之前运行。统计功能在时间模式下不起作用。时间转换由脚本函数处理。

data_time_format = "%Y-%m-%d %H:%M" #date format in file
date_cols = 2 # Number of columns consumed by date format

# get numeric month value of time - 1=January, 12=December
get_month(x) = 0+strftime("%m",strptime(data_time_format,x))

# get numeric year value of time
get_year(x) = 0+strftime("%Y",strptime(data_time_format,x))

# get internal time representation of day 1 of month x in year y
get_month_first(x,y) = strptime("%Y-%m-%d",sprintf("%d-%d-01",y,x))

# get internal time representation of date
get_date(x) = strptime(data_time_format,x)

# get date string in file format corresponding to day y in month x of year z
get_date_string(x,y,z) = strftime(data_time_format,strptime("%Y-%m-%d",sprintf("%04d-%02d-%02d",z,x,y)))

# determine if date represented by z is in month x of year y
check_valid(x,y,z) = (get_date(z)>=get_month_first(x,y))&(get_date(z)<get_month_first(x+1,y))

# Determine year and month range represented by file
year = 0 
stats datafile u (year=get_year(strcol(1)),get_month(strcol(1))) nooutput
month_min = STATS_min
month_max = STATS_max

# list of average values for each month
aves = ""

# fill missing months at beginning of year with 0
do for[i=1:(month_min-1)] {
    aves = sprintf("%s %d",aves,0)
}

# compute average of each month and store it at the end of aves
do for[i=month_min:month_max] {
    # In versions prior to 5.0, replace NaN with 1/0
    stats datafile u (check_valid(i,year,strcol(1))?column(date_cols+1):NaN) nooutput
    aves = sprintf("%s %f",aves,STATS_mean)
}

# day on which to plot average
baseday = 15

# In version prior to 5.0, replace $k with a temporary file name
set print $k
# Change this to start at 1 if we want to fill in prior months
do for [i=month_min:month_max] {
    print sprintf("%s %s",get_date_string(i,baseday,year),word(aves,i))
}
set print

此脚本将为早期版本(带有注释的更改)创建内存数据块或临时文件,其中包含与原始文件类似的文件,但每月包含一个条目,其中包含月平均值。 / p>

一开始我们需要定义日期格式和日期格式消耗的列数。从那时起,假设数据文件的结构为datetime value。定义了几个函数,它们广泛使用 strptime 函数(计算日期字符串为内部整数)和 strftime 函数(计算字符串的内部表示) )。其中一些函数计算两种方式以提取必要的值。请注意,在 get_month get_year 函数中添加0可将字符串值转换为整数。

我们对数据执行了几个步骤,以构建生成的数据块/文件。

  1. 使用统计功能计算第一个月,上个月和年份。我们假设只有一年。如果我们需要工作超过一年,则需要对此步骤进行大量修改。特别是第二年的月份需要编号为13 - 24,第三年需要编号为25 - 36,依此类推。我们需要修改此行以捕获多年。可能需要两次通行证。
  2. 构建一个字符串,其中包含每个月平均值的空格分隔值。这是通过每月应用一次统计功能来完成的。 check_valid 函数检查某个值是否在感兴趣的月份中,并且未分配的值为NaN,导致统计函数忽略它。
  3. 循环关注的月份并构建一个数据块/临时文件,每个月有一个条目,该月份的平均值。在这种情况下,平均值被分配给该月的第15天的开始。这可以很容易地改变到任何其他所需的时间。 get_date_string 函数用于将值分配给时间。
  4. 现在为了证明这一点,假设我们有以下数据

    2016-02-03 15:22 95
    2016-02-20 18:03 23
    2016-03-10 16:03 200
    2016-03-15 03:02 100
    2016-03-18 02:02 200
    

    我们希望将这些数据与每个月的平均值一起绘制。我们可以运行上面的脚本,我们将获得一个数据块 $ k (在底部附近进行注释更改以使用临时文件),其中包含以下内容

    2016-02-15 00:00 59.000000
    2016-03-15 00:00 166.666667
    

    这正是每个月的平均值。现在我们可以用

    绘图
    set xdata time
    set timefmt data_time_format
    set key outside top right
    plot $k u 1:3 w points pt 7 t "Monthly Average",\
         datafile u 1:3 with lines t "Original Data"
    

    enter image description here

    这里,为了说明,我使用了平均值。随意使用您想要的任何风格。如果您选择使用步骤,则很可能需要调整数据块/临时文件中指定 的日期(可能是该月的第一天或最后一天)取决于你想怎么做)。

    这样的任务通常更容易进行一些外部预处理,但这表明它可以在纯gnuplot中使用。

    <小时/> 关于更改分配的日期,只要是每个月发生的一天(从1日开始),就可以轻松使用当月的任何特定日期到28日) - 只需更改 baseday 。对于其他值,需要对 get_date_string 函数进行修改。

    例如,要使用最后一天,该函数可以定义为

    get_date_string(x,y,z) = strftime(data_time_format,strptime("%Y-%m-%d",sprintf("%04d-%02d-01",z,x+1))-24*60*60)
    

    这个版本实际上计算下个月的第一天,然后从那里减去一整天。第二个参数在此版本中被忽略,但保留以允许使用它而无需对脚本进行任何其他更改。

答案 1 :(得分:0)

使用最新版本的gnuplot,你有stats命令,你可以做类似这样的事情:

stats "datafile" using 1:3 name m0

month_sec=3600*24*30.5
do for [month=1:12] {
   stats [now_secs-(i+1)*month_sec:(i+0)*now_secs-month_sec]  "datafile" using 1:3 name sprintf("m%d")
}

您获得总平均值的m0_mean值,并获得所有m1_mean m2_mean个变量用于上个月等...在gnuplot中定义

最后要绘制你应该做的事情:

plot 'datafile', for [month=0:12] value(sprintf("m%d_mean"))

有关上述命令的详情,请参阅help stats help for help value help sprintf

相关问题