Seaborn tsplot does not show datetimes on x axis well

前端 未结 4 1100
猫巷女王i
猫巷女王i 2020-12-03 00:23

Below I have the following script which creates a simple time series plot:

%matplotlib inline
import datetime
import pandas as pd
import seaborn as sns
import         


        
相关标签:
4条回答
  • 2020-12-03 00:34

    Here is a potentially inelegant solution, but it's the only one I have ... Hope it helps!

        g = sns.pointplot(x, y, data=df, ci=False);
    
        unique_dates = sorted(list(df['Date'].drop_duplicates()))
        date_ticks = range(0, len(unique_dates), 5)
    
        g.set_xticks(date_ticks);
        g.set_xticklabels([unique_dates[i].strftime('%d %b') for i in date_ticks], rotation='vertical');
        g.set_xlabel('Date');
    

    Let me know if you see any issues!

    0 讨论(0)
  • 2020-12-03 00:38

    Matplotlib represents dates as floating point numbers (in days), thus unless you (or pandas or seaborn), tell it that your values are representing dates, it will not format the ticks as dates. I'm not a seaborn expert, but it looks like it (or pandas) does convert the datetime objects to matplotlib dates, but then does not assign proper locators and formatters to the axes. This is why you get these strange numbers, which are in fact just the days since 0001.01.01. So you'll have to take care of the ticks manually (which, in most cases, is better anyways as it gives you more control).

    So you'll have to assign a date locator, which decides where to put ticks, and a date formatter, which will then format the strings for the tick labels.

    import datetime
    import pandas as pd
    import seaborn as sns
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    
    # build up the data
    df = []
    start_date = datetime.datetime(2015, 7, 1)
    for i in range(10):
        for j in [1,2]:
            unit = 'Ones' if j == 1 else 'Twos'
            date = start_date + datetime.timedelta(days=i)
    
            # I believe it makes more sense to directly convert the datetime to a
            # "matplotlib"-date (float), instead of creating strings and then let
            # pandas parse the string again
            df.append({
                    'Date': mdates.date2num(date),
                    'Value': i * j,
                    'Unit': unit
                })
    df = pd.DataFrame(df)
    
    # build the figure
    fig, ax = plt.subplots()
    sns.tsplot(df, time='Date', value='Value', unit='Unit', ax=ax)
    
    # assign locator and formatter for the xaxis ticks.
    ax.xaxis.set_major_locator(mdates.AutoDateLocator())
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y.%m.%d'))
    
    # put the labels at 45deg since they tend to be too long
    fig.autofmt_xdate()
    plt.show()
    

    Result:

    enter image description here

    0 讨论(0)
  • 2020-12-03 00:39
    def myFormatter(x, pos):
           return pd.to_datetime(x).strftime('%Y%m%d')
    ax.xaxis.set_major_formatter(mpl.ticker.FuncFormatter(myFormatter))
    
    0 讨论(0)
  • 2020-12-03 00:56

    For me, @hitzg's answer results in "OverflowError: signed integer is greater than maximum" in the depths of DateFormatter.

    Looking at my dataframe, my indices are datetime64, not datetime. Pandas converts these nicely though. The following works great for me:

    import matplotlib as mpl
    
    def myFormatter(x, pos):
        return pd.to_datetime(x)
    
    [ . . . ]
    
    ax.xaxis.set_major_formatter(mpl.ticker.FuncFormatter(myFormatter))
    
    0 讨论(0)
提交回复
热议问题