Как обрабатывать время с часовым поясом в Matplotlib?

У меня есть данные, чьи абсциссы datetime.datetime объекты с часовым поясом (их tzinfo случается быть bson.tz_util.FixedOffset получено через MongoDB).

Когда я планирую их scatter() какой часовой пояс обозначен галочкой?

Изменение timezone в matplotlibrc ничего не меняет в отображаемом графике (я, должно быть, неправильно понял обсуждение часовых поясов в документации Matplotlib).

Я немного поэкспериментировал с plot() (вместо scatter()). Когда ему дается одна дата, она наносит ее на график и игнорирует часовой пояс. Однако при задании нескольких дат используется фиксированный часовой пояс, но как он определяется? Я не могу найти ничего в документации.

Наконец, это plot_date() должно быть решением этих проблем с часовым поясом?

2 ответа

На вопрос уже отвечали в комментариях вроде. Однако я все еще боролся с часовыми поясами сам. Чтобы было понятно, я перепробовал все комбинации. Я думаю, что у вас есть два основных подхода в зависимости от того, находятся ли ваши объекты даты и времени в желаемом часовом поясе или в другом часовом поясе, я попытался описать их ниже. Возможно, я все еще что-то пропустил / перепутал..

Отметки времени (объекты даты и времени): в UTC. Требуемое отображение: в определенном часовом поясе.

  • Установите для xaxis_date() желаемый часовой пояс дисплея (по умолчанию rcParam['timezone'] который был UTC для меня)

Отметки времени (объекты даты и времени): в определенном часовом поясе Желаемое отображение: в другом определенном часовом поясе

  • Накормите ваши объекты функции datetime графиком с соответствующим часовым поясом (tzinfo=)
  • Установите для rcParams['timezone'] желаемый часовой пояс для отображения
  • Используйте форматирование даты (даже если вы удовлетворены форматом, форматер поддерживает временную зону)

Если вы используете plot_date(), вы также можете передать ключевое слово tz, но для точечной диаграммы это невозможно.

Когда ваши исходные данные содержат метки времени Unix, не забудьте выбрать мудро из datetime.datetime.utcfromtimestamp() и без 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()

Если, как и я, вы подходите к этому вопросу, пытаясь заставить панду 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()
Другие вопросы по тегам