Гистограмма с индивидуальной шириной в Python - PullRequest
2 голосов
/ 10 января 2020

У меня есть этот фрейм данных df, который содержит -

Name       Team Name        Category       Challenge      Points            Time
 A            B               1              1ABC           50       2019-11-04 07:37:02        
 D            B               2              2ACE          150       2019-11-04 09:57:02
 X            P               4              4PQR          500       2019-11-05 08:45:02
 A            B               3              3PQR           10       2019-11-04 10:25:20
 N            P               4              4ABC          120       2019-11-05 08:35:00
 C            G               1              1ABC           50       2019-11-04 07:37:02
 D            B               4              4RST          200       2019-11-04 10:57:02

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

enter image description here

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

df.groupby(['Team Name'])['Challenge'].count().plot.bar()

, но кроме этого, я не знаю, как изменить ширину стержня. Может ли кто-нибудь помочь с этим? В качестве альтернативы, если у кого-то есть лучшее представление о том, как его визуализировать, используя любой из обычных сюжетов, я бы тоже хотел услышать ваше мнение.

Спасибо!

1 Ответ

2 голосов
/ 10 января 2020

Похоже ли это на то, что вы хотите?

enter image description here

Вы можете сделать это sh, вручную нарисовав 'блоки' с помощью matplotlib.patches , это просто требует дополнительных манипуляций, чтобы сделать это алгоритмически. Вот полный пример с использованием данных, представленных в вопросе

import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import numpy as np
import pandas as pd

t20 = [(31, 119, 180), (174, 199, 232), (255, 127, 14), (255, 187, 120)]
for i in range(len(t20)):    
    r, g, b = t20[i]    
    t20[i] = (r / 255., g / 255., b / 255.)

fig, ax = plt.subplots(1)
df['Time'] = pd.to_datetime(df['Time'])
df = df.sort_values('Time')
cat = df['Category'].unique()
cidx = dict(zip(cat, range(len(cat))))

mw = max(df['Points'])
names = list(df['Team Name'].unique())
nt = len(names)
h = 0.5
hs = [0]*3
for ii in range(len(df.index)):
    w = float(df['Points'].iloc[ii])/mw
    idx = names.index(df['Team Name'].iloc[ii])
    r = Rectangle((idx - w/2.0, hs[idx]), w, h, color=t20[cidx[df['Category'].iloc[ii]]])
    hs[idx] += 0.5
    ax.add_patch(r)
plt.xlim([-0.5, len(names)-0.5])
plt.ylim([0, max(hs)+3])
plt.xticks(range(len(names)), names)
plt.show()

Я использовал первые 4 цвета в палитре tableau на случай, если вы заинтересованы.


Редактировать

Вы можете добавить легенду со строкой

plt.legend(handles=[Patch(facecolor=t20[ii], label=cat[ii]) for ii in range(len(t20))])

, если включен дополнительный импорт Patches из matplotlib.patches, то есть

from matplotlib.patches import Rectangle, Patch

А на выходе будет

Plot with legend

...