2

I have a data frame:

import pandas as pd
data = {
'BU': ['A', 'C', 'C', 'E', 'E', 'A', 'D', 'C', 'D', 'E', 'A', 'A', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'A', 'B', 'C', 'E', 'E', 'A', 'A'],
'Sub - BU': ['A2', 'B1', 'C1', 'D1', 'E1', 'A1', 'B1', 'C1', 'D1', 'E2', 'A1', 'B1', 'C1', 'D2', 'E2', 'A1', 'B1', 'C1', 'D1', 'E1', 'C1', 'D2', 'E1', 'E2', 'A1', 'A1'],
'Initial contract result': [0, 2, 0, 1, 3, 2, 0, 0, 0, 9, 0, 5, 2, 0, 0, 8, 7, 4, 0, 0, 0, 0, 5, 0, 8, 4]} 
df_cur = pd.DataFrame(data)

df_cur['Contract Sum Type'] = df_cur['Initial contract result'].apply(lambda x: 'Zero' if x == 0 else 'Non-zero')
counts_df = df_cur.groupby(['BU', 'Sub - BU', 'Contract Sum Type']).size().reset_index(name='Count')

group_totals = counts_df.groupby(['BU', 'Sub - BU'])['Count'].transform('sum')
counts_df['Percentage'] = 100 * counts_df['Count'] / group_totals

counts_df['Total Count'] = counts_df.groupby('Sub - BU')['Count'].transform('sum')

Now I want to plot this as a stacked bar chart. On the x axis I want to see the Sub - BU but also I want it to be grouped by the BU column and each BU should get its own colors. Also the stacked bar chart should be descending. How to do this, because the fig.updatelayout commant doesnt seem to do anything in this also I tried creating a subset where I filter the dataframe descending based on the Total Count column but this didnt work.

import plotly.express as px
fig = px.bar(counts_df, x='Sub - BU', y='Count', color='Contract Sum Type', 
         title='Initial Contract Sum by Sub - BU', barmode='stack', text_auto=True)

fig.update_layout(yaxis={'categoryorder':'total ascending'})

fig.show()
mozway
  • 194,879
  • 13
  • 39
  • 75
hvahva
  • 51
  • 5

2 Answers2

2

Unless I misunderstand your question you could do something like this:

import pandas as pd
import plotly.express as px

data = {
    'BU': ['A', 'C', 'C', 'E', 'E', 'A', 'D', 'C', 'D', 'E', 'A', 'A', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'A', 'B', 'C', 'E', 'E', 'A', 'A'],
    'Sub - BU': ['A2', 'B1', 'C1', 'D1', 'E1', 'A1', 'B1', 'C1', 'D1', 'E2', 'A1', 'B1', 'C1', 'D2', 'E2', 'A1', 'B1', 'C1', 'D1', 'E1', 'C1', 'D2', 'E1', 'E2', 'A1', 'A1'],
    'Initial contract result': [0, 2, 0, 1, 3, 2, 0, 0, 0, 9, 0, 5, 2, 0, 0, 8, 7, 4, 0, 0, 0, 0, 5, 0, 8, 4]
}

df_cur = pd.DataFrame(data)

df_cur['Contract Sum Type'] = df_cur['Initial contract result'].apply(lambda x: 'Zero' if x == 0 else 'Non-zero')
counts_df = df_cur.groupby(['BU', 'Sub - BU', 'Contract Sum Type']).size().reset_index(name='Count')

group_totals = counts_df.groupby(['BU', 'Sub - BU'])['Count'].transform('sum')
counts_df['Percentage'] = 100 * counts_df['Count'] / group_totals

counts_df['Total Count'] = counts_df.groupby('Sub - BU')['Count'].transform('sum')

# sort by descending Total Count within each BU
counts_df = counts_df.sort_values(['BU', 'Total Count'], ascending=[True, False])

fig = px.bar(counts_df, x='Sub - BU', y='Count', color='Contract Sum Type',
             title='Initial Contract Sum by Sub - BU', barmode='stack',
             text='Percentage', facet_col='BU', color_discrete_sequence=px.colors.qualitative.Set1)

fig.update_layout(yaxis={'categoryorder': 'total descending'})

fig.show()

which give

enter image description here

2

To create a grouping and stacking graph, the x-axis can be graphed by specifying a grouping column and a subgroup column in the list.

import plotly.graph_objects as go

fig = go.Figure()

for t in counts_df['Contract Sum Type'].unique():
    dff = counts_df[counts_df['Contract Sum Type'] == t]
    fig.add_trace(go.Bar(x=[dff['BU'], dff['Sub - BU']], y=dff['Count'], name=t))

fig.update_layout(barmode='stack', legend_title='Contract Sum Type')
fig.show()

enter image description here

Set different colours for different groups


import plotly.graph_objects as go
import plotly.express as px

colors = px.colors.qualitative.T10

fig = go.Figure()
i = 0
for t in counts_df['Contract Sum Type'].unique():
    for g in counts_df['BU'].unique():
        dff = counts_df[(counts_df['Contract Sum Type'] == t) & (counts_df['BU'] == g)]
        fig.add_trace(go.Bar(x=[dff['BU'], dff['Sub - BU']], y=dff['Count'], name=t, marker=dict(color=colors[i])))
        i += 1

# names = set()
# fig.for_each_trace(
#     lambda trace:
#         trace.update(showlegend=False)
#         if (trace.name in names) else names.add(trace.name))

fig.update_layout(barmode='stack', legend_title='Contract Sum Type')
fig.show()

enter image description here

r-beginners
  • 31,170
  • 3
  • 14
  • 32
  • Hi how to make this plot descending? – hvahva Mar 09 '23 at 11:24
  • 1
    If the original data frame is ordered as desired, the graph will be as intended. – r-beginners Mar 09 '23 at 12:36
  • Any idea how I can give the different groups a different color? So group A should get a unique color for zero and Non-zero and the same for B , C , E , D – hvahva Mar 10 '23 at 14:05
  • 1
    Coloring each group differently adds group-specific processing to the zero and nonzero loop process. A legend is added to each loop process. To avoid duplicate legends, enable the commented-out process so that there are two legends. The color of the legend will be the color of the first one. – r-beginners Mar 10 '23 at 14:40