Как правильно составить график событий при использовании matplotlib - PullRequest
11 голосов
/ 07 января 2012

У меня есть 3 списка, каждый из которых содержит числа, представляющие время.Время представляет собой происшествие.Например, в этом A у меня есть номер для каждого события A.Я хочу представить эти данные на графике.Любым из следующих двух способов:

1)

aabaaabbccacac

2)

a-> xx xxx    x x
b->   x   xx  
c->         xx x x

Ответы [ 5 ]

16 голосов
/ 09 января 2012

В качестве дополнения к предыдущим ответам вы можете использовать plt.hbar:

import matplotlib.pyplot as plt
import numpy as np
import string

x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
y = np.array([0, 0, 1, 0, 0, 0, 1, 1, 2, 2, 0, 2, 0, 2])

labels = np.array(list(string.uppercase))    
plt.barh(y, [1]*len(x), left=x, color = 'red', edgecolor = 'red', align='center', height=1)
plt.ylim(max(y)+0.5, min(y)-0.5)
plt.yticks(np.arange(y.max()+1), labels)
plt.show()

enter image description here

Или вы можете попробовать что-то вроде этого:

import matplotlib.pyplot as plt
import numpy as np

data = [[1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0],
        [0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0], 
        [0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 3, 0, 3]]

fig = plt.figure()
ax = fig.add_subplot(111)
ax.axes.get_yaxis().set_visible(False)
ax.set_aspect(1)

def avg(a, b):
    return (a + b) / 2.0

for y, row in enumerate(data):
    for x, col in enumerate(row):
        x1 = [x, x+1]
        y1 = np.array([y, y])
        y2 = y1+1
        if col == 1:
            plt.fill_between(x1, y1, y2=y2, color='red')
            plt.text(avg(x1[0], x1[1]), avg(y1[0], y2[0]), "A", 
                                        horizontalalignment='center',
                                        verticalalignment='center')
        if col == 2:
            plt.fill_between(x1, y1, y2=y2, color='orange')
            plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "B", 
                                        horizontalalignment='center',
                                        verticalalignment='center')
        if col == 3:
            plt.fill_between(x1, y1, y2=y2, color='yellow')
            plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "C", 
                                        horizontalalignment='center',
                                        verticalalignment='center')

plt.ylim(3, 0)
plt.show()

enter image description here

Если вы хотите, чтобы все слоты находились в одном ряду, просто внесите несколько изменений, как показано ниже:

import matplotlib.pyplot as plt
import numpy as np

data = [[1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0],
        [0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0], 
        [0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 3, 0, 3]]

fig = plt.figure()
ax = fig.add_subplot(111)
ax.axes.get_yaxis().set_visible(False)
ax.set_aspect(1)

def avg(a, b):
    return (a + b) / 2.0

for y, row in enumerate(data):
    for x, col in enumerate(row):
        x1 = [x, x+1]
        y1 = [0, 0]
        y2 = [1, 1]
        if col == 1:
            plt.fill_between(x1, y1, y2=y2, color='red')
            plt.text(avg(x1[0], x1[1]), avg(y1[0], y2[0]), "A", 
                                        horizontalalignment='center',
                                        verticalalignment='center')
        if col == 2:
            plt.fill_between(x1, y1, y2=y2, color='orange')
            plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "B", 
                                        horizontalalignment='center',
                                        verticalalignment='center')
        if col == 3:
            plt.fill_between(x1, y1, y2=y2, color='yellow')
            plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "C", 
                                        horizontalalignment='center',
                                        verticalalignment='center')

plt.ylim(1, 0)
plt.show()

enter image description here

Второй и третий варианты - больше кода, но они дают гораздо лучшие результаты.

10 голосов
/ 08 января 2012

Вы можете использовать plt.hlines :

import matplotlib.pyplot as plt
import random
import numpy as np
import string

def generate_data(N = 20):
    data = [random.randrange(3) for x in range(N)]
    A = [i for i, x in enumerate(data) if x == 0]
    B = [i for i, x in enumerate(data) if x == 1]
    C = [i for i, x in enumerate(data) if x == 2]
    return A,B,C

def to_xy(*events):
    x, y = [], []
    for i,event in enumerate(events):
        y.extend([i]*len(event))
        x.extend(event)
    x, y = np.array(x), np.array(y)
    return x,y

def event_string(x,y):
    labels = np.array(list(string.uppercase))        
    seq = labels[y[np.argsort(x)]]
    return seq.tostring()

def plot_events(x,y):
    labels = np.array(list(string.uppercase))    
    plt.hlines(y, x, x+1, lw = 2, color = 'red')
    plt.ylim(max(y)+0.5, min(y)-0.5)
    plt.yticks(range(y.max()+1), labels)
    plt.show()

A,B,C = generate_data(20)
x,y = to_xy(A,B,C)
print(event_string(x,y))
plot_events(x,y)

выходы

BBACBCACCABACCBCABCC

enter image description here

3 голосов
/ 07 января 2012

Это подход, с которого вы можете начать:

from matplotlib import pyplot as plt

A = [23,45,56,78,32,11]
B = [44,56,78,98]
C = [23,46,67,79]

x = []
y = []
for idx, lst in enumerate((A, B, C)):
    for time in lst:
        x.append(time)
        y.append(idx) 

plt.ylim((-3,5))
plt.yticks([0, 1, 2], ['A', 'B', 'C'])
plt.scatter(x,y, color='r', s=70)
plt.show()

enter image description here

2 голосов
/ 08 января 2012

Вы можете рассмотреть отображение расписания поездов, используемое на обложке книги Эдварда Туфте Визуальное отображение количественной информации .Это полезно для отображения скорости изменения событий в разное время (см. Пояснение на стр. 31, 2-е издание), но это имеет значение только в том случае, если ваши события происходят в нерегулярное время.

В любом случае, другойответы предоставляют хорошие варианты для вашего второго запроса.Вы можете просто захотеть построить линии с помощью команды pyplot (или axes) plot(x).Вы можете изменить метки, как показано в других ответах, чтобы они представляли собой текст, представляющий ваши события.Наконец, чтобы эмулировать эффект, показанный на рисунке расписания поездов, вы можете установить сетку, используя метод pyplot grid (или axes.xaxis.grid).

0 голосов
/ 16 февраля 2018

Создание и упрощение последнего графика @amillerrhodes (также с удалением текстовой части):

import matplotlib.pyplot as plt
import numpy as np

# run-length encoding, instead of a list of lists with a bunch of zeros
data = [(2, 1), (1, 2), (3, 1), (2, 2), (2, 3), (1, 1), (1, 3), (1, 1), (1, 3)]

fig = plt.figure()
ax = fig.add_subplot(111)
ax.axes.get_yaxis().set_visible(False)
ax.set_aspect(1)

for i, (num, cat) in enumerate(data):

    if i > 0:
        x_start += data[i-1][0] # get previous end position
    else:
        x_start = i             # start from 0

    x1 = [x_start, x_start+num]

    y1 = [0, 0]
    y2 = [1, 1]

    if cat == 1:
        plt.fill_between(x1, y1, y2=y2, color='red')
    if cat == 2:
        plt.fill_between(x1, y1, y2=y2, color='orange')
    if cat == 3:
        plt.fill_between(x1, y1, y2=y2, color='yellow')

plt.ylim(1, 0)
plt.show()

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...