14

我有数据点,其横坐标是datetime.datetime具有时区的对象(它们tzinfo恰好是bson.tz_util.FixedOffset通过 MongoDB 获得的)。

当我用 绘制它们时scatter(),刻度标签的时区是什么?

更改timezoneinmatplotlibrc不会改变显示图中的任何内容(我一定误解了 Matplotlib 文档中关于时区的讨论)。

我用plot()(而不是scatter())做了一些实验。当给定一个日期时,它会绘制它并忽略时区。但是,当给定多个日期时,它使用一个固定的时区,但它是如何确定的呢?我在文档中找不到任何东西。

最后,plot_date()应该是解决这些时区问题的方法吗?

4

2 回答 2

11

这个问题已经在评论中得到了回答。但是,我自己仍在与时区作斗争。为了清楚起见,我尝试了所有组合。我认为您有两种主要方法,具体取决于您的日期时间对象是已经在所需的时区还是在不同的时区,我试图在下面描述它们。有可能我仍然错过/混合了一些东西..

时间戳(日期时间对象):UTC 所需显示:特定时区

  • xaxis_date()设置为您想要的显示时区(默认rcParam['timezone']为我的 UTC)

时间戳(日期时间对象):在特定时区 所需显示:在不同的特定时区

  • 为您的绘图函数 datetime 对象提供相应的时区 ( tzinfo=)
  • 将 rcParams['timezone'] 设置为您想要的显示时区
  • 使用日期格式化程序(即使您对格式感到满意,格式化程序也是时区感知的

如果你使用 plot_date() 你也可以传入 tz 关键字,但对于散点图这是不可能的。

当您的源数据包含 unix 时间戳时,请务必明智地选择datetime.datetime.utcfromtimestamp()utc 或不使用 utc:fromtimestamp()如果您要使用 matplotlib 时区功能。

这是我所做的实验(在这种情况下是在 scatter() 上),可能有点难以理解,但只是写在这里给任何关心的人。注意第一个点出现的时间(每个子图的 x 轴不是在同一时间开始): 不同的时区组合

源代码:

import time,datetime,matplotlib
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
from dateutil import tz


#y
data = np.array([i for i in range(24)]) 

#create a datetime object from the unix timestamp 0 (epoch=0:00 1 jan 1970 UTC)
start = datetime.datetime.fromtimestamp(0)  
# it will be the local datetime (depending on your system timezone) 
# corresponding to the epoch
# and it will not have a timezone defined (standard python behaviour)

# if your data comes as unix timestamps and you are going to work with
# matploblib timezone conversions, you better use this function:
start = datetime.datetime.utcfromtimestamp(0)   

timestamps = np.array([start + datetime.timedelta(hours=i) for i in range(24)])
# now add a timezone to those timestamps, US/Pacific UTC -8, be aware this
# will not create the same set of times, they do not coincide
timestamps_tz = np.array([
    start.replace(tzinfo=tz.gettz('US/Pacific')) + datetime.timedelta(hours=i)
    for i in range(24)])


fig = plt.figure(figsize=(10.0, 15.0))


#now plot all variations
plt.subplot(711)
plt.scatter(timestamps, data)
plt.gca().set_xlim([datetime.datetime(1970,1,1), datetime.datetime(1970,1,2,12)])
plt.gca().set_title("1 - tzinfo NO, xaxis_date = NO, formatter=NO")


plt.subplot(712)
plt.scatter(timestamps_tz, data)
plt.gca().set_xlim([datetime.datetime(1970,1,1), datetime.datetime(1970,1,2,12)])
plt.gca().set_title("2 - tzinfo YES, xaxis_date = NO, formatter=NO")


plt.subplot(713)
plt.scatter(timestamps, data)
plt.gca().set_xlim([datetime.datetime(1970,1,1), datetime.datetime(1970,1,2,12)])
plt.gca().xaxis_date('US/Pacific')
plt.gca().set_title("3 - tzinfo NO, xaxis_date = YES, formatter=NO")


plt.subplot(714)
plt.scatter(timestamps, data)
plt.gca().set_xlim([datetime.datetime(1970,1,1), datetime.datetime(1970,1,2,12)])
plt.gca().xaxis_date('US/Pacific')
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%H:%M(%d)'))
plt.gca().set_title("4 - tzinfo NO, xaxis_date = YES, formatter=YES")


plt.subplot(715)
plt.scatter(timestamps_tz, data)
plt.gca().set_xlim([datetime.datetime(1970,1,1), datetime.datetime(1970,1,2,12)])
plt.gca().xaxis_date('US/Pacific')
plt.gca().set_title("5 - tzinfo YES, xaxis_date = YES, formatter=NO")


plt.subplot(716)
plt.scatter(timestamps_tz, data)
plt.gca().set_xlim([datetime.datetime(1970,1,1), datetime.datetime(1970,1,2,12)])
plt.gca().set_title("6 - tzinfo YES, xaxis_date = NO, formatter=YES")
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%H:%M(%d)'))


plt.subplot(717)
plt.scatter(timestamps_tz, data)
plt.gca().set_xlim([datetime.datetime(1970,1,1), datetime.datetime(1970,1,2,12)])
plt.gca().xaxis_date('US/Pacific')
plt.gca().set_title("7 - tzinfo YES, xaxis_date = YES, formatter=YES")
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%H:%M(%d)'))

fig.tight_layout(pad=4)
plt.subplots_adjust(top=0.90)

plt.suptitle(
    'Matplotlib {} with rcParams["timezone"] = {}, system timezone {}"
    .format(matplotlib.__version__,matplotlib.rcParams["timezone"],time.tzname))

plt.show()
于 2016-11-25T15:06:36.837 回答
6

如果像我一样,您在尝试正确绘制时区感知pandas DataFrame时遇到这个问题,@pseyfert 使用带时区的格式化程序的评论也是正确的。以下是 的示例pandas.plot,显示了从 EST 过渡到 EDT 时的一些要点:

df = pd.DataFrame(
    dict(y=np.random.normal(size=5)),
    index=pd.DatetimeIndex(
        start='2018-03-11 01:30',
        freq='15min',
        periods=5,
        tz=pytz.timezone('US/Eastern')))

请注意当我们过渡到夏令时时时区如何变化:

> [f'{t:%T %Z}' for t in df.index]
['01:30:00 EST',
 '01:45:00 EST',
 '03:00:00 EDT',
 '03:15:00 EDT',
 '03:30:00 EDT']

现在,绘制它:

df.plot(style='-o')
formatter = mdates.DateFormatter('%m/%d %T %Z', tz=df.index.tz)
plt.gca().xaxis.set_major_formatter(formatter)
plt.show()

在此处输入图像描述


PS

不知道为什么某些日期(EST 日期)看起来像粗体,但大概 matplotlib 的内部结构不止一次呈现标签,并且位置改变了一两个像素......以下确认格式化程序是多次调用相同的时间戳:

class Foo(mdates.DateFormatter):
    def __init__(self, *args, **kwargs):
        super(Foo, self).__init__(*args, **kwargs)

    def strftime(self, dt, fmt=None):
        s = super(Foo, self).strftime(dt, fmt=fmt)
        print(f'out={s} for dt={dt}, fmt={fmt}')
        return s

并查看以下输出:

df.plot(style='-o')
formatter = Foo('%F %T %Z', tz=df.index.tz)
plt.gca().xaxis.set_major_formatter(formatter)
plt.show()
于 2018-09-21T19:30:49.263 回答