Search code examples
pythonmatplotlibdata-visualizationseabornword-wrap

Seaborn: Is there a better way to wrap the text in my bar plot?


I am writing a function for bar plots and have encountered another small problem. I have some ytick labels that are too long, causing my y axis label not able to be seen. I'm only able to see the y label when I drastically decrease the size of the ytick labels.

def bar_plot(data, x, y, title):
    sns.set_style('darkgrid')
    data = data.sort_values(ascending=False, by=x)
    data = data.head(n=10)
    if (data[x]>1000000).any():
        data[x] = data[x] / 1000000
        ax = sns.barplot(data=data, x=x, y=y)
        ax.set_title(title, size=35)
        ax.set_xlabel(x + ' ($ Millions)', size=15)
        ax.set_ylabel(y, size=15)
        ax.set_yticklabels(data[y].head(n=10), wrap=True)

    else:
       ax = sns.barplot(data=data, x=x, y=y)
       ax.set_xlabel(x, size=15)
       ax.set_ylabel(y, size=15)
       ax.set_title(title, size=35)
       ax.set_yticklabels(data[y].head(n=10), wrap=True)

I have tried ax.set_yticklabels(data[y].head(n=10), wrap=True) to wrap the text. While it works, it doesn't wrap the text enough. Is there a way to tell wrap=True to wrap after x amount of characters? I've tried googling this but couldn't quite find anything that works.

Edit

The format of the dataframe that I am working with is similar to

Client Name            Col 1      Col 2      Col 3      Col 4       Col 5
Some name              51,235.00  nan        23,423.00  12,456.00   654.00
Some long company name 152.00     5,626.00   nan        82,389.00   5,234.00
Name                   12,554.00  5,850.00   1,510.00   nan         12,455.00
Company                12,464.00  nan        752.00     1,243.00    1,256.00
Long Company Name      12,434.00  78,915.00  522.00     2,451.00    6,567.00

Solution

  • As @ImportanceOfBeingErnest pointed out, you can use the textwrap module to do this, specifically useful would be textwrap.fill():

    textwrap.fill(text[, width[, ...]])

    Wraps the single paragraph in text so every line is at most width characters long, and returns a single string containing the wrapped paragraph. fill() is shorthand for

    "\n".join(wrap(text, ...))

    Although you will need to call this on each label separately with something like

    ax.set_yticklabels([textwrap.fill(e, width) for e in data[y].head()])
    

    Edit

    Here is a more complete example to show the usage:

    import textwrap
    import matplotlib.pyplot as plt
    import pandas as pd
    
    df = {'Client Name': ['Some Name', 'Some long company name', 'Name',
                'Company', 'Long Comany Name'],
          'Col 1': [51235, 152, 12554, 12464, 12434]}
    data = pd.DataFrame(df)
    
    fig, ax = plt.subplots(1)
    
    
    ax.set_yticklabels(data['Client Name'].head())
    plt.show()
    

    This will show the following

    enter image description here

    whereas

    ax.set_yticklabels([textwrap.fill(e, 7) for e in data['Client Name'].head()])
    plt.show()
    

    will show something more like

    enter image description here