Stacked Bar Plot Using Matplotlib

stacked bar plot using matplotlib

You need the bottom of each dataset to be the sum of all the datasets that came before. you may also need to convert the datasets to numpy arrays to add them together.

p1 = plt.bar(ind, dataset[1], width, color='r')
p2 = plt.bar(ind, dataset[2], width, bottom=dataset[1], color='b')
p3 = plt.bar(ind, dataset[3], width,
bottom=np.array(dataset[1])+np.array(dataset[2]), color='g')
p4 = plt.bar(ind, dataset[4], width,
bottom=np.array(dataset[1])+np.array(dataset[2])+np.array(dataset[3]),
color='c')

Sample Image

Alternatively, you could convert them to numpy arrays before you start plotting.

dataset1 = np.array(dataset[1])
dataset2 = np.array(dataset[2])
dataset3 = np.array(dataset[3])
dataset4 = np.array(dataset[4])

p1 = plt.bar(ind, dataset1, width, color='r')
p2 = plt.bar(ind, dataset2, width, bottom=dataset1, color='b')
p3 = plt.bar(ind, dataset3, width, bottom=dataset1+dataset2, color='g')
p4 = plt.bar(ind, dataset4, width, bottom=dataset1+dataset2+dataset3,
color='c')

Or finally if you want to avoid converting to numpy arrays, you could use a list comprehension:

p1 = plt.bar(ind, dataset[1], width, color='r')
p2 = plt.bar(ind, dataset[2], width, bottom=dataset[1], color='b')
p3 = plt.bar(ind, dataset[3], width,
bottom=[sum(x) for x in zip(dataset[1],dataset[2])], color='g')
p4 = plt.bar(ind, dataset[4], width,
bottom=[sum(x) for x in zip(dataset[1],dataset[2],dataset[3])],
color='c')

Single Stacked Bar Chart Matplotlib

First transpose one column DataFrame:

df.T.plot.barh(stacked=True, legend=False)

If 2 or more columns:

df[['Percentage']].T.plot.barh(stacked=True, legend=False)

Stacked barplot with some customizations using matplotlib

You can reshape the data such that the stacked categories are columns. Then you can use pandas plot.bar with stacked=True. reindex adds the missing years.

fig, ax=plt.subplots(figsize=(15,8))

df_stack = df.pivot_table(index="Year",
columns="Category",
values="Number",
aggfunc=sum)
df_stack = df_stack.reindex(np.arange(2000, 2022))

df_stack.plot.bar(stacked=True, ax=ax)

plt.xlabel("Year", fontsize=15)
plt.ylabel("Number", fontsize=15)

Double Agriculture is due to one with and one without trailing space.

Sample Image

Stacked Bar Chart with multiple variables in python

For a stacked barplot via pandas, each of the columns will be converted to a layer of bars. The index of the dataframe will be used as the x-axis.

In the given dataframe, you seem to want the columns for the x-axis. Using .T to transpose the dataframe (exchanging rows and columns), will help. First, you'll need to set the amino acids as index.

import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_html('https://stackoverflow.com/questions/71654486/stacked-bar-chart-with-multiple-variables-in-python')[0]

ax = df.set_index('Amino Acid').T.plot.bar(stacked=True, rot=0, cmap='tab20', figsize=(10, 7))
ax.legend(bbox_to_anchor=(1.01, 1.02), loc='upper left')
plt.tight_layout()
plt.show()

stacked bar plot from transposed dataframe

how to create stacked bar graph with custom width based on X-values in python

In the end, I solved my own question while creating this question :) .
Although this answer still cannot generate a table below the graph.

But here you go, I hope it can help someone who also have a similar problem.

import matplotlib.pyplot as plt

# Bar's starting x-point
xPoint = [0, 850, 1100,1220, 1300, 1500]
# Values
Power = [850, 500, 150, 500, 400,1100]
Vapor = [750, 850, 300, 350, 200, 300]

# the width of the bars
width = [850,250,120,80,200,500]
# Bar Color's scheme
color1 = ['#E02E15','#E9C430','#3BB273','#456990','#8491A3','#505168']
color2 = ['#EF6958','#F0D670','#70CF9D','#7598BD','#ABB3BF','#80819D']

fig, ax = plt.subplots()

bar1 = ax.bar(xPoint, height= Power, width=width, align='edge', color=color1)
bar2 = ax.bar(xPoint, height= Vapor, width=width, align='edge', color=color2, bottom=Power)
ax.set_xlabel("Total hour[h]", fontname="MS Gothic", fontsize=16) # https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.text.html#matplotlib.axes.Axes.text
ax.set_ylabel('Power Consumption+Gas', fontname="MS Gothic", fontsize=16)
ax.set_title('Total Consumption Graph', fontname="MS Gothic", fontsize=20)

ax.bar_label(bar1, label_type='center')
ax.bar_label(bar2, label_type='center')
ax.bar_label(bar2)

plt.show()

Matplotlib stacked bar chart set column order

to set a custom order for the stacked bars, you will need to order it by setting the CategoricalIndex and sorting the data by these categories. This will sort the three categories in the way you need. A small example to show the same is below...

Data 'df'

Intervention    Remuneration    Training    Supervision
A 21 4 12
B 41 5 21
C 33 6 7

Code

#Convert Intervention as index, so columns are the categories
df = df.set_index('Intervention')

#Set categories... Order will Remuneration-Training-Supervision
df.columns=pd.CategoricalIndex(df.columns.values, ordered=True, categories=['Remuneration','Training','Supervision'])

#Sort the data
df = df.sort_index(axis=1)

#...and plot
bar = df.plot.barh(stacked=True)

Output

Sample Image

Stacked bar plot for items with multiple identifiers across dates using plotly

This cannot be accomplished by express alone, as it requires both stacked and grouped bar charts. I am not sure if the method I have employed is optimal: I am reusing the graph data from express and creating a graph with the results extracted by sensor id in the graph object. As for the data, I have grouped and aggregated data frames for the graph. Sensor names are added as annotations. Add to both x-axis bar graphs if needed. The legend is displayed as a color bar and that is hidden. As a complement to that functionality, code names are added as annotations to the graphs.

df['date_time'] = pd.to_datetime(df['date_time'], format='%d-%m-%Y %H:%M')
df['date'] = df['date_time'].dt.date
dfg = df.groupby(['date','sensor_id','u_code']).size().to_frame('counts')
dfg.reset_index(inplace=True)

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

figA = px.bar(dfg.query('sensor_id == "1234abcd"'), x="date", y="counts", color="u_code", text="u_code", barmode='stack')
figB = px.bar(dfg.query('sensor_id == "5678efgh"'), x="date", y="counts", color="u_code", text="u_code", barmode='stack')

fig = go.Figure()
fig.add_trace(go.Bar(figA.data[0]))
fig.add_trace(go.Bar(figB.data[0]))

fig.add_annotation(x=dfg['date'].unique()[0], y=8.5,
xref='x', yref='y',
text="1234abcd",
showarrow=False,
xshift=-90)

fig.add_annotation(x=dfg['date'].unique()[0], y=8.5,
xref='x', yref='y',
text="5678efgh",
showarrow=False,
xshift=90)

fig.update_layout(yaxis=dict(range=[0,10]), coloraxis_showscale=False)

fig.show()

Sample Image

How to create loop to build matplotlib bar stacked bar graphs using a dataframe?

Try this for your loop:

# Looping through our shares list
bottom = []
for i in range(len(shares)-1):
bottom += df21[shares[i]]
ax.bar(df21.index, df21[shares[i+1]], label = shares[i+1], bottom = bottom)

I think you used =+ when you meant += (note that =+ isn't an operator in python, so it's equivalent to just =), and python doesn't let you assign the result of using += (that is, you can't do something like y = (x += 3)). So just modify bottom separately and then use bottom in you call to ax.bar()



Related Topics



Leave a reply



Submit