Seaborn Barplot and Formatting Dates on X-Axis

Question:

I am currently working on visualizing datasets with Seaborn and Pandas. I have some time-dependent data that I would like to graph in bar charts.

However, I am battling with two issues in Seaborn:

  1. Formatting dates on the x-axis
  2. Only showing a handful of dates (as
    it doesn’t make sense to have every day labeled on a 6 month graph)

I have found a solution for my issues in normal Matplotlib, which is:

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np

N = 20
np.random.seed(2022)
dates = pd.date_range('1/1/2014', periods=N, freq='m')
df = pd.DataFrame(
    data={'dt':dates, 'val': np.random.randn(N)}
)

fig, ax = plt.subplots(figsize=(10, 6))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
ax.bar(df['dt'], df['val'], width=25, align='center')

enter image description here

However, I already have most of my graphs done in Seaborn, and I would like to stay consistent. Once I convert the previous code into Seaborn, I lose the ability to format the dates:

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np

N = 20
np.random.seed(2022)
dates = pd.date_range('1/1/2014', periods=N, freq='m')
df = pd.DataFrame(
    data={'dt':dates, 'val': np.random.randn(N)}
)

fig, ax = plt.subplots(1,1)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%y-%m'))
sns.barplot(x='dt', y='val', data=df)
fig.autofmt_xdate()

enter image description here

When I run the code, the date format remains unchanged and I can’t locate any dates with DateLocator.

Is there any way for me to format my X-Axis for dates in Seaborn in a way similar to Matplotlib with DateLocator and DateFormatter?

Asked By: Hunter

||

Answers:

No, you cannot use seaborn.barplot in conjunction with matplotlib.dates ticking. The reason is that the ticks for seaborn barplots are at integer positions (0,1,…, N-1). So they cannot be interpreted as dates.

You have three options:

  1. Use seaborn, and loop through the labels and set them to anything you want
  2. Not use seaborn and have the advantages (and disadvantages) of matplotlib.dates tickers available.
  3. Change the format in the dataframe prior to plotting.
  • Tested in python 3.10, pandas 1.5.0, matplotlib 3.5.2, seaborn 0.12.0
N = 20
np.random.seed(2022)
dates = pd.date_range('1/1/2014', periods=N, freq='m')
df = pd.DataFrame(data={'dates': dates, 'val': np.random.randn(N)})

# change the datetime format in the dataframe prior to plotting
df.dates = df.dates.dt.strftime('%Y-%m')

fig, ax = plt.subplots(1,1)
sns.barplot(x='dates', y='val', data=df)

xticks = ax.get_xticks()
xticklabels = [x.get_text() for x in ax.get_xticklabels()]

_ = ax.set_xticks(xticks, xticklabels, rotation=90)

enter image description here

N = 20
np.random.seed(2022)
dates = pd.date_range('1/1/2014', periods=N, freq='m')
df = pd.DataFrame(data={'dates': dates, 'val': np.random.randn(N)})

df.dates = df.dates.dt.strftime('%Y-%m')
fig, ax = plt.subplots(figsize=(10, 6))
sns.barplot(x='dates', y='val', data=df)

xticks = ax.get_xticks()
xticklabels = [x.get_text() if not i%2 == 0 else '' for i, x in enumerate(ax.get_xticklabels())]

_ = ax.set_xticks(xticks, xticklabels)

enter image description here