как построить метки иерархии в горизонтальной гистограмме

1

Я хотел бы иметь горизонтальную стеклянную гистограмму с ярлыками иерархии по оси y. Я немного искал и нашел следующий хороший пример и код.

Но это для вертикальной штабелированной гистограммы. Я хочу применить его к горизонтальной гистограмме, поэтому я просто изменил kind='barh', но это не сработает.

Мне удалось удалить идентификаторы по умолчанию, изменив все x на y в последних нескольких строках. Но изменение x в y в определенных функциях не дало мне то, что я хочу: метки иерархии все еще находятся на оси x.

Может ли кто-нибудь помочь? Благодарю.

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

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

def test_table():
data_table = pd.DataFrame({'Room': ['Room A'] * 4 + ['Room B'] * 3,
                       'Shelf': ['Shelf 1'] * 2 + ['Shelf 2'] * 2 + ['Shelf 1'] * 2 + ['Shelf 2'],
                       'Staple':['Milk', 'Water', 'Sugar', 'Honey', 'Wheat', 'Corn', 'Chicken'],
                       'Quantity': [10, 20, 5, 6, 4, 7, 2,],
                       'Ordered': np.random.randint(0, 10, 7)
                       })
data_table
def add_line(ax, xpos, ypos):
line = plt.Line2D([xpos, xpos], [ypos + .1, ypos],
                  transform=ax.transAxes, color='black')
line.set_clip_on(False)
ax.add_line(line)

def label_len(my_index,level):
labels = my_index.get_level_values(level)
return [(k, sum(1 for i in g)) for k,g in groupby(labels)]

def label_group_bar_table(ax, df):
ypos = -.1
scale = 1./df.index.size
for level in range(df.index.nlevels)[::-1]:
    pos = 0
    for label, rpos in label_len(df.index,level):
        lxpos = (pos + .5 * rpos)*scale
        ax.text(lxpos, ypos, label, ha='center', transform=ax.transAxes)
        add_line(ax, pos*scale, ypos)
        pos += rpos
    add_line(ax, pos*scale , ypos)
    ypos -= .1

df = test_table().groupby(['Room','Shelf','Staple']).sum()
fig = plt.figure()
ax = fig.add_subplot(111)
df.plot(kind='bar',stacked=True,ax=fig.gca())

#Below 3 lines remove default labels
labels = ['' for item in ax.get_xticklabels()]
ax.set_xticklabels(labels)
ax.set_xlabel('')
label_group_bar_table(ax, df)
fig.subplots_adjust(bottom=.1*df.index.nlevels)
plt.show()
Теги:
pandas
matplotlib
axis-labels

1 ответ

1
Лучший ответ

Вы можете сделать что-то подобное.

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import pandas as pd
import numpy as np

data_table = pd.DataFrame({'Room': ['Room A'] * 4 + ['Room B'] * 3,
                           'Shelf': ['Shelf 1'] * 2 + ['Shelf 2'] * 2 + ['Shelf 1'] * 2 + ['Shelf 2'],
                           'Staple': ['Milk', 'Water', 'Sugar', 'Honey', 'Wheat', 'Corn', 'Chicken'],
                           'Quantity': [10, 20, 5, 6, 4, 7, 2, ],
                           'Ordered': np.random.randint(0, 10, 7)
                           })

arrays = [list(data_table['Room']), list(data_table['Shelf']), list(data_table['Staple'])]
data_table = data_table.groupby(['Room', 'Shelf', 'Staple']).sum()
index = pd.MultiIndex.from_tuples(list(zip(*arrays)))

df = pd.DataFrame(data_table[['Ordered', 'Quantity']], index=index).T

# plotting
fig = plt.figure()
height_ratios = [len(df[df.columns.levels[0][0]].columns), len(df[df.columns.levels[0][1]].columns)] #i.e. 4, 3
gs = gridspec.GridSpec(nrows=len(df.columns.levels[0]), ncols=1, height_ratios=height_ratios)

ax1 = fig.add_subplot(gs[0,0])
ax2 = fig.add_subplot(gs[1,0], sharex=ax1)
axes = [ax1, ax2]
for i, col in enumerate(df.columns.levels[0]):
    print(col)
    ax = axes[i]
    df[col].T.plot(ax=ax, stacked=True, kind='barh', width=.8)

    ax.legend_.remove()
    ax.set_ylabel(col, weight='bold')
    ax.xaxis.grid(b=True, which='major', color='black', linestyle='--', alpha=.4)
    ax.set_axisbelow(True)

    for tick in ax.get_xticklabels():
        tick.set_rotation(0)

ax.legend()
# make the ticklines invisible
ax.tick_params(axis=u'both', which=u'both', length=0)
plt.tight_layout()
# remove spacing in between
fig.subplots_adjust(wspace=0)  # space between plots

plt.show()

Изображение 174551

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

  • 0
    Спасибо Крис за помощь. Но у моего настоящего df больше уровней, скажем так: arrays = [['Fruit', 'Fruit', 'Fruit', 'Veggies', 'Veggies', 'Veggies','Fruit', 'Fruit', 'Fruit', 'Veggies'], ['Bananas', 'Oranges', 'Pears', 'Carrots', 'Potatoes', 'Celery','Bananas', 'Oranges', 'Pears', 'Carrots'], ['A','B','C','D','E','nan','G','H','I','J'], ['a','b','c','d','e','f','nan','h','i','nan']] index = pd.MultiIndex.from_tuples(list(zip(*arrays))) df = pd.DataFrame(np.random.randint(10, 50, size=(4, 10)), columns=index) df.sort_index(axis=1,inplace=True) .
  • 0
    Мои вопросы: 1. Как я могу показать другие уровни также в иерархии? 2. как сделать так, чтобы толщина стержня автоматически рассчитывалась как равная? 3. как можно избавиться от nan , а не показывать их на графике?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню