Гистограмма со сложенными компонентами

Допустим, у меня есть значение, которое я измерял каждый день в течение последних 90 дней. Я хотел бы построить гистограмму значений, но я хочу, чтобы зритель мог легко увидеть, где накопились измерения за определенные неперекрывающиеся подмножества за последние 90 дней. Я хочу сделать это, «разбив» каждую полосу гистограммы на части. Один кусок для самых ранних наблюдений, один для более поздних, один для самых последних.

Похоже, это работа для df.plot(kind='bar', stacked=True), но у меня проблемы с уточнением деталей.

Вот что у меня есть на данный момент:

import numpy as np
import pandas as pd
import seaborn as sbn

np.random.seed(0)

data = pd.DataFrame({'values': np.random.randn(90)})
data['bin'] = pd.cut(data['values'], 15, labels=False)
forhist = pd.DataFrame({'first70': data[:70].groupby('bin').count()['bin'],
                         'next15': data[70:85].groupby('bin').count()['bin'],
                         'last5': data[85:].groupby('bin').count()['bin']})

forhist.plot(kind='bar', stacked=True)

И это дает мне:

плохой результат

У этого графика есть недостатки:

  • Полосы уложены в неправильном порядке. last5 должен быть сверху, а next15 посередине. Т.е. они должны быть расположены в порядке столбцов в forhist.
  • Между планками есть горизонтальное пространство
  • Ось x помечена целыми числами, а не чем-то показывающим значения, которые представляют ячейки. Моим «первым выбором» было бы пометить ось x точно так, как если бы я просто запустил data['values'].hist(). Моим «вторым выбором» было бы, чтобы на оси x были помечены «имена бункеров», которые я получил бы, если бы сделал pd.cut(data['values'], 15). В моем коде я использовал labels=False, потому что, если бы я этого не делал, он использовал бы метки краев бункера (как строки) в качестве меток столбцов, и он поместил бы их в алфавитном порядке, что сделало бы график практически бесполезным.

Как лучше всего подойти к этому? Мне кажется, что пока я использую очень неуклюжие функции.


person 8one6    schedule 06.03.2014    source источник


Ответы (1)


Хорошо, вот один из способов атаковать его, используя возможности самой функции matplotlib hist:

fig, ax = plt.subplots(1, 1, figsize=(9, 5))
ax.hist([data.ix[low:high, 'values'] for low, high in [(0, 70), (70, 85), (85, 90)]],
         bins=15,
         stacked=True,
         rwidth=1.0,
         label=['first70', 'next15', 'last5'])
ax.legend()

Который дает:

лучше

person 8one6    schedule 06.03.2014