1

I am trying to plot grouped bar with a line graph on it using seaborn.

So far I have achieved to plt the graph. However, the bars are getting overlapped and also need some help to align the text.

DataFrame:

df_long = pd.DataFrame({
'group': [ 9, 10, 11, 12, 13, 14, 15, 16, 17,18, 19, 20, 21, 22,  9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,  9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,  9, 10, 11,  12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22],

'status': ['1st hour', '1st hour', '1st hour', '1st hour', '1st hour',
   '1st hour', '1st hour', '1st hour', '1st hour', '1st hour',
   '1st hour', '1st hour', '1st hour', '1st hour', '2nd hour',
   '2nd hour', '2nd hour', '2nd hour', '2nd hour', '2nd hour',
   '2nd hour', '2nd hour', '2nd hour', '2nd hour', '2nd hour',
   '2nd hour', '2nd hour', '2nd hour', '3rd hour', '3rd hour',
   '3rd hour', '3rd hour', '3rd hour', '3rd hour', '3rd hour',
   '3rd hour', '3rd hour', '3rd hour', '3rd hour', '3rd hour',
   '3rd hour', '3rd hour', '4th hour', '4th hour', '4th hour',
   '4th hour', '4th hour', '4th hour', '4th hour', '4th hour',
   '4th hour', '4th hour', '4th hour', '4th hour', '4th hour',
   '4th hour', '5th hour', '5th hour', '5th hour', '5th hour',
   '5th hour', '5th hour', '5th hour', '5th hour', '5th hour',
   '5th hour', '5th hour', '5th hour', '5th hour', '5th hour',
   '6th hour', '6th hour', '6th hour', '6th hour', '6th hour',
   '6th hour', '6th hour', '6th hour', '6th hour', '6th hour',
   '6th hour', '6th hour', '6th hour', '6th hour'],

"value":   
[44.88, 45.56, 46.67, 47.37, 47.74, 49.1 , 50.68, 49.64, 50.97,
 48.5 , 52.69, 54.38, 49.89, 58.66, 16.14, 17.22, 15.77, 16.69,
 16.22, 16.41, 15.68, 16.21, 15.54, 15.55, 14.1 , 14.08, 16.44,
 12.82,  6.45,  6.13,  6.12,  5.47,  5.89,  6.13,  5.92,  6.26,
  6.08,  6.38,  7.88,  5.96,  5.38,  4.73,  4.14,  3.68,  3.76,
  3.62,  3.69,  3.89,  3.64,  3.84,  3.73,  6.16,  3.62,  2.91,
  3.27,  3.12,  3.35,  2.47,  3.25,  2.92,  3.47,  2.77,  2.51,
  2.81,  3.65,  2.98,  2.18,  1.59,  2.18,  0.58,  2.6 ,  2.06,
  2.55,  2.57,  2.52,  2.33,  2.84,  2.6 ,  2.15,  1.71,  0.93,
  0.86,  1.24,  0.92]})

Code:

import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots(figsize=(20, 8))

g = sns.barplot(data=df_long, x='group', y='value', hue='status', ax=ax)

for bar in g.patches:
  height = bar.get_height()
  ax.text(bar.get_x() + bar.get_width()/3, 0.7 * height, int(height),
            ha='center', va='center', color='white')

def change_width(ax, new_value) :
  for patch in ax.patches :
    current_width = patch.get_width()
    diff = current_width - new_value

    # we change the bar width
    patch.set_width(new_value)

    # we recenter the bar
    patch.set_x(patch.get_x() + diff * .5)
    
change_width(ax, .30)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
plt.show()

Output:

enter image description here

  1. I wanted to alight the text and organise these bars for each group.
  2. I want to plot a line graph over these bars by taking the sum of "value" column for each group.

Code:

ax2 = ax.twinx()
color = 'tab:red'
ax2.set_ylabel('AverageEfficiency', fontsize=16)
freq = df_long.groupby('group').agg({"value": "sum"})
ax2 = sns.lineplot(x=freq.index.values, y=freq.value.values)
ax2.tick_params(color=color)

But this din't work well.

Dhvani Shah
  • 351
  • 1
  • 7
  • 17
  • @AlexK I have added the code to reproduce the dataframe. What i mean by alight text and organize bars: The bar of each label is overlapped with the other. The numbers i.e. the text is not clearly visible on these graphs. Also, I wanted a line graph over these bars: #line plot creation ax2 = ax.twinx() color = 'tab:red' ax2.set_ylabel('AverageEfficiency', fontsize=16) freq = df_long.groupby('group').agg({"value": "sum"}) ax2 = sns.lineplot(x=freq.index.values, y=freq.value.values) ax2.tick_params(color=color) I tried using this code, but dint work – Dhvani Shah Jul 13 '22 at 01:09
  • if you don't want the overlapped why not just remove: change_width(ax, .30) – Chris Seeling Jul 13 '22 at 02:17
  • @ChrisSeeling Yes, i did. However, then the width of bards gets too small. – Dhvani Shah Jul 13 '22 at 02:19

1 Answers1

1

for the line plot use:

freq = df_long.groupby('group').agg({"value": "sum"}).reset_index(drop=True)
Chris Seeling
  • 606
  • 4
  • 11