首页 > 解决方案 > 使用gnuplot绘制二进制数据时是否可以设置X轴时间范围?

问题描述

我有一个二进制数据文件,其中包含一个标头,后跟一堆五字节的数据记录。每个字节是对不同数量的测量,所有这些都是同时获取的1。我想显示一个有五行的图表,显示每个数量如何随时间变化。数据文件的开始时间在文件开头以一些字节编码,我知道每条记录都是在前一条记录之后 2 秒拍摄的,但是这些记录没有单独的时间戳。

通过完全忽略实际时间,我可以或多或少地像我想要的那样绘制它;如果你set xdata time,那么 gnuplot 做正确的事。但是,它无法显示正确的时间。另一方面,如果你set xrange ["*time1*":"*time2*"],那么你根本不会得到任何图表,因为 gnuplot 不知道未加时间戳的记录对应于那些时间。

有没有办法告诉 gnuplot 文件中的二进制记录以特定时间戳开头,以便它们匹配正确的 xrange?

我的二进制数据(50 字节标头 =0003签名,uint16 年,uint8 月,uint8 日,uint8 小时,uint8 分钟,uint8 秒,其他随机内容,然后是 5 字节记录):

00000000  03 00 e3 07 0b 0f 16 22  13 63 97 00 00 fc 78 00  |.......".c....x.|
00000010  00 60 5c 04 00 00 00 00  00 63 00 00 00 00 00 00  |.`\......c......|
00000020  00 00 00 00 00 00 00 00  ff ff ff 00 00 ff ff ff  |................|
00000030  00 00 61 3a 00 00 00 61  3a 00 00 00 61 3b 00 00  |..a:...a:...a;..|
00000040  00 61 3b 00 00 00 60 3c  00 00 00 60 3c 00 00 00  |.a;...`<...`<...|
00000050  60 3c 00 00 00 60 3c 00  00 00 60 3d 00 00 00 60  |`<...`<...`=...`|
00000060  3d 00 00 00 60 3c 00 00  00 60 3c 00 00 00 61 3e  |=...`<...`<...a>|
00000070  00 00 00 61 3e 00 00 00  61 3f 00 00 00 61 3f 00  |...a>...a?...a?.|
00000080  00 00 61 3f 00 02 00 61  3f 00 02 00 61 3f 00 01  |..a?...a?...a?..|
00000090  00 61 3f 00 01 00 61 3f  00 00 00 61 3f 00 00 00  |.a?...a?...a?...|
000000a0  61 3f 00 00 00 61 3f 00  00 00 61 41 00 01 00 61  |a?...a?...aA...a|
000000b0  41 00 01 00 60 42 00 00  00 60 42 00 00 00 60 40  |A...`B...`B...`@|
000000c0  00 00 00 60 40 00 00 00  60 3d 00 00 00 60 3d 00  |...`@...`=...`=.|
000000d0  00 00 60 3c 00 00 00 60  3c 00 00 00 60 3c 00 00  |..`<...`<...`<..|
000000e0  00 60 3c 00 00 00 60 3c  00 00 00 60 3c 00 00 00  |.`<...`<...`<...|
000000f0  60 3d 00 00 00 60 3d 00  00 00 60 3e 00 00 00 60  |`=...`=...`>...`|
00000100  3e 00 00 00 60 3e 00 00  00 60 3e 00 00 00 60 3f  |>...`>...`>...`?|
00000110  00 00 00 60 3f 00 00 00  60 40 00 00 00 60 40 00  |...`?...`@...`@.|
00000120  00 00 60 40 00 05 00 60  40 00 05 00 60 40 00 04  |..`@...`@...`@..|
00000130  00 60 40 00 04 00 60 3f  00 00 00 60 3f 00 00 00  |.`@...`?...`?...|
00000140  60 40 00 00 00 60 40 00  00 00 60 3f 00 00 00 60  |`@...`@...`?...`|
00000150  3f 00 00 00 60 3e 00 00  00 60 3e 00 00 00 60 3e  |?...`>...`>...`>|
00000160  00 0f 00 60 3e 00 0f 00  60 3c 00 00 00 60 3c 00  |...`>...`<...`<.|
00000170  00 00 60 3d 00 00 00 60  3d 00 00 00 60 3e 00 01  |..`=...`=...`>..|
00000180  00 60 3e 00 01 00 60 3e  00 18 00 60 3e 00 18 00  |.`>...`>...`>...|
00000190  60 3e 00 02 00 60 3e 00  02 00 60 3e 00 03 00 60  |`>...`>...`>...`|

我的 gnuplot 脚本:

#!/usr/bin/gnuplot

fn="20191115223419"

set title "Heart Rate, O2, Motion"
set xlabel "Time"

set xdata time
set timefmt "%Y%m%d%H%M%S"
set xrange ["20191115223419":"20191116071015"]
set format x "%H:%M"

set yrange [40:120]     # Heart rate
set y2range [50:100]    # O2 saturation

plot \
     fn binary skip=0x32 format="%5uint8" using 0:2 with lines lt rgb "red" title "HR", \
     fn binary skip=0x32 format="%5uint8" using 0:(($4)/4+40) with lines lt rgb "orange" title "Motion", \
     fn binary skip=0x32 format="%5uint8" using 0:1 with lines lt rgb "gray60" title "O2" axes x1y2

pause -1 "Hit <ENTER> to continue..."

如果我注释掉该xrange行,它会根据需要绘制。

我知道我可以很容易地编写一个脚本来将数据转换成更好的形式,也许这就是要做的事情:将它的 Python 转换成一个更好的字符串,然后 gnuplot 那个。但如果我能单独告诉 gnuplot 做我想做的事,我会很高兴。


1这 5 个字节实际上是 O 2饱和度、脉搏率、虚拟(始终为零)、运动传感器和另一个虚拟字节。我的 gnuplot 脚本只绘制了 3 个非虚拟值。

标签: plotgraphgnuplot

解决方案


这是一个完整的 gnuplot 脚本,用于从二进制文件中提取 Y/M/DH:M:S 数据并绘制其余数据以及示例图像。

#!/usr/bin/gnuplot
#
# This script plots data from a Viatom pulse oximeter (www.viatomtech.com).  The
# Android app extracts recorded data and stores it in an Sqlite3 database, and also
# creates files under /sdcard/PlusebitO2CN with names based on the recording start
# date & time.  These are binary files with a two-byte "signature" of 0x0003; 7 bytes
# of start date/time as uint16:year, uint8 month, day, hour, minute, second; 41 bytes
# of something else ??? and then 5-byte records of Oxygenation, Heart Rate, dummy-1,
# motion-sensor, dummy-2.
#

# Put file name here...everything else is automagic.
#
fn="20191115223419"
#
####################################################

set title "Heart Rate, O2, Motion"
set xlabel "Time"

#
# Get start time from binary file by fake-plotting.  This will
# print a warning message; I don't know how to get rid of it.
#
set term unknown
plot fn binary skip=2 format="%uint16%5uint8" every 1:1:0:0:0:0 \
     using (year=$1):(month=$2):(day=$3):(hour=$4):(minute=$5):(second=$6):1 with candlesticks
# Now put the values we extracted into a single 'YYYYmmddHHMMSS' string
sd=sprintf("%04d%d%d%d%d%d", year, month, day, hour, minute, second )
set term qt

set xdata time
start=strptime("%Y%m%d%H%M%S", sd ) # sd contains YYYYmmddHHMMSS extracted from file
set xtics time format "%H%M%S"
#set timefmt "%Y%m%d%H%M%S"
#set xrange ["20191115223419":"20191116071015"]
set format x "%H:%M"

set yrange [40:120]     # Heart rate
set y2range [50:100]    # O2 saturation

plot \
     fn binary skip=0x32 format="%5uint8" using (start+2*$0):2 with lines lt rgb "red" title "HR", \
     fn binary skip=0x32 format="%5uint8" using (start+2*$0):(($4)/4+40) with lines lt rgb "orange" title "Motion", \
     fn binary skip=0x32 format="%5uint8" using (start+2*$0):1 with lines lt rgb "gray60" title "O2" axes x1y2

pause -1 "Hit <ENTER> to continue..."

结果: gnuplot 心率示例


推荐阅读