Что не так с этим составленным барным сюжетом? - PullRequest
0 голосов
/ 31 марта 2020

Я действительно не понимаю, что с этим не так ... Я просмотрел довольно простые данные несколько раз и перезапустил ядро ​​(работает на Jupyter Notebook), и, похоже, ничего не решает.

Вот кадр данных, который у меня есть (извините, я знаю, что цифры выглядят немного глупо, это действительно редкий набор данных за длительный период времени, оригинал переиндексируется в течение 20 лет):

DATE        NODP            NVP             VP              VDP
03/08/2002  0.083623        0.10400659      0.81235517      1.52458E-05
14/09/2003  0.24669167      0.24806379      0.5052293       1.52458E-05
26/07/2005  0.15553726      0.13324796      0.7111538       0.000060983
20/05/2006  0               0.23            0.315           0.455
05/06/2007  0.21280034      0.29139224      0.49579217      1.52458E-05
21/02/2010  0               0.55502195      0.4449628       1.52458E-05
09/04/2011  0.09531311      0.17514162      0.72954527      0
14/02/2012  0.19213217      0.12866237      0.67920546      0
17/01/2014  0.12438848      0.10297326      0.77263826      0
24/02/2017  0.01541347      0.09897548      0.88561105      0

Обратите внимание, что все строки в сумме составляют 1! Я трижды, вчетверо проверил это ... XD

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

NODP = df['NODP']
NVP = df['NVP']
VDP = df['VDP']
VP = df['VP']
ind = np.arange(len(df.index))
width = 5.0

p1 = plt.bar(ind, NODP, width, label = 'NODP', bottom=NVP, color= 'grey')
p2 = plt.bar(ind, NVP, width, label = 'NVP', bottom=VDP, color= 'tan')
p3 = plt.bar(ind, VDP, width, label = 'VDP', bottom=VP, color= 'darkorange')
p4 = plt.bar(ind, VP, width, label = 'VP', color= 'darkgreen')
plt.ylabel('Ratio')
plt.xlabel('Year')
plt.title('Ratio change',x=0.06,y=0.8)
plt.xticks(np.arange(min(ind), max(ind)+1, 6.0), labels=xlabels) #the xticks were cumbersome so not included in this example code
plt.legend()

Что дает мне следующий график:

enter image description here

Как видно, 1) NODP не появляется в все, и 2) остальные из них строятся с неправильными пропорциями ...

Я действительно не понимаю, что не так, это должно быть действительно просто, верно ?! Извините, если это действительно просто, это, вероятно, прямо под моим носом. Любые идеи с благодарностью!

Ответы [ 2 ]

2 голосов
/ 31 марта 2020

Если вы хотите создать столбчатые столбцы таким образом (например, стандартный matplotlib без использования pandas или seaborn для построения графиков), нижняя часть должна быть суммой всех нижних столбцов.

Вот пример с данными.

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd

columns = ['DATE', 'NODP', 'NVP', 'VP', 'VDP']
data = [['03/08/2002', 0.083623, 0.10400659, 0.81235517, 1.52458E-05],
        ['14/09/2003', 0.24669167, 0.24806379, 0.5052293, 1.52458E-05],
        ['26/07/2005', 0.15553726, 0.13324796, 0.7111538, 0.000060983],
        ['20/05/2006', 0, 0.23, 0.315, 0.455],
        ['05/06/2007', 0.21280034, 0.29139224, 0.49579217, 1.52458E-05],
        ['21/02/2010', 0, 0.55502195, 0.4449628, 1.52458E-05],
        ['09/04/2011', 0.09531311, 0.17514162, 0.72954527, 0],
        ['14/02/2012', 0.19213217, 0.12866237, 0.67920546, 0],
        ['17/01/2014', 0.12438848, 0.10297326, 0.77263826, 0],
        ['24/02/2017', 0.01541347, 0.09897548, 0.88561105, 0]]
df = pd.DataFrame(data=data, columns=columns)
ind = pd.to_datetime(df.DATE)
NODP = df.NODP.to_numpy()
NVP = df.NVP.to_numpy()
VP = df.VP.to_numpy()
VDP = df.VDP.to_numpy()

width = 120
p1 = plt.bar(ind, NODP, width, label='NODP', bottom=NVP+VDP+VP, color='grey')
p2 = plt.bar(ind, NVP, width, label='NVP', bottom=VDP+VP, color='tan')
p3 = plt.bar(ind, VDP, width, label='VDP', bottom=VP, color='darkorange')
p4 = plt.bar(ind, VP, width, label='VP', color='darkgreen')
plt.ylabel('Ratio')
plt.xlabel('Year')
plt.title('Ratio change')
plt.yticks(np.arange(0, 1.001, 0.1))
plt.legend()
plt.show()

resulting plot

Обратите внимание, что в этом случае ось х измеряется в днях, и каждый столбец находится на своей дате , Это помогает узнать относительный интервал между датами, если это важно. Если это не важно, x-позиции могут быть выбраны равноудаленными и помечены через столбец дат.

Для этого со стандартным matplotlib изменится следующий код:

ind = range(len(df))
width = 0.8
plt.xticks(ind, df.DATE, rotation=20)
plt.tight_layout() # needed to show the full labels of the x-axis

example plot

1 голос
/ 31 марта 2020

График данных

# using your data above
df.DATE = pd.to_datetime(df.DATE)
df.set_index('DATE', inplace=True)

ax = df.plot(stacked=True, kind='bar', figsize=(12, 8))
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)

# sets the tick labels so time isn't included
ax.xaxis.set_major_formatter(plt.FixedFormatter(df.index.to_series().dt.strftime("%Y-%m-%d")))

plt.show()

enter image description here

Добавьте метки для ясности

  • Добавив следующий код перед plt.show() Вы можете добавить текстовые аннотации к столбцам
# .patches is everything inside of the chart
for rect in ax.patches:
    # Find where everything is located
    height = rect.get_height()
    width = rect.get_width()
    x = rect.get_x()
    y = rect.get_y()

    # The width of the bar is the data value and can used as the label
    label_text = f'{height:.2f}'  # f'{height:.2f}' if you have decimal values as labels

    label_x = x + width - 0.125
    label_y = y + height / 2

    # don't include label if it's equivalently 0
    if height > 0.001:
        ax.text(label_x, label_y, label_text, ha='right', va='center', fontsize=8)

plt.show()

enter image description here

...