Home > Enterprise >  How to start Seaborn Logarithmic Barplot at y=1
How to start Seaborn Logarithmic Barplot at y=1

Time:11-29

I have a problem figuring out how to have Seaborn show the right values in a logarithmic barplot. A value of mine should be, in the ideal case, be 1. My dataseries (5,2,1,0.5,0.2) has a set of values that deviate from unity and I want to visualize these in a logarithmic barplot. However, when plotting this in the standard log-barplot it shows the following:

Wrong plot

But the values under one are shown to increase from -infinity to their value, whilst the real values ought to look like this:

Right plot, Excel

Strangely enough, I was unable to find a Seaborn, Pandas or Matplotlib attribute to "snap" to a different horizontal axis or "align" or ymin/ymax. I have a feeling I am unable to find it because I can't find the terms to shove down my favorite search engine. Some semi-solutions I found just did not match what I was looking for or did not have either xaxis = 1 or a ylog. A try that uses some jank Matplotlib lines:

Right-ish

If someone knows the right terms or a solution, thank you in advance.

Here are the Jupyter cells I used:

{1}

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

data = {'X': ['A','B','C','D','E'], 'Y': [5,2,1,0.5,0.2]}
df = pd.DataFrame(data)

{2}

%matplotlib widget
g = sns.catplot(data=df, kind="bar", y = "Y", x = "X", log = True)

{3}

%matplotlib widget
plt.vlines(x=data['X'], ymin=1, ymax=data['Y'])

CodePudding user response:

You could let the bars start at 1 instead of at 0. You'll need to use sns.barplot directly.

The example code subtracts 1 of all y-values and sets the bar bottom at 1.

import matplotlib.pyplot as plt
from matplotlib.ticker import NullFormatter
import seaborn as sns
import pandas as pd
import numpy as np

data = {'X': ['A', 'B', 'C', 'D', 'E'], 'Y': [5, 2, 1, 0.5, 0.2]}
df = pd.DataFrame(data)
ax = sns.barplot(y=df["Y"] - 1, x=df["X"], bottom=1, log=True, palette='flare_r')
ax.axhline(y=1, c='k')

# change the y-ticks, as the default shows too few in this case
ax.set_yticks(np.append(np.arange(.2, .8, .1), np.arange(1, 7, 1)), minor=False)
ax.set_yticks(np.arange(.3, 6, .1), minor=True)
ax.yaxis.set_major_formatter(lambda x, pos: f'{x:.0f}' if x >= 1 else f'{x:.1f}')
ax.yaxis.set_minor_formatter(NullFormatter())
ax.bar_label(ax.containers[0], labels=df["Y"])
sns.despine()
plt.show()

sns.barplot with logscale starting at 1

PS: With these specific values, the plot might go without logscale:

sns.barplot starting at 1, no logscale

  • Related