我有一个包含几个月分钟数据的数据文件,其中包含" 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"
但不知道如何计算和绘制每个月的平均值(=显示每个月平均值的一个阶梯线)
答案 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可将字符串值转换为整数。
我们对数据执行了几个步骤,以构建生成的数据块/文件。
现在为了证明这一点,假设我们有以下数据
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"
这里,为了说明,我使用了平均值。随意使用您想要的任何风格。如果您选择使用步骤,则很可能需要调整数据块/临时文件中指定 † 的日期(可能是该月的第一天或最后一天)取决于你想怎么做)。
这样的任务通常更容易进行一些外部预处理,但这表明它可以在纯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