pythonseabornseaborn-objects

Format y-axis as percentage in a seaborn.objects plot


I found a suggestion to use ticker.PercentFormatter. This changed the decimal numbers on the y-axis to percentages like I want, but the style formatting (grid, background, etc.) is lost, and the legend is pushed outside the plot area and cropped out.

Why does the plot change, and how do I fix the script so the plot retains my legend and styling?

import seaborn as sns
import seaborn.objects as so
import matplotlib.ticker as ticker
import matplotlib.pyplot as plt

market_data = {
    'Year': ['2001','2001','2002', '2002', '2003', '2003'],
    'Company': ['Shony','Ponysonic','Shony','Ponysonic','Shony','Ponysonic'],
    'Market Share': [0.15, 0.35, 0.25, 0.4, 0.2, 0.45]
}

market_chart = (
    so.Plot(data=market_data, x="Year", y="Market Share",color="Company")
    .add(so.Area(), so.Stack())
)

market_chart.show()  # looks good, but y-axis not in percent format

fig, ax = plt.subplots()
market_chart.on(ax).plot()
ax.yaxis.set_major_formatter(ticker.PercentFormatter(1))
plt.show() # display with percent y-axis. Lost theme styling.

fig1

fig2


Solution

  • The plot changes because calling .on(ax).plot() disables Seaborne theme system, which is what applied the background grid, facecolor, legend layout, etc. The fix is to apply the percent formatter inside Seaborne theming context, after the plot is created, and without manually creating a new fig, ax.

    import seaborn as sns
    import seaborn.objects as so
    import matplotlib.ticker as ticker
    import matplotlib.pyplot as plt
    
    market_data = {
        'Year': ['2001','2001','2002', '2002', '2003', '2003'],
        'Company': ['Shony','Ponysonic','Shony','Ponysonic','Shony','Ponysonic'],
        'Market Share': [0.15, 0.35, 0.25, 0.4, 0.2, 0.45]
    }
    
    market_chart = (
        so.Plot(data=market_data, x="Year", y="Market Share", color="Company")
        .add(so.Area(), so.Stack())
        .scale(
            y=so.Continuous().label(ticker.PercentFormatter(xmax=1))
        )
    )
    
    market_chart.show()
    
    

    enter image description here