Как создать гистограмму с двойной сгруппированной осью с помощью Pandas

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

data_dict = {'major_group': list(np.array([['A']*10, ['B']*10]).flat), 
'minor_group': ['q ','r ','s ','t ']*5,
'legend_group':np.repeat(['d','e','f','g','h','i'],[7,3,1,5,1,3])}
(pd.DataFrame(data= data_dict)
.groupby(['major_group', 'minor_group','legend_group'], observed = True)
.size()
.unstack()
.plot(kind='barh', stacked=True))

Результат:

Однако я ищу что-то вроде этого:

Как этого можно достичь? Можно ли установить какие-либо метки главной и второстепенной оси?

Это сложнее, чем вы думаете... stackoverflow.com/q/31845258/6361531

Scott Boston 02.08.2024 19:00
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Этот код создаст горизонтальные столбцы, иерархически сгруппированные в метке оси Y:

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

def create_data() -> DataFrame:
    data_dict = {
        'major_group': list(np.array([['A'] * 10, ['B'] * 10]).flat), 
        'minor_group': ['q', 'r', 's', 't'] * 5,
        'legend_group': np.repeat(['d', 'e', 'f', 'g', 'h', 'i'], [7, 3, 1, 5, 1, 3])
    }
    return pd.DataFrame(data=data_dict).groupby(['major_group', 'minor_group', 'legend_group'], observed=True).size().unstack()

def plot_stacked_barh(df: DataFrame) -> None:
    fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True)

    for i, major_group in enumerate(df.index.levels[0]):
        ax = axes[i]
        df.loc[major_group].plot(kind='barh', stacked=True, ax=ax, width=.8)

        if i == 0:
            handles, labels = ax.get_legend_handles_labels()

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

    fig.legend(handles, labels, title='Legend Group')

    plt.tight_layout()
    fig.subplots_adjust(hspace=0)
    plt.show()

def main() -> None:
    df = create_data()
    print(df)
    plot_stacked_barh(df)

if __name__ == "__main__":
    main()

Аналогичный вертикальный эквивалент можно найти здесь.

Мое предложение состоит в том, чтобы нарисовать GridSpec на основе value_counts основной группы (в вашем DataFrame) и поместить TextPath (например, [, {, (, ...) внутри вторичных осей. :

import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from matplotlib.patches import PathPatch
from matplotlib.text import TextPath

def brack_it(idx, maj_grp, txt = "["):
    plt.subplot(gs[idx, 0]).axis("off")
    tw = plt.gca().twinx()
    tw.set(xticks=[], yticks=[])
    tw.set_ylabel(maj_grp, labelpad=-10)
    tw.spines[list(tw.spines)].set_visible(False)
    tw.add_artist(PathPatch(TextPath((0.5, 0.12), txt, size=1.1), fc = "k"))

vc = df.reset_index().value_counts("major_group", normalize=True)

plt.figure(figsize=(6, 3))

gs = GridSpec(len(vc), 2, width_ratios=(1, 5), height_ratios=vc, wspace=0.1)

df.droplevel("major_group").rename_axis(None).plot.barh(
    stacked=True, legend=False, grid=False, alpha=.9,
    ax=plt.subplot(gs[:, 1]),
)

for i, n in enumerate(vc.index[::-1]):
    brack_it(i, n)

Хорошее решение! Но, к сожалению, он плохо сочетался с длиной меток второстепенных групп. Когда на этих метках появляется больше символов, основная группа печатается прямо через них или поверх них.

saQuist 08.08.2024 09:58

Другие вопросы по теме