Гистограмма с накоплением с использованием matplotlib и pandas dataframe

У меня есть некоторые данные:

df = pd.DataFrame({
    'Plan': [40, 50, 60, 25],
    'Fact': [10, 20, 30, 15],
    'financing_type': ['type_1', 'type_2', 'type_1', 'type_3']
})

И мне нужно построить два столбца разного цвета в зависимости от суммы финансирования_типа
Именно так:

Я сделал это следующим образом:

df_type_1 = df[df['financing_type'] == 'type_1']
df_type_2 = df[df['financing_type'] == 'type_2']
df_type_3 = df[df['financing_type'] == 'type_3']

plt.bar(['Plan', 'Fact'], [df_type_1['Plan'].sum(), df_type_1['Fact'].sum()], color='blue', label='type_1')
plt.bar(
    ['Plan', 'Fact'],
    [df_type_2['Plan'].sum(), df_type_2['Fact'].sum()], 
    bottom=[df_type_1['Plan'].sum(), df_type_1['Fact'].sum()], 
    color='red', 
    label='type_2',
)
plt.bar(
    ['Plan', 'Fact'],
    [df_type_3['Plan'].sum(), df_type_3['Fact'].sum()], 
    bottom=[df_type_1['Plan'].sum() + df_type_2['Plan'].sum(), df_type_1['Fact'].sum() + df_type_2['Fact'].sum()], 
    color='green', 
    label='type_3',
)
plt.legend()
plt.show()

Как я могу это сделать для более распространенного случая? Если я не знаю, сколько разных типов в столбце «finance_type».

Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Вот подход:

  • Объедините столбцы «План» и «Факт», чтобы создать фрейм данных длинной формы.
  • Создайте pivot_table, суммируя значения для каждого типа.
  • Создайте составную линейчатую диаграмму из сводной таблицы.
import pandas as pd

# Given a dataframe
df = pd.DataFrame({
    'Plan': [40, 50, 60, 25],
    'Fact': [10, 20, 30, 15],
    'financing_type': ['type_1', 'type_2', 'type_1', 'type_3']})

# Melt the DataFrame
df_melted = df.melt(id_vars=['financing_type'], var_name='Category', value_name='Value')

# Pivot the dataFrame to get the sum of 'Plan' and 'Fact' for each 'financing_type'
df_pivot = df_melted.pivot_table(index='Category', columns='financing_type', values='Value', aggfunc='sum')

# Reorder the index of the pivoted dataframe
df_pivot = df_pivot.reindex(['Plan', 'Fact'])

# Create a stacked bar plot
df_pivot.plot.bar(stacked=True, rot=0, xlabel='')

В качестве альтернативы вы можете использовать seaborn для создания составной взвешенной гистограммы:

import seaborn as sns
import pandas as pd

# Given a dataframe
df = pd.DataFrame({
    'Plan': [40, 50, 60, 25],
    'Fact': [10, 20, 30, 15],
    'financing_type': ['type_1', 'type_2', 'type_1', 'type_3']})

# Melt the DataFrame
df_melted = df.melt(id_vars=['financing_type'], var_name='Category', value_name='Value')

# Create a stacked, weighted histogram 
sns.histplot(df_melted, x='Category', hue='financing_type', weights='Value', multiple='stack', alpha=1)

Вы можете перебирать уникальные значения в 'financing_type' и отслеживать значения bottom:

bottom = [0, 0]
colors = ["blue", "red", "green"]

for i, t in enumerate(df["financing_type"].unique()):
    df_t = df[df["financing_type"] == t]
    plan_sum = df_t["Plan"].sum()
    fact_sum = df_t["Fact"].sum()

    plt.bar(
        ["Plan", "Fact"],
        [plan_sum, fact_sum],
        bottom=bottom,
        color=colors[i % len(colors)],
        label=t,
    )

    bottom[0] += plan_sum
    bottom[1] += fact_sum

plt.legend()
plt.show()

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