在matplotlib / gnuplot中绘制标记的间隔

时间:2011-10-07 07:54:52

标签: plot matplotlib gnuplot intervals

我有一个如下所示的数据样本:

a 10:15:22 10:15:30 OK
b 10:15:23 10:15:28 OK
c 10:16:00 10:17:10 FAILED
b 10:16:30 10:16:50 OK

我想要的是以下列方式绘制上述数据:

captions ^
  |
c |         *------*
b |   *---*    *--*
a | *--*
  |___________________
                     time >

线条的颜色取决于数据点的OK/FAILED状态。标签(a/b/c/...)可能重复也可能不重复。

正如我从 gnuplot matplotlib 的文档中收集的那样,这种类型的情节应该更容易在后者中进行,因为它不是标准情节而且会需要一些预处理。

问题是:

  1. 在任何工具中都有标准的方法来制作这样的图吗?
  2. 如果没有,我应该如何绘制这些数据(指向相关工具/文档/函数/示例,这些指针有点像这里描述的那样)?

3 个答案:

答案 0 :(得分:23)

更新:现在包括处理数据样本并使用mpl日期功能。

import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter, MinuteLocator, SecondLocator
import numpy as np
from StringIO import StringIO
import datetime as dt

### The example data
a=StringIO("""a 10:15:22 10:15:30 OK
b 10:15:23 10:15:28 OK
c 10:16:00 10:17:10 FAILED
b 10:16:30 10:16:50 OK
""")

#Converts str into a datetime object.
conv = lambda s: dt.datetime.strptime(s, '%H:%M:%S')

#Use numpy to read the data in. 
data = np.genfromtxt(a, converters={1: conv, 2: conv},
                     names=['caption', 'start', 'stop', 'state'], dtype=None)
cap, start, stop = data['caption'], data['start'], data['stop']

#Check the status, because we paint all lines with the same color 
#together
is_ok = (data['state'] == 'OK')
not_ok = np.logical_not(is_ok)

#Get unique captions and there indices and the inverse mapping
captions, unique_idx, caption_inv = np.unique(cap, 1, 1)

#Build y values from the number of unique captions.
y = (caption_inv + 1) / float(len(captions) + 1)

#Plot function
def timelines(y, xstart, xstop, color='b'):
    """Plot timelines at y from xstart to xstop with given color."""   
    plt.hlines(y, xstart, xstop, color, lw=4)
    plt.vlines(xstart, y+0.03, y-0.03, color, lw=2)
    plt.vlines(xstop, y+0.03, y-0.03, color, lw=2)

#Plot ok tl black    
timelines(y[is_ok], start[is_ok], stop[is_ok], 'k')
#Plot fail tl red
timelines(y[not_ok], start[not_ok], stop[not_ok], 'r')

#Setup the plot
ax = plt.gca()
ax.xaxis_date()
myFmt = DateFormatter('%H:%M:%S')
ax.xaxis.set_major_formatter(myFmt)
ax.xaxis.set_major_locator(SecondLocator(interval=20)) # used to be SecondLocator(0, interval=20)

#To adjust the xlimits a timedelta is needed.
delta = (stop.max() - start.min())/10

plt.yticks(y[unique_idx], captions)
plt.ylim(0,1)
plt.xlim(start.min()-delta, stop.max()+delta)
plt.xlabel('Time')
plt.show()

Resulting image

答案 1 :(得分:0)

gnuplot with vector解决方案

最小化于:http://gnuplot.sourceforge.net/demo_5.2/gantt.html

main.gnuplot

#!/usr/bin/env gnuplot

$DATA << EOD
1 1 5
1 11 13
2 3 10
3 4 8
4 7 13
5 6 15
EOD

set terminal png size 512,512
set output "main.png"
set xrange [-1:]
set yrange [0:]
unset key
set border 3
set xtics nomirror
set ytics nomirror
set style arrow 1 nohead linewidth 3
plot $DATA using 2 : 1 : ($3-$2) : (0.0) with vector as 1, \
     $DATA using 2 : 1 : 1 with labels right offset -2

GitHub upstream

输出:

enter image description here

您可以通过删除第二个plot命令行来删除标签,我之所以添加它们是因为它们在许多应用程序中对于更轻松地识别时间间隔很有用。

我链接到的甘特示例显示了如何处理日期格式而不是整数。

在gnuplot 5.2补丁程序级别2(Ubuntu 18.04)中进行了测试。

答案 2 :(得分:0)

gnuplot 5.2版本,具有创建唯一密钥列表的功能

与@CiroSantilli解决方案的主要区别在于,从第1列自动创建唯一键列表,并且可以通过定义的函数Lookup()访问索引。所引用的gnuplot演示已经使用了唯一项列表,但是,在OP中,存在重复项。

在gnuplot中并不立即创建这样的唯一项列表,因此您必须自己实现它。 该代码要求gnuplot> = 5.2。可能很难获得在gnuplot 4.4(OP提出问题的时间)下工作的解决方案,因为当时尚未实现一些有用的功能:do for-循环,summation,数据块等。 。(某些解决方法可能会使用gnuplot 4.6的版本)。

编辑:较早的版本使用with vectorslinewidth 20绘制条形图,但是linewidth 20也沿x方向延伸,这在此处是不希望的。因此,现在使用with boxxyerror

代码:

### Time chart
reset session

$Data <<EOD
# category        start    end      status
"event 1"         10:15:22 10:15:30 OK
"event 2"         10:15:23 10:15:28 OK
pause             10:16:00 10:17:10 FAILED
"something else"  10:16:30 10:17:50 OK
unknown           10:17:30 10:18:50 OK
"event 3"         10:18:30 10:19:50 FAILED
pause             10:19:30 10:20:50 OK
"event 1"         10:17:30 10:19:20 FAILED
EOD

# create list of keys
List = ''
set table $Dummy
    plot $Data u (List=List.'"'.strcol(1).'" ',NaN) w table
unset table

# create list of unique keys
UniqueList = ''
do for [i=1:words(List)] {
    item = word(List,i)
    found = 0
    do for [j=1:words(UniqueList)] {
        if (item eq word(UniqueList,j)) { found=1; break }
    }
    if (!found) { UniqueList = UniqueList.'"'.item.'" '}
}
print UniqueList

# define functions for lookup and color
Lookup(s) = (Index = NaN, sum [i=1:words(UniqueList)] \
    (Index = s eq word(UniqueList,i) ? i : Index,0), Index)
Color(s) = s eq "OK" ? 0x00cc00 : 0xff0000

set xdata time
set timefmt  "%H:%M:%S"
set format x "%M'".'%S"'
set yrange [0.5:words(UniqueList)+0.5]
plot $Data u (timecolumn(2)):(Idx=Lookup(strcol(1))): \
    (timecolumn(3)):(timecolumn(2)):(Idx-0.3):(Idx+0.3): \
    (Color(strcol(4))):ytic(strcol(1)) \
    w boxxyerror fill solid 1.0 lc rgb var notitle
### end of code

结果:

enter image description here