pandas : plot stacked barchart for row values
Question:
I have below data frame and I wanted to plot stacked bar chart for ‘closed’/’open’ state.
state requests
created
2016-09-28 OPEN 1
2017-02-03 OPEN 1
2017-06-15 CLOSED 1
2017-06-15 OPEN 1
2017-06-16 CLOSED 2
2017-08-23 OPEN 1
2017-10-25 OPEN 1
2018-01-19 OPEN 1
2018-03-01 OPEN 1
2018-03-05 OPEN 1
2018-06-12 OPEN 1
2018-06-15 OPEN 1
I have tried following(df_temp is dataframe of above data)
fig,ax = plt.subplots()
ax.set_ylabel('Requests')
df_closed = df_temp[df_temp['state'] == 'CLOSED']
df_open = df_temp[df_temp['state'] == 'OPEN']
b = ax.bar(x = df_open.index.get_level_values(0), height = df_open['requests'])
a = ax.bar(x = df_closed.index.get_level_values(0), height = df_closed['requests'],bottom = df_open['requests'])
but it is giving me error as
ValueError: shape mismatch: objects cannot be broadcast to a single shape
Answers:
I’m posting a proper answer here since it’s probably easier than keeping commenting. This also includes the further case (asked in the comment) where there might be an arbitrary, unknown set of values in state
.
fig, ax = plt.subplots()
index = df_temp.index.unique()
cumsum = pd.Series(0, index=index)
for s in df.state.unique():
new_vals = df_temp.loc[df.state == s, 'requests'].reindex(index).fillna(0)
ax.bar(index, new_vals, bottom = cumsum)
cumsum += new_vals
ax.set_ylabel('Requests')
This should take care of everything. Within each ax, I’d probably also put a label=s
and add an ax.legend()
in the end to map each resulting color to one status.
Since you mention pandas pivot function – you can transform your dataset with it in one line before you stack the bar chart:
df_temp.pivot(columns = "state", values = "requests").plot(kind = "bar", stacked = True)
Now we can additionally beautify the graph – label the y-axis, rotate the x-tick labels:
plt.ylabel("Requests")
plt.xticks(rotation = 45, ha = "right")
plt.tight_layout()
plt.show()
I have below data frame and I wanted to plot stacked bar chart for ‘closed’/’open’ state.
state requests
created
2016-09-28 OPEN 1
2017-02-03 OPEN 1
2017-06-15 CLOSED 1
2017-06-15 OPEN 1
2017-06-16 CLOSED 2
2017-08-23 OPEN 1
2017-10-25 OPEN 1
2018-01-19 OPEN 1
2018-03-01 OPEN 1
2018-03-05 OPEN 1
2018-06-12 OPEN 1
2018-06-15 OPEN 1
I have tried following(df_temp is dataframe of above data)
fig,ax = plt.subplots()
ax.set_ylabel('Requests')
df_closed = df_temp[df_temp['state'] == 'CLOSED']
df_open = df_temp[df_temp['state'] == 'OPEN']
b = ax.bar(x = df_open.index.get_level_values(0), height = df_open['requests'])
a = ax.bar(x = df_closed.index.get_level_values(0), height = df_closed['requests'],bottom = df_open['requests'])
but it is giving me error as
ValueError: shape mismatch: objects cannot be broadcast to a single shape
I’m posting a proper answer here since it’s probably easier than keeping commenting. This also includes the further case (asked in the comment) where there might be an arbitrary, unknown set of values in state
.
fig, ax = plt.subplots()
index = df_temp.index.unique()
cumsum = pd.Series(0, index=index)
for s in df.state.unique():
new_vals = df_temp.loc[df.state == s, 'requests'].reindex(index).fillna(0)
ax.bar(index, new_vals, bottom = cumsum)
cumsum += new_vals
ax.set_ylabel('Requests')
This should take care of everything. Within each ax, I’d probably also put a label=s
and add an ax.legend()
in the end to map each resulting color to one status.
Since you mention pandas pivot function – you can transform your dataset with it in one line before you stack the bar chart:
df_temp.pivot(columns = "state", values = "requests").plot(kind = "bar", stacked = True)
Now we can additionally beautify the graph – label the y-axis, rotate the x-tick labels:
plt.ylabel("Requests")
plt.xticks(rotation = 45, ha = "right")
plt.tight_layout()
plt.show()