Проблемы с форматом даты в тиках графика с matplotlib.dates (и datestr2num)

Я использую matplotlib.dates для построения гистограммы с экземплярами, встречающимися в определенные даты (представленные в виде списка строк), и использую matplotlib.dates.datestr2num для отображения двух наборов данных на дату (согласно верхнему ответу в Python matplotlib несколько баров).

Однако для дат ниже 12-го числа месяца график интерпретирует даты в формате ММ / ДД / ГГ, тогда как для дат выше 12-го числа месяца он интерпретирует даты как ДД / ММ / ГГ, в результате чего данные, чтобы прыгать по графику. Я думаю, что проблема может быть в том, как я использую datestr2num, но не знаю, как заставить его быть в том или ином формате.

import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter, AutoDateLocator, AutoDateFormatter, datestr2num

days = ['30/01/2019', '31/01/2019', '01/02/2019', '02/02/2019', '03/02/2019', '04/02/2019']
adata = [1, 9, 10, 3, 7, 6]
bdata = [1, 2, 11, 3, 6, 2]

x=datestr2num(days)

w=0.25
fig = plt.figure(figsize = (8,4))
ax = fig.add_subplot(111)
ax.bar(x-w, adata, width=2*w, color='g', align='center', tick_label = days)
ax.bar(x+w, bdata, width=2*w, color='r', align='center', tick_label = days)
ax.xaxis_date()
ax.xaxis.set_major_locator(AutoDateLocator(minticks=3, interval_multiples=False))
ax.xaxis.set_major_formatter(DateFormatter("%d/%m/%y"))

plt.show()

В приведенном выше примере adata а также bdata относятся к последующим датам (с 30 января по 4 февраля), при этом все столбцы показаны рядом друг с другом, но на графике отображаются данные между 2 января и 2 апреля, поэтому данные отображаются не по порядку.

Любая помощь или разъяснение будут полезны, спасибо!

Изображение выхода сверху

1 ответ

Решение

Кажется, что datestr2num() звонки dateutil.parser.parse(d, default=default). dateutil.parser.parse есть kwarg dayfirst но datestr2num()не дает возможности передать аргумент вперед. Если вы передадите список дат вdatesttr2num() сначала будет месяц.

>>> [dateutil.parser.parse(day, dayfirst=True) for day in days]
[
    datetime.datetime(2019, 1, 30, 0, 0), 
    datetime.datetime(2019, 1, 31, 0, 0), 
    datetime.datetime(2019, 2, 1, 0, 0), 
    datetime.datetime(2019, 2, 2, 0, 0), 
    datetime.datetime(2019, 2, 3, 0, 0), 
    datetime.datetime(2019, 2, 4, 0, 0)
]

>>> datestr2num(days)
[737089. 737090. 737061. 737092. 737120. 737151.]

>>> datestr2num(days, dayfirst=True)
Traceback (most recent call last):
File "C:\Users\bcohan\Downloads\so.py", line 22, in <module>
    print(datestr2num(days, dayfirst=True))
TypeError: datestr2num() got an unexpected keyword argument 'dayfirst'

Я бы предложил обрабатывать даты с помощью datetimeсначала, а затем запуск остальных. (Если нет смысла переписывать строки в исходномdays список.)

x = datestr2num([
    datetime.strptime(day, '%d/%m/%Y').strftime('%m/%d/%Y')
    for day in days
])

Вот полностью рабочий сценарий.

from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.dates import (
    DateFormatter, AutoDateLocator, AutoDateFormatter, datestr2num
)

days = [
    '30/01/2019', '31/01/2019', '01/02/2019',
    '02/02/2019', '03/02/2019', '04/02/2019'
]
adata = [1, 9, 10, 3, 7, 6]
bdata = [1, 2, 11, 3, 6, 2]

x = datestr2num([
    datetime.strptime(day, '%d/%m/%Y').strftime('%m/%d/%Y')
    for day in days
])
w = 0.25

fig = plt.figure(figsize=(8, 4))
ax = fig.add_subplot(111)
ax.bar(x - w, adata, width=2 * w, color='g', align='center', tick_label=days)
ax.bar(x + w, bdata, width=2 * w, color='r', align='center', tick_label=days)
ax.xaxis_date()
ax.xaxis.set_major_locator(
    AutoDateLocator(minticks=3, interval_multiples=False))
ax.xaxis.set_major_formatter(DateFormatter("%d/%m/%y"))

plt.show()

Другие вопросы по тегам