【问题标题】:max value for same minute over multiple days from csv with unix timestamps来自 csv 的多天同一分钟的最大值,带有 unix 时间戳
【发布时间】:2019-08-29 10:13:40
【问题描述】:

我有一个带有 unix 时间戳列的 CSV,该列是在多天内收集的,每 5 分钟有一个数据行(我的光伏屋顶发电厂的输出日志)。

我想创建一个 24 小时图,显示所有天中每一(五)分钟的最大值。

这可以通过gnuplots 自己的功能来完成,还是我必须通过脚本在gnuplot 之外进行处理?


你没有展示你的确切数据结构是什么样子的,-theozh

这个文件相当大。我在这里放了一个例子:
http://www.filedropper.com/log-pv-20190607-20190811 (300kB)

我对第 4 列 (DC1 P) 和第 9 列 (DC2 P) 特别感兴趣。 第 1 列 (Zeit) 保存 unix 时间戳。

最终目标是为DC1 PDC2 P 提供单独的图表(颜色),但这是一个不同的问题... ;o)

【问题讨论】:

  • 感谢您的加入。我不需要整个文件,只需要结构和一些示例行......现在我看到你在标题中提到了 CSV。
  • @theozh 我认为“几个例子”很难安排在不同的日子里涵盖一天中的同一分钟,这对我的问题至关重要......

标签: gnuplot


【解决方案1】:

你没有展示你的确切数据结构是什么样子的,所以我假设了一些东西。为了说明一些事情,我创建了一些测试数据,这些数据在第一列中有时间戳,在第二列中有一些值。此外,我假设您的数据在每一天开始之前都没有空行,这将使生活更轻松。无论如何,您仍然可以使用 gnuplot 完成这一切,而无需外部脚本。

首先,您必须设置开始日期,例如"29.08.2019 00:00:00"。通过使用模 %86400(每天 86400 秒),您将每 24 小时绘制一次。使用对虚拟数据块$Dummy 的单独绘图命令,您将提取每天的最大值并将最大值放入数组DailyMax。然后创建一个显示这些值的标签。最后,绘制所有曲线。如果您需要对某些细节进行更多解释,请随时询问。 我希望,我正确理解了您的问题,并且您可以根据自己的需要调整建议。使用 gnuplot 5.2.6 测试。

代码:

### timestamp plot for 24h with extraction of daily maximum 
reset session
set colorsequence classic

# define some values and functions
StartTime = strptime("%d.%m.%Y %H:%M:%S", "29.08.2019 00:00:00")
NoOfDays = 5
Hours24(n) = int(n-StartTime)%86400
DayNo(n) = int((n-StartTime)/86400)

# generate some dummy data
set print $Data
    t(n) = StartTime + n*5*60
    do for [i=0:NoOfDays-1] {
        A = rand(0)*70+30
        p(n) = A*exp(-(n%288-144-rand(0)*10)**2/(720+rand(0)*2000))
        do for [j=0:287] {
            print sprintf("%.0f\t%f",t(i*288+j),p(i*288+j))
        }
    }
set print

# extract the maximum of each day and store it in an array
array DailyMax[NoOfDays]
DayPrev = NaN
set table $Dummy
   plot $Data u (DayPrev!=DayNo($1) ? Comp=$2 : 0, DayPrev=DayNo($1), \
       $2>=Comp ? (Comp=$2, DailyMax[DayNo($1)+1]=Comp) : 0) with table
unset table
print DailyMax

# create label with max values
do for [i=1:NoOfDays] {
    set label i at graph 0.05, 0.95-i*0.05 tc lt i-1 sprintf("Max of day %d: %.1f\n", i, DailyMax[i]) 
}

set xdata time
set format x "%H:%M"
set timefmt "%s"

plot $Data u (Hours24($1)):2:(DayNo($1)) w l lc var notitle
### end of code

结果:

加法:

假设我现在已经理解了你,那么你可以简单地绘制你的数据with boxes。无需提取最大值。较高的方框将覆盖较短的方框。

代码:

### timestamp plot plot maximum within every 5 min interval over all days
reset session
set colorsequence classic

# define some values and functions
StartTime = strptime("%d.%m.%Y %H:%M:%S", "29.08.2019 00:00:00")
NoOfDays = 5
Hours24(n) = int(n-StartTime)%86400
DayNo(n) = int((n-StartTime)/86400)

# generate some dummy data
set print $Data
    t(n) = StartTime + n*5*60
    do for [i=0:NoOfDays-1] {
        A = rand(0)*70+30
        p(n) = A*exp(-(n%288-144-rand(0)*10)**2/(720+rand(0)*2000))
        do for [j=0:287] {
            print sprintf("%.0f\t%f",t(i*288+j),p(i*288+j))
        }
    }
set print

set xdata time
set format x "%H:%M"
set timefmt "%s"
plot $Data u (Hours24($1)):2 w boxes fill solid 1.0 fc "web-green" notitle
### end of code

结果:

加法2:

现在,我想我们越来越近了。我修改了代码。您可以输入要绘制的数据的时间范围。您需要从数据顶部跳过 7 行,因为它们不以注释字符开头,例如#。检查下面的代码。

它的代码要简单得多,但是让我感到困惑的是,您不能在 plot 命令中直接使用函数Hours24(n)。它将在 00:00 为您提供一个高峰。我还不明白为什么。 交换最后两行就可以测试了

set xrange[0:86400]
plot $Data u 1:2 w boxes fill solid 1.0 fc "web-blue" notitle

set xrange[-10000:86400]
plot FILE u (Hours24($1)):4 skip 7 w boxes fill solid 1.0 fc "web-blue" notitle

代码:(针对自动完整时间范围进行了编辑)

### timestamp plot; put values of days on top of each other
reset session

FILE = 'log-pv-20190607-20190811.csv'

# automatic StartTime, EndTime
# StartTime always has to start at 00:00:00
stats FILE u 1 skip 7 nooutput
StartTime = strptime("%d.%m.%Y", strftime("%d.%m.%Y", STATS_min) )
EndTime = STATS_max
# alternatively, manually set StartTime, EndTime
# StartTime = strptime("%d.%m.%Y", "08.08.2019")   
# EndTime  = strptime("%d.%m.%Y %H:%M:%S", "11.08.2019 23:59:59")
print "StartTime: ", strftime("%d.%m.%Y %H:%M:%S", StartTime)
print "EndTime:   ", strftime("%d.%m.%Y %H:%M:%S", EndTime)

Hours24(n) = (n<StartTime || n>EndTime) ? "" : (int((n-StartTime))%86400)

# This extra of plotting to $Data step seems to be necessary, 
# because if you plot directly via
# plot FILE u (Hours24($1)):4 skip 7 w boxes fill solid 1.0 fc "web-blue" notitle
# you will get some value at 00:00, which I don't understand. A bug?
set table $Data
    plot FILE u (Hours24($1)):4 skip 7 w table
unset table

set xdata time
set format x "%H:%M"
set timefmt "%s"
set yrange[0:]

set xrange[0:86400]
plot $Data u 1:2 skip 7 w boxes fill solid 1.0 fc "web-blue" notitle
### end of code

结果:(现在有您的数据)

【讨论】:

  • 谢谢,这看起来非常接近我想要的,除了我只想要一条曲线,其中包含所有天中特定 5 分钟间隔的最大值,同样将所有图表设置为相同的颜色并填充它。
  • 简单地说,跳过测试数据部分并在绘图命令中执行plot 'YourFile.dat' u ...
  • 啊,好吧,这是因为你有8月8日之前半天的数据,取模会给出负数。我会修改代码。
  • 当然也可以。我将修改代码。我以为你想手动设置几天的某个窗口。
  • 欢迎您!我想我们已经完成了?!可接受的解决方案?现在应该很容易以相同的方式用不同的颜色绘制第 9 列。
【解决方案2】:

时间格式请见Gnuplot date/time in x axis

如果您不关心格式作为时间,您可以使用every 命令,请参阅gnuplot docu,但这并不需要最大值或其他东西。

对于给定时间间隔内的最大值,我建议使用awk 脚本,例如https://unix.stackexchange.com/a/207287/297901

【讨论】:

    【解决方案3】:

    从 gnuplot 5.2 开始,您可以使用新的 array 数据类型来计算每 5 分钟槽的最大值。我不是 gnuplot 专家,所以下面的例子需要更多的工作,但展示了潜力。

    假设数据类似于这些行,其中格式中有日期 yyyy.mm.dd.HH:MM,一个逗号和一个 y 值:

    2018.02.03.18:23,4
    2018.02.03.19:23,7
    2018.02.04.18:23,8
    2018.02.05.19:23,11
    

    不使用 gnuplot 的内置时间解析,因为我们想忽略日期,所以我们创建一个函数 fsecs 来使用 substr(stringcolumn(...),12,16) 从数据列 1 中获取小时和分钟,并使用 strptime("%H:%M",...) 来获取将其转换为秒:

    set datafile separator ","
    fsecs(v) = strptime("%H:%M",substr(stringcolumn(v),12,16))
    

    我们创建一个数组Max,以“5 分钟槽”为索引,其中每天有24*60/5。它被初始化为NaN,不是数字。

    Nitems = int(24*60/5)+1
    array Max[Nitems]
    do for [i=1:Nitems] {
        Max[i] = NaN
    }
    

    然后我们将数据文件data.csv“绘制”到一个虚拟表中,而不是生成任何输出。当我们遍历数据时,我们通过fsecs(1) 转换为秒的数据 x 值(第 1 列)索引Max,然后通过findex() 转换为插槽。这是Max[findex(fsecs(1))]。 我们调用函数fmax() 来返回要在数组中设置的新最大值。

    findex(x) = int(((x)/60)/5)
    fmax(a,b) = ((a>=b)?a:b)
    set table $Dummy
      plot 'data.csv' using \
        (Max[findex(fsecs(1))] = fmax(Max[findex(fsecs(1))],$2)):2
    unset table
    

    最后,我们绘制数组,即插槽号与该插槽号中保存的值的对比。

    plot Max using 1:(Max[$1]) with points lw 2 title "max day"
    

    这在 5.2 上适用于我。您仍然需要使用 HH:MM 标记 x 轴,并更改日期解析以满足您的需要。

    【讨论】:

    • 感谢您的回答。但是你的建议给了我array index out of range(Max[findex(fsecs(1))] = fmax(Max[findex(fsecs(1))],$2)):2
    • 我目前无法测试任何东西,但您可以尝试更改 findex(),将结果加 1 并可能暂时提升 Nitems。我不确定 gnuplot 对索引 0 的作用,因为数组似乎从 1 开始。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    • 1970-01-01
    • 2011-02-16
    • 2020-11-25
    • 2017-05-18
    • 1970-01-01
    • 2011-02-18
    相关资源
    最近更新 更多