MBasith
MBasith

Reputation: 1499

Matplotlib Control Spacing Between Bars

I am trying to insert spacing between two specific bars but cannot find any easy way to do this. I can manually add a dummy row with with 0 height to create and empty space but doesn't give me control of how wide the space should be. Is there a more programmatic method I can use to control the spacing between bars at any position?

Example Code:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

mydict = {
    'Event': ['Running', 'Swimming', 'Biking', '', 'Hiking', 'Jogging'],
    'Completed': [2, 4, 3, 0, 7, 9],
    'Participants': [10, 20, 35, 0, 10, 20]}

df = pd.DataFrame(mydict).set_index('Event')
df = df.assign(Completion=(df.Completed / df.Participants) * 100)

plt.subplots(figsize=(5, 4))

print(df.index)
ax = sns.barplot(x=df.Completion, y=df.index, color="orange", orient='h')

plt.xticks(rotation=60)

plt.tight_layout()
plt.show()

Example DataFrame Output:

          Completed  Participants  Completion
Event                                        
Running           2            10   20.000000
Swimming          4            20   20.000000
Biking            3            35    8.571429
                  0             0         NaN
Hiking            7            10   70.000000
Jogging           9            20   45.000000

Example output (blue arrows added outside of code to show where empty row was added.):

enter image description here

Upvotes: 3

Views: 133

Answers (1)

Ben.T
Ben.T

Reputation: 29635

I think you can access the position of the boxes and the name of the labels. Then modify them. You may find an more general way depending on your use case, but this works for the given example.

#define a function to add space starting a specific label
def add_space_after(ax, label_shift='', extra_space=0):
    bool_space = False
    # get postion of current ticks
    ticks_position = np.array(ax.get_yticks()).astype(float)
    # iterate over the boxes/label
    for i, (patch, label) in enumerate(zip(ax.patches, ax.get_yticklabels())):
        # if the label to start the shift found
        if label.get_text()==label_shift: bool_space = True
        # reposition the boxes and the labels afterward
        if bool_space:
            patch.set_y(patch.get_y() + extra_space)
            ticks_position[i] += extra_space
    # in the case where the spacing is needed
    if bool_space:
        ax.set_yticks(ticks_position)
        ax.set_ylim([ax.get_ylim()[0]+extra_space, ax.get_ylim()[1]])

#note: no more blank row
mydict = {
    'Event': ['Running', 'Swimming', 'Biking', 'Hiking', 'Jogging'],
    'Completed': [2, 4, 3, 7, 9],
    'Participants': [10, 20, 35, 10, 20]}
df = pd.DataFrame(mydict).set_index('Event')
df = df.assign(Completion=(df.Completed / df.Participants) * 100)

ax = sns.barplot(x=df.Completion, y=df.index, color="orange", orient='h')
plt.xticks(rotation=60)
plt.tight_layout()

#use the function
add_space_after(ax, 'Hiking', 0.6)

plt.show()

enter image description here

Upvotes: 1

Related Questions