I have a df and I am trying to create horizontal bar charts. Currently, I have the code like below.
import pandas as pd
import matplotlib.pyplot as plt
data = {'Name': ["A", "B", "C", "D",'E'],
'Todo': [4, 5, 6, 7, 3],
'Done': [6, 2, 6, 8, 6],
'TimeRemaining': [4, 4, 4, 4, 4]}
df = pd.DataFrame(data)
fig, ax1 = plt.subplots(figsize=(10, 8))
ax2 = ax1.twinx()
# Get the names of columns at indices 1 to 10
selected_column_names = df.columns[0:2].to_list()
ax = df.plot(kind='barh',y=selected_column_names, stacked=True, ax=ax2, )
for c in ax.containers:
# Optional: if the segment is small or 0, customize the labels
labels = [v.get_width() if v.get_width() > 0 else '' for v in c]
# remove the labels parameter if it's not needed for customized labels
ax.bar_label(c, fmt=lambda x: f'{x:.0f}' if x > 0 else '',label_type='center')
df.set_index('Name').plot(kind='barh', y=["TimeRemaining"], color='whitesmoke', alpha=0.3,ax=ax1, align='center', width=0.8, edgecolor='blue',)
# Hide y-axis tick labels
ax2.tick_params(axis='y', labelright=False, right=False)
ax2.set_yticklabels([])
ax1.get_legend().remove()
plt.title('Status Chart')
plt.tight_layout()
plt.show()
Which results in a plot like so & as you can see the dark blue bars are not centered with the semi-transparent bars (both bars are on different axes)
If I put them on the same axis by changing ax1
to ax2
on the second plot like so df.set_index('Name').plot(kind='barh', y=["TimeRemaining"], color='whitesmoke', alpha=0.3,ax=ax2, align='center', width=0.8, edgecolor='blue',)
they align perfectly but the names are not visible any more! I also get the legend for "TimeRemaining" which I don't want and the semi transparent bars are in the front now.
How do I fix the chart such that both bars are on top & I also have the name shown in the y-axis on the left?
You are using two different axes - ax1
and ax2
; which have different y-axis positioning. When you put both plots on the same axis, they align properly but you lose the y-axis labels. You need to Put both plots on the same axis - ax2;
so they align perfectly.
import pandas as pd
import matplotlib.pyplot as plt
data = {'Name': ["A", "B", "C", "D", 'E'],
'Todo': [4, 5, 6, 7, 3],
'Done': [6, 2, 6, 8, 6],
'TimeRemaining': [4, 4, 4, 4, 4]}
df = pd.DataFrame(data)
fig, ax1 = plt.subplots(figsize=(10, 8))
ax2 = ax1.twinx()
selected_column_names = df.columns[1:3].to_list()
ax = df.set_index('Name').plot(kind='barh', y=selected_column_names, stacked=True, ax=ax2)
for c in ax.containers:
labels = [v.get_width() if v.get_width() > 0 else '' for v in c]
ax.bar_label(c, fmt=lambda x: f'{x:.0f}' if x > 0 else '', label_type='center')
df.set_index('Name').plot(kind='barh', y=["TimeRemaining"], color='whitesmoke',
alpha=0.3, ax=ax2, align='center', width=0.8,
edgecolor='blue', zorder=0)
ax2.tick_params(axis='y', labelright=False, right=False)
ax1.tick_params(axis='y', labelleft=True, left=True)
ax1.set_ylim(ax2.get_ylim())
ax1.set_yticks(ax2.get_yticks())
ax1.set_yticklabels(df['Name'])
handles, labels = ax2.get_legend_handles_labels()
ax2.legend([handles[0]], [labels[0]], loc='upper right')
plt.title('Status Chart')
plt.tight_layout()
plt.show()