【问题标题】:Seaborn tsplot does not show datetimes on x axis wellSeaborn tsplot 不能很好地在 x 轴上显示日期时间
【发布时间】:2015-09-24 04:31:04
【问题描述】:

下面我有以下脚本,它创建了一个简单的时间序列图:

%matplotlib inline
import datetime
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

fig, ax = plt.subplots()

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)
        
        df.append({
                'Date': date.strftime('%Y%m%d'),
                'Value': i * j,
                'Unit': unit
            })
    
df = pd.DataFrame(df)

sns.tsplot(df, time='Date', value='Value', unit='Unit', ax=ax)
fig.autofmt_xdate()

结果如下:

如您所见,x 轴的日期时间数字很奇怪,而不是 matplotlib 和其他绘图实用程序附带的通常的“漂亮”表示。我已经尝试了很多东西,重新格式化数据,但它从来没有干净。有人知道解决办法吗?

【问题讨论】:

    标签: python datetime matplotlib seaborn


    【解决方案1】:

    Matplotlib 将日期表示为浮点数(以天为单位),因此除非您(或 pandas 或 seaborn)告诉它您的值表示日期,否则它不会将刻度格式化为日期。我不是 seaborn 专家,但看起来它(或 pandas)确实将 datetime 对象转换为 matplotlib 日期,但没有为轴分配适当的定位器和格式化程序。这就是为什么你会得到这些奇怪的数字,这些数字实际上只是自 0001.01.01 以来的日子。因此,您必须手动处理滴答声(在大多数情况下,这会更好,因为它可以为您提供更多控制权)。

    因此,您必须分配一个 date locator,它决定在哪里放置刻度,以及一个 date formatter,然后它将格式化刻度标签的字符串。

    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()
    

    结果:

    【讨论】:

    • 我得到这个错误:OverflowError: Python int too large to convert to C long
    • 在我身边工作。你用我的确切例子吗?也许你需要更新你的发行版。
    • @kurious:我得到了类似的东西:OverflowError: signed integer is greater than maximum 来自 _from_ordinalf(x, tz) 中的 matplotlib/dates.pyc(第 214 行)。只需使用 Python 2.7 在 Linux 上安装 pip。
    【解决方案2】:

    对我来说,@hitzg 的回答在 DateFormatter 的深处导致“溢出错误:有符号整数大于最大值”。

    查看我的数据框,我的索引是 datetime64,而不是 datetime。 Pandas 很好地转换了这些。以下对我很有用:

    import matplotlib as mpl
    
    def myFormatter(x, pos):
        return pd.to_datetime(x)
    
    [ . . . ]
    
    ax.xaxis.set_major_formatter(mpl.ticker.FuncFormatter(myFormatter))
    

    【讨论】:

    • 那我们该如何格式化呢? ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y.%m.%d')) 不起作用。
    【解决方案3】:

    这是一个可能不太优雅的解决方案,但它是我唯一的一个......希望它有所帮助!

        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');
    

    如果您发现任何问题,请告诉我!

    【讨论】:

    • 我很好奇,for i in <tons of spaces> date_ticks 有什么原因吗?
    • 这对我来说很奇怪......事实证明unique_dates 是一个日期时间对象列表。即list没有strftime方法,所以我们需要从列表中取出i第一项并应用该方法。
    【解决方案4】:
    def myFormatter(x, pos):
           return pd.to_datetime(x).strftime('%Y%m%d')
    ax.xaxis.set_major_formatter(mpl.ticker.FuncFormatter(myFormatter))
    

    【讨论】:

      猜你喜欢
      • 2015-02-10
      • 2017-08-14
      • 2015-06-19
      • 1970-01-01
      • 2021-04-19
      • 1970-01-01
      • 1970-01-01
      • 2017-05-16
      相关资源
      最近更新 更多