【问题标题】:How to set the range of stats function in gnuplot?如何在 gnuplot 中设置 stats 函数的范围?
【发布时间】:2021-09-26 01:07:21
【问题描述】:

我有如下所示的时间序列数据,我想绘制所有数据,即特定范围的平均值,例如3、6 或 9 个月。

    Time           T      D      T/D
    8/1/2021    1785.28 23.99   74.42
    7/1/2021    1807.84 25.68   70.40
    6/1/2021    1834.57 27  67.95
    5/1/2021    1850.26 27.5    67.28
    4/1/2021    1760.04 25.69   68.51
    3/1/2021    1718.23 25.65   66.99
    2/1/2021    1808.17 27.29   66.26
    1/1/2021    1866.98 25.88   72.14
    12/1/2020   1858.42 24.97   74.43
    11/1/2020   1866.3  24.08   77.50
    10/1/2020   1900.27 24.23   78.43
    9/1/2020    1921.92 25.74   74.67
    8/1/2020    1968.63 27  72.91

我正在使用 gnuplot 5.2,并尝试使用以下代码进行绘图,但似乎统计数据没有按预期工作。

  # plot data vs date 
    
    reset session
    
    FILE = "data_01.dat"

    set timefmt "%m/%d/%Y"
    stats ["8/1/2020":"1/1/2021"] FILE u 4 name "A"
    stats ["8/1/2020":"8/1/2021"] FILE u 4 name "B"

    set label 1  sprintf("6 months average= %.2f",A_mean) at graph 0.02, graph 0.95
    set label 2  sprintf("12 months average= %.2f",B_mean) at graph 0.02, graph 0.90

    set xdata time
    set format x "%m/%y"
    set xrange ["8/1/2020":"8/1/2021"]
    
    plot FILE u 1:4 skip 1 w lp lc rgb 'blue' t 'data' ,\
    A_mean lc rgb 'black' t '6 months avg',\
    B_mean lc rgb 'red' t '12 months avg'
    
  # end of code

我得到的输出是这样的: data_plot

我认为我在设置统计数据限制时犯了一个错误,这使得统计数据计算列中整个数据的平均值,而不是在特定范围内计算它。但我找不到如何解决它。起初我尝试使用这个

stats ["8/1/2020":"1/1/2021"] FILE u (timecolumn(1)):4 name "A"

但它没有给我任何输出并以:“未定义变量:A_mean”结尾。 如何在 gnuplot 中正确设置 stats 函数的范围?

【问题讨论】:

  • 欢迎来到 SO!你的stats 命令的using 部分有一个小错误,它应该说using 1:4——否则行号被用作x。在我的理解中,set xdata time 应该在stats 之前。但是,这会引发错误“Stats 命令在 timedata 模式下不可用”,所以在我看来解决方案并不简单......

标签: gnuplot


【解决方案1】:

基本上,Eldrad 已经提到了所有的要点……当我还在编码的时候……

stats 不适用于时间数据,即set xdata time。 此外,如果您想限制第一个日期列,您还必须使用stats 中的第 1 列。 检查修改后的代码会给出合理的结果。

编辑: 除了多次使用strptime(myTimeFmt,"8/1/2020"),您还可以定义一个函数myTime(s) = strptime(myTimeFmt,s),它可以稍微缩短所有内容,并且不会让它看起来那么“可怕”。

代码:

# plot data vs date and using stats 
reset session

$Data <<EOD
Time           T      D      T/D
8/1/2021    1785.28 23.99   74.42
7/1/2021    1807.84 25.68   70.40
6/1/2021    1834.57 27  67.95
5/1/2021    1850.26 27.5    67.28
4/1/2021    1760.04 25.69   68.51
3/1/2021    1718.23 25.65   66.99
2/1/2021    1808.17 27.29   66.26
1/1/2021    1866.98 25.88   72.14
12/1/2020   1858.42 24.97   74.43
11/1/2020   1866.3  24.08   77.50
10/1/2020   1900.27 24.23   78.43
9/1/2020    1921.92 25.74   74.67
8/1/2020    1968.63 27  72.91
EOD

myTimeFmt = "%m/%d/%Y"
set timefmt myTimeFmt
myTime(s) = strptime(myTimeFmt,s)

stats [myTime("8/1/2020"):myTime("1/1/2021")] $Data u (timecolumn(1)):4 name "A" nooutput
stats [myTime("8/1/2020"):myTime("8/1/2021")] $Data u (timecolumn(1)):4 name "B" nooutput

set label 1  sprintf("6 months average= %.2f",A_mean_y) at graph 0.02, graph 0.95
set label 2  sprintf("12 months average= %.2f",B_mean_y) at graph 0.02, graph 0.90

set format x "%m/%y" time
set xrange [myTime("8/1/2020"):myTime("8/1/2021")]

plot $Data u (timecolumn(1)):4 skip 1 w lp lc rgb 'blue' t 'data' ,\
     A_mean_y lc rgb 'black' t '6 months avg',\
     B_mean_y lc rgb 'red'   t '12 months avg'
### end of code

结果:

【讨论】:

  • 谢谢,@theozh,您的代码让我更好地理解了如何使用此类数据限制 stats。我认为集合timefmt 使第1 列可以直接用于限制范围,就像我的代码中的set xrange 一样,它适用于绘图但不适用于stats
  • @Agung 不客气。据我了解,如果您在“stats”命令中写入using 4,它会尝试将您的第 4 列限制在您的时间限制内,这不匹配。
  • @theozh 啊,这绝对是比我的方法更直接或更“干净”的解决方案,我一直在努力解决所有这些时间函数……无论如何,stats 中的using 4 被解释为在plot 中,即行号被视为 x(其中 ofc 与时间范围不匹配)。或者换句话说,它是using 0:4的同义词。
【解决方案2】:

似乎在 stats 中使用 timedata 并没有在 gnuplot 中实现,至少在 5.5 版中是这样。我发现了一个基于gnuplot: xdata time & calculations 的(丑陋的)解决方法,它将输入时间和范围定义从 1.1.1970 转换为秒,比较输入值是否大于下限和小于上限;如果是,则返回实际的 y 值,如果不是,则返回 NaN,然后​​被 stats 忽略。

reset session
fmt="%m/%d/%Y"      #shortcut for the format string

FILE = "data_01.dat"
stats FILE u 1:(strptime(fmt,stringcolumn(1)) >= strptime(fmt,"8/1/2020") && strptime(fmt,stringcolumn(1)) <= strptime(fmt,"1/1/2021") ? $4 : NaN) name "A"

函数说明:strptime 将根据第一个参数格式化的时间字符串(第二个参数)转换为 UNIX 时间。因此,从文件中读取的 x 值需要作为字符串处理。 $1 将提供一个数字,而不是字符串,因此必须使用 stringcolumn 代替。这样就得到了y列的平均值,存储为A_mean_y(注意'_y'!)。

但也许有人有比我更优雅的解决方案……

【讨论】:

  • 谢谢@Eldrad!我知道stats 不适用于时间数据,这就是我将set xdata time 放在stats 之后的原因。但我没有意识到我需要使用stats 中的strptime 才能将它与stringcolumn 一起使用。感谢您的清晰解释,包括 A_mean_y!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-08
  • 1970-01-01
  • 1970-01-01
  • 2016-09-13
  • 1970-01-01
  • 2020-01-18
相关资源
最近更新 更多