У меня есть следующий фрейм данных (за исключением того, что мои фактические данные старше 25 лет):
import pandas as pd
df = pd.DataFrame(
dict(
date=pd.date_range(start = "2020-01-01", end = "2020-12-31", freq = "MS"),
data=[1,2,3,4,5,6,7,8,9,10,11,12]
),
)
df
Выход:
date data
0 2020-01-01 1
1 2020-02-01 2
2 2020-03-01 3
3 2020-04-01 4
4 2020-05-01 5
5 2020-06-01 6
6 2020-07-01 7
7 2020-08-01 8
8 2020-09-01 9
9 2020-10-01 10
10 2020-11-01 11
11 2020-12-01 12
И я получаю разные результаты при построении графиков по умолчанию в matplotlib и pandas:
import matplotlib as mpl
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
fig = mpl.figure.Figure(constrained_layout=True)
axs = fig.subplot_mosaic("ac;bd")
ax = axs["a"]
ax.bar(x = "date", height = "data", data=df, width=15)
ax = axs["b"]
ax.bar(x = "date", height = "data", data=df, width=15)
locator = mdates.AutoDateLocator(minticks=12, maxticks=24)
formatter = mdates.ConciseDateFormatter(locator)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
ax = axs["c"]
df.plot.bar(x = "date", y = "data", ax=ax, legend=False)
ax = axs["d"]
df.plot.bar(x = "date", y = "data", ax=ax, legend=False, ) # incorrect year -> 1970 instead of 2020
locator = mdates.AutoDateLocator(minticks=12, maxticks=24)
formatter = mdates.ConciseDateFormatter(locator)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
for k, ax in axs.items():
for label in ax.get_xticklabels():
label.set_rotation(40)
label.set_horizontalalignment('right')
fig
Выход:
Я хотел бы иметь возможность использовать pandas для построения графиков, но затем отформатировать галочки соответствующим образом для графика, готового к публикации. Однако похоже, что я теряю информацию о дате и времени или получаю неправильный год при использовании панд.
Есть ли способ отформатировать метки осей с помощью функций mdates
без прямого использования данных? т. е. если я повторно выбираю данные или разрезаю их на другой год, я бы хотел, чтобы ось отражала это автоматически.
Вот более простая иллюстрация проблемы, с которой я столкнулся:
import matplotlib as mpl
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
fig = mpl.figure.Figure(constrained_layout=True)
axs = fig.subplot_mosaic("a")
ax = axs["a"]
df.plot.bar(x = "date", y = "data", ax=ax, legend=False) # incorrect year -> 1970 instead of 2020
formatter = mdates.DateFormatter("%Y - %b")
ax.xaxis.set_major_formatter(formatter)
fig
При использовании DateFormatter
даты указаны неправильно.
Я хочу использовать код для последнего графика (внизу справа), но год для него отображается как 1970-Jan
.
В документации pandas говорится, что он вызывает fig.autoformat_xdate()
, но когда я вызываю это вручную, я не получаю тех же результатов в matplotlib. Это ошибка в пандах? Как мне заставить панд вести себя так же, как должен вести себя matplotlib?
кстати, даже использование DateFormatter
не работает. Похоже, что после построения графиков с помощью pandas встроенные функции matplotlib mdates
не работают должным образом.
Когда вы используете гистограмму, координаты x становятся 0, 1, 2, 3 и т. д. Вот почему mdates.DateFormatter
возвращает 1970, поскольку он рассматривает эти координаты как секунды, прошедшие с начала эпохи.
Вы можете установить галочки вручную:
ax.set_xticklabels(df["date"].dt.strftime("%Y - %b"))
Спасибо за ответ, похоже, в этом проблема. В частности, к сожалению, похоже, что когда кто-то использует df.plot(kind = "bar")
, панды всегда рассматривают ось X как категориальные значения. Я перешел на использование площадных диаграмм вместо гистограмм.
Я открыл проблему на pandas-dev/pandas с предложением улучшить гистограммы с помощью индексов даты и времени: github.com/pandas-dev/pandas/issues/59543
Какие метки осей вам нужны? Мне все примеры кажутся верными. Все точки данных относятся к одному и тому же году (2020), и вы использовали
ConciseDateFormatter
, поэтому год отображается только для первой точки данных. ИспользуйтеDateFormatter
, если вам нужен определенный формат для всех ярлыков.