How to add a vertical line to a seaborn pointplot

Question:

I want to add a vertical line in sns.pointplot(), which has datetime xticks, I used ax.axvline, but the position of the line was wrong.

my dataframe like this:

city year PM
c1 2011 2
c1 2012 2
c1 2013 3
c2 2011 3
c2 2012 2
c2 2013 3

my code like this:

df['year']=pd.to_datetime(df['year'])

fig,ax=plt.subplots()

g=sns.pointplot(x='year',
          y='PM',
          data=df,
          ax=ax,
          color='black',
          scale=0.5,
          capsize=0.2,
          errwidth=0.8
          )


ax.axvline(x=pd.Timestamp('2012-09-01 00:00:00'),
        ymin=0,ymax=1,
        #c="red",
        ls='--',
        linewidth=0.8,zorder=0, clip_on=False)

I got this:

Asked By: apple apple

||

Answers:

  • seaborn.pointplot is 0 indexed like a bar plot. The ticks are not a datetime range like a line plot.
    • g.get_xticklabels() → [Text(0, 0, '2011-01-01'), Text(1, 0, '2012-01-01'), Text(2, 0, '2013-01-01')]
    • g.get_xticks() → array([0, 1, 2])
  • Add the vertical line based on the tick location plus the fraction of days per year. In this case, 2012 is at tick 1, so x=1 + 244days/365days or x=1.67
  • Also see How to draw vertical lines on a given plot for additional information about adding vertical lines to a bar plot.
  • Tested in python 3.8.11, pandas 1.3.3, matplotlib 3.4.3, seaborn 0.11.2
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

data = {'city': ['c1', 'c1', 'c1', 'c2', 'c2', 'c2'], 'year': [2011, 2012, 2013, 2011, 2012, 2013], 'PM': [2, 2, 3, 3, 2, 3]}
df = pd.DataFrame(data)

# convert to datetime if desired
df['year'] = pd.to_datetime(df['year'], format='%Y').dt.date

fig, ax = plt.subplots()

g = sns.pointplot(x='year', y='PM', data=df, color='black', scale=0.5, capsize=0.2, errwidth=0.8, ax=ax)

g.axvline(x=1 + 244/365,
          ymin=0, ymax=1, c="red", ls='--', linewidth=0.8, zorder=0, clip_on=False)

enter image description here

Answered By: Trenton McKinney