У меня есть ежедневные данные. Как я могу ограничить тики только месяцами? - PullRequest
1 голос
/ 11 декабря 2019

У меня есть фрейм данных с одним столбцом одного года ежедневных дат и двумя столбцами данных. Я создаю тепловую карту данных, используя даты в качестве оси Y. Как я могу ограничить тики по оси Y только месяцами? Я в порядке, когда «январь» появляется либо в строке, представляющей 1-е число месяца, либо в строке, представляющей середину месяца. В целях масштабируемости столбец «Дата» всегда будет хронологическим и всегда будет иметь постоянные приращения, хотя не обязательно точно 1 день, как в моем примере.

df = pd.DataFrame({'Date':[dt.date(2019,1,1) + dt.timedelta(days=x) for x in range(365)],
               'a':[x%5 for x in range(365)], 'b':[x%3 for x in range(365)]})
print(df.head())
         Date  a  b
0  2019-01-01  0  0
1  2019-01-02  1  1
2  2019-01-03  2  2
3  2019-01-04  3  0
4  2019-01-05  4  1

1) Стандартный код тепловой карты. Это приводит к захламленной оси Y.

ax = sns.heatmap(data=df[['a','b']], yticklabels=df['Date'])

enter image description here

2) Использование MonthLocator из matplotlib.dates (как «mdates»). Я не мог заставить это работать. Это приводит к отсутствию меток по оси Y.

ax = sns.heatmap(data=df[['a','b']], yticklabels=df['Date'])
ax.yaxis.set_major_locator(mdates.MonthLocator())

enter image description here

3) Использование причудливой математики. Это не может учитывать месяцы с неравным числом дней.

ax = sns.heatmap(data=df[['a','b']])
ax.set_yticks(range(0,df.shape[0]-1,df.shape[0]//12)) #13 evenly spaced tick marks
ax.set_yticklabels(df['Date'].apply(lambda x: x.strftime('%B %d %Y')).iloc[range(0,df.shape[0]-1,df.shape[0]//12)]) #Select dates matching tick marks

enter image description here

4) Здесь нет примера кода. Я пытался найти даты, когда «день» был 1. Это не было проблемой. Я просто не мог понять, как создать правильно неравномерно распределенные галочки, чтобы назначить их.

1 Ответ

2 голосов
/ 11 декабря 2019

Полагаю, единственное чистое решение здесь - использовать matplotlib и отформатировать ось. Для этого преобразуйте даты в числа и установите экстент изображения в диапазоне значений даты. (Если быть точным, можно также добавить полдня, чтобы день находился посередине каждого пикселя). Предполагается, что даты (и, следовательно, пиксели) расположены на одинаковом расстоянии.

import numpy as np
import pandas as pd
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

df = pd.DataFrame({'Date':[dt.date(2019,1,1) + dt.timedelta(days=x) for x in range(365)],
               'a':[x%5 for x in range(365)], 'b':[x%3 for x in range(365)]})


x = np.arange(len(df.columns[1:]))
y = mdates.date2num(df['Date'].values)
z = df[["a", "b"]].values

dy = y[1]-y[0]
extent = [-0.5, len(x)-0.5, y[0]-dy, y[-1]+dy]

fig, ax = plt.subplots()
im = ax.imshow(z, aspect="auto", extent=extent)
ax.yaxis_date()
ax.invert_yaxis()
ax.set(xticks=x, xticklabels=df.columns[1:])
fig.colorbar(im)

plt.show()

enter image description here

Теперь вы также можете без проблем использовать локаторы и форматеры дат matplotlib

...