Gnuplot: x轴多标签

3
我正在尝试绘制以下数据。
29.07.2012 18:45:04;23.6;54
29.07.2012 18:50:04;22.7;56
29.07.2012 18:55:04;22.2;56
29.07.2012 19:00:04;22.0;56
29.07.2012 19:05:04;21.9;57
29.07.2012 19:10:04;21.8;56
29.07.2012 19:15:04;21.8;54
29.07.2012 19:20:04;21.7;53
29.07.2012 19:25:04;21.7;53

以下是关于(日期、时间、温度、湿度)的图表样式(顶部已裁剪): enter image description here x轴上的标签是从当天开始的小时数,下方是星期几和日期。我的数据文件中没有星期几,但我希望在小时数下方显示日期。
我的绘图文件:
set datafile separator ";"
set terminal png size 5280,1024
set output '~/tfd.png'
set xdata time
set timefmt "%d.%m.%Y %H:%M:%S"
set format x "%H"
plot "data.csv" using 1:2 title 'temperatur'
1个回答

4
我可以想到三种方法来实现这个。如果你不需要在同一坐标轴上显示那些日期,第二种方法可能是最稳定的。第一种和第三种方法都有各自的优缺点。在这两种方法之间,第三种可能是更好的方法,但它需要更多的工作。
为了确保数据跨越超过1天,在这些示例中,我使用了您的相同数据,但添加了一个额外的行。
31.07.2012 19:30:04;22.7;53

所有三种方法都适用于5.0版本。

在4.6版本中,方法1无法正确对齐,但可以通过添加一个额外的命令来实现。

方法2应该适用于任何较新的版本。

由于迭代中存在溢出错误(请参见此处了解一些解释),因此方法3将无法在4.6版本中放置所有日期标签,但可以通过更改迭代以放置标签来使其工作。

方法1-多图

我们可以使用multiplot将相同的图形叠加在一起,并每次使用不同的x轴来完成此操作。

set datafile separator ";"
set xdata time
set timefmt "%d.%m.%Y %H:%M:%S"

# Increase bottom margin to allow room for dates
set bmargin at screen 0.1

set multiplot layout 1,1
    # tics starting at 0 every 6 hours showing hour
    set xtics 0,60*60*6 format "%H"
    plot "data.csv" using 1:2 with lines t "Temperature"

    # Tics starting at 0 every 24 hours showing day.month
    # moved down by 1 character to be under hours
    set xtics 0,60*60*24 format "%d.%m" offset 0,-1
    set origin 0,0 # This is not needed in version 5.0
    replot
unset multiplot

enter image description here

除了坐标轴标签的差异外,图表必须完全相同,以避免它们不对齐,并且会使y轴标签略微加粗,因为它们重叠在一起。
在5.0版本中,不需要使用“set origin”命令,但在4.6版本中需要。
方法二-次要轴
如果使用次要轴是可以接受的,您也可以采用这种方法。例如,如果日期显示在x2轴上,小时显示在x1轴上,我们可以这样做。
set datafile separator ";"
set xdata time
set x2data time
set timefmt "%d.%m.%Y %H:%M:%S"
set xtics 0,60*60*6 format "%H"
set x2tics 0,60*60*24 format "%d.%m"
plot "data.csv" using 1:2 with lines t "Temperature"

enter image description here

这消除了多绘图方法的一些问题,但导致两个数据标签位于不同的轴上。
第三种方法-手动设置标签
最后,我们可以手动设置标签。幸运的是,在最新版本的gnuplot中,我们可以使用循环,因此不必为其发出单独的命令,但我们必须自己计算标签。
我们可以使用stats命令计算标签。如果我们给它时间数据,stat命令将抱怨,因此我们必须在打开时间模式之前使用它,并且我们必须做一些工作来计算日边界。为了确保我们正在处理每天的开始而不是在中间某个时候,我们将日期解析为内部表示形式(自Unix纪元以来的秒数),并向下舍入到最近的86400的倍数(一天的秒数)。
总体上,我们可以做如下操作:
# in-large margin for date labels
set bmargin at screen 0.1
set datafile separator ";"

# Get first and last day in data file as STATS_min and STATS_max
stats "data.csv" u (floor(strptime("%d.%m.%Y %H:%M:%S",stringcolumn(1))/86400)*86400) nooutput

set xdata time
set timefmt "%d.%m.%Y %H:%M:%S"

set for [i=STATS_min:(STATS_max+86400):86400] label strftime("%d.%m",i) at i,graph 0 center offset 0,char -2

# set xtics every 6 hours
set xtics 0,60*60*6 format "%H"
plot "data.csv" using 1:2 with lines t "Temperature"

enter image description here

我们可以通过为标签编号来改进它,如果以后需要删除它们((i-STATS_min)/86400+1将使它们编号为1、2、3等)。请注意,与第一种方法一样,我们需要增加底部的边距大小。我在标签上添加了一天的额外时间,以覆盖gnuplot在x轴上可能进行的四舍五入。
在版本4.6中,存在处理迭代和整数溢出的错误。要在4.6中使用此解决方案,请更改
set for [i=STATS_min:(STATS_max+86400):86400] label strftime("%d.%m",i) at i,graph 0 center offset 0,char -2

days = (STATS_max-STATS_min)/86400+1
set for [i=0:days] label strftime("%d.%m",i*86400+STATS_min) at (i*86400+STATS_min),graph 0 center offset 0,char -2

我无法使用gnuplot 4.6 patchlevel 0 (Debian wheezy)和终端png或pngcairo重现您的输出。您使用的是哪个版本和终端? - Jan
更正:我可以使用pngcairo重现第二种方法!谢谢。 - Jan
我可以确认这三个都能使用png终端(我认为来自于libpng)和pngcairo终端。我在Windows 7上使用版本5。您是正确的,方法1和3似乎不能在4.6上工作。 - Matthew
1
我已经修改了方法1和3,它们现在可以与4.6版本一起工作。 - Matthew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接