7

I am trying to do a plot of values over time using seaborn linear model plot but I get the error

TypeError: invalid type promotion

I have read that it is not possible to plot pandas date objects, but that seems really strange given seaborn requires you pass a pandas DataFrame to the plots.

Below is a simple example. Does anyone know how I can get this to work?

import pandas as pd
import seaborn as sns; sns.set(color_codes=True)
import matplotlib.pyplot as plt

date = ['1975-12-03','2008-08-20', '2011-03-16']
value = [1,4,5]
df = pd.DataFrame({'date':date, 'value': value})
df['date'] = pd.to_datetime(df['date'])

g = sns.lmplot(x="date", y="value", data=df, size = 4, aspect = 1.5)

I am trying to do a plot like this one I created in r using ggplot hence why I want to use sns.lmplot enter image description here

Robin
  • 389
  • 5
  • 19
  • `lmplot` isn't really designed to work with timeseries data. – Paul H Feb 19 '18 at 06:17
  • and where did you read it's impossible to plot pandas date objects? people do it constantly: http://pandas.pydata.org/pandas-docs/stable/visualization.html#basic-plotting-plot – Paul H Feb 19 '18 at 06:18
  • Yeah I didn't say that well. What I read was there is an issue with seaborn not being able to plot pandas date objects. – Robin Feb 19 '18 at 06:20
  • Here's an alternative: https://stackoverflow.com/questions/44354614/seaborn-regplot-using-datetime64-as-the-x-axis – ayhan Feb 19 '18 at 06:44

2 Answers2

8

You need to convert your dates to floats, then format the x-axis to reinterpret and format the floats into dates.

Here's how I would do this:

import pandas
import seaborn
from matplotlib import pyplot, dates
%matplotlib inline

date = ['1975-12-03','2008-08-20', '2011-03-16']
value = [1,4,5]
df = pandas.DataFrame({
    'date': pandas.to_datetime(date),   # pandas dates
    'datenum': dates.datestr2num(date), # maptlotlib dates
    'value': value
})

@pyplot.FuncFormatter
def fake_dates(x, pos):
    """ Custom formater to turn floats into e.g., 2016-05-08"""
    return dates.num2date(x).strftime('%Y-%m-%d')

fig, ax = pyplot.subplots()
# just use regplot if you don't need a FacetGrid
seaborn.regplot('datenum', 'value', data=df, ax=ax)

# here's the magic:
ax.xaxis.set_major_formatter(fake_dates)

# legible labels
ax.tick_params(labelrotation=45)

enter image description here

Paul H
  • 65,268
  • 20
  • 159
  • 136
  • TypeError: formatter argument should be instance of matplotlib.ticker.Formatter – Florin Andrei Dec 30 '19 at 00:06
  • @FlorinAndrei the example still runs on modern python/matplotlib/seaborn, so I'm not sure what you expect with your copy/pasted error message. – Paul H Dec 30 '19 at 05:30
0

I have found a derived solution from Paul H. for plotting timestamp in seaborn. I had to apply it over my data due to some backend error messages that was returning.

In my solution, I added a matplotlib.ticker FuncFormatter over the ax.xaxis.set_major_formatter. This FuncFormatter wraps the fake_dates function. This way, one doesn't need to insert the @pyplot.FuncFormatter beforehand.

Here is my solution:

import pandas
import seaborn
from matplotlib import pyplot, dates
from matplotlib.ticker import FuncFormatter

date = ['1975-12-03','2008-08-20', '2011-03-16']
value = [1,4,5]
df = pandas.DataFrame({
    'date': pandas.to_datetime(date),   # pandas dates
    'datenum': dates.datestr2num(date), # maptlotlib dates
    'value': value
})


def fake_dates(x, pos):
    """ Custom formater to turn floats into e.g., 2016-05-08"""
    return dates.num2date(x).strftime('%Y-%m-%d')

fig, ax = pyplot.subplots()
# just use regplot if you don't need a FacetGrid
seaborn.regplot('datenum', 'value', data=df, ax=ax)

# here's the magic:
ax.xaxis.set_major_formatter(FuncFormatter(fake_dates))

# legible labels
ax.tick_params(labelrotation=45)

fig.tight_layout()

I hope that works.

Philipe Riskalla Leal
  • 954
  • 1
  • 10
  • 28