Подтвердить что ты не робот

Пометка интервалов с метками в matplotlib/gnuplot

У меня есть образец данных, который выглядит так:

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, этот тип сюжета должен быть проще сделать в последнем, поскольку он не является стандартным сюжетом и требуется некоторая предварительная обработка.

Возникает вопрос:

  • Есть ли стандартный способ делать такие графики в любом из инструментов?
  • Если нет, как мне следует планировать эти данные (указатели на соответствующие инструменты/документацию/функции/примеры, которые делают что-то вроде вида, описанного здесь)?
4b9b3361

Ответ 1

Обновлено: теперь включает обработку образца данных и использование функций дат 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

Ответ 2

Гнуплот 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 вверх по течению.

Выход:

enter image description here

Вы можете удалить метки, удалив вторую командную строку plot, я добавил их, потому что они полезны во многих приложениях для более простой идентификации интервалов.

Пример Ганта, с которым я связан, показывает, как обрабатывать форматы даты вместо целых.

Протестировано в gnuplot 5.2 patchlevel 2, Ubuntu 18.04.

Ответ 3

версия gnuplot 5.2 с созданием уникального списка ключей

Основное отличие решения @CiroSantilli состоит в том, что список уникальных ключей создается автоматически из столбца 1, и к индексу можно получить доступ через определенную функцию Lookup(). Ссылочная демонстрационная версия gnuplot уже использует список уникальных элементов, однако в случае OP есть дубликаты.

Создание такого списка уникальных элементов не существует в gnuplot сразу, поэтому вы должны реализовать его самостоятельно. Код требует gnuplot> = 5.2. Вероятно, трудно получить решение, которое работает в gnuplot 4.4 (время вопроса OP), потому что в то время не было реализовано несколько полезных функций: do for -loops, summation, блоки данных,... (версия для gnuplot 4.6 может быть возможно с некоторыми обходными путями).

Редактировать: более ранняя версия использовалась with vectors и linewidth 20 для построения with vectors, однако linewidth 20 также расширяется в направлении х, что здесь нежелательно. Поэтому 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