График зависимости времени от даты при пропуске нежелательных дат в Python - PullRequest
0 голосов
/ 01 июня 2019

Я хочу создать программу, которая будет следить за моим прогрессом в 5000 метров. Вдохновленный этим и этим , я пытался заставить его работать, комбинируя некоторые ответы без всякой удачи.

from __future__ import division
from matplotlib import pyplot as plt
from matplotlib.ticker import FuncFormatter
import matplotlib.dates as mdates
import numpy as np
import datetime as dt

def equidate_ax(fig, ax, dates, fmt="%d.%m.%Y", label="Date"):
    N = len(dates)
    def format_date(index, pos):
        index = np.clip(int(index + 0.5), 0, N - 1)
        return dates[index].strftime(fmt)
    ax.xaxis.set_major_formatter(FuncFormatter(format_date))
    ax.set_xlabel(label)
    fig.autofmt_xdate()

def DistVel2Time(distance, velocity_kph):
    velocity_ms = velocity_kph / 3.6
    time_sec = distance / velocity_ms
    hours = int(time_sec//3600)
    minutes = int((time_sec%3600)//60)
    seconds = int(time_sec%60)
    return "{:02d}:{:02d}".format(minutes, seconds)

times = [DistVel2Time(a, b) for a, b in [(5000, 13), (5000, 15), (5000, 14)]]

dates = [dt.datetime(year, month, day) for year, month, day in [(2019,2,1), (2019,2,2), (2019,2,7)]]

fig_1, ax_1 = plt.subplots()
ax_1.plot(dates, times, 'o--')
ax_1.xaxis_date()
ax_1.xaxis.set_major_formatter(mdates.DateFormatter('%d.%m.%Y'))
#ax_1.yaxis_date()
#ax_1.yaxis.set_major_formatter(mdates.DateFormatter("%M:%S"))
fig_1.autofmt_xdate()
plt.show()

fig_2, ax_2 = plt.subplots()
ax_2.plot(dates, times, 'D--')
ax_2.xaxis_date()
ax_2.xaxis.set_major_formatter(mdates.DateFormatter('%d.%m.%Y'))
equidate_ax(fig_2, ax_2, dates)
plt.show()

fig_1.savefig('fig1.png')
fig_2.savefig('fig2.png')

Я украл equidate_ax из @ascripter (из второй ссылки), потому что я хотел бы пропустить все даты, которые я не запускаю.

Если я запускаю этот фрагмент кода и сохраняю рисунки, я получаю следующие два довольно странных рисунка, поскольку ось Y не различает более низкие или более высокие значения (рисунки 1 и 2), и ось х на рисунке 2 повторяется. enter image description here Рисунок 1: fig_1 из кода выше. enter image description here Рисунок 2: fig_2 из кода выше.

  • Почему неправильно отображается ось Y с точки зрения более низких или более высоких значений?
  • Как я могу предотвратить повторение функции equidate_ax и пропустить нежелательные даты?

Если бы кто-нибудь мог помочь убрать мой беспорядок, я был бы благодарен.

Ответы [ 2 ]

1 голос
/ 01 июня 2019

Объединение ответов на связанные вопросы:

Вы должны убедиться, что matplotlib не может угадать формат оси x, но может угадать формат оси y. С этим matplotlib не будет пытаться быть умным и добавлять даты, которые вы не хотите отображать на оси X, но в то же время будет умным и сортировать время для вас по оси Y.

from __future__ import division
from matplotlib import pyplot as plt
from matplotlib.ticker import FuncFormatter
import matplotlib.dates as mdates
import numpy as np
import datetime as dt

def DistVel2Time(distance, velocity_kph):
    velocity_ms = velocity_kph / 3.6
    time_sec = distance / velocity_ms
    hours = int(time_sec//3600)
    minutes = int((time_sec%3600)//60)
    seconds = int(time_sec%60)
    # note that I return a timedelta object here
    return dt.timedelta(minutes=minutes, seconds=seconds)

# we have to choose a interpretable data-type here, simply take the total time needed in seconds
times = [ DistVel2Time(a, b).total_seconds() for a, b in [(5000, 13), (5000, 15), (5000, 14)]]

# here we want to make sure that matplotlib cannot interpret it so we use strings directly
# change the format as required
dates = [ "%00d.%00d.%000d" % ymd for ymd in [(2019,2,1), (2019,2,2), (2019,2,7)]]

# the formatting function taken from https://stackoverflow.com/questions/48294332/plot-datetime-timedelta-using-matplotlib-and-python
def format_func(x, pos):
    hours = int(x//3600)
    minutes = int((x%3600)//60)
    seconds = int(x%60)

    return "{:d}:{:02d}:{:02d}".format(hours, minutes, seconds)

formatter = FuncFormatter(format_func)

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

ax.plot(dates, times, 'o--')
ax.yaxis.set_major_formatter(formatter)

plt.show()

Будет получен сюжет, подобный этому:

0 голосов
/ 02 июня 2019

Хотя @milck ответил на мои вопросы, я сделал более упрощенную версию, вдохновленную его ответом и ранее упомянутыми ответами на вопрос.

from matplotlib import pyplot as plt
from matplotlib.ticker import FuncFormatter

def DistVel2Time(*velocity_kph):
    distance = 5000
    times = [int(distance / (_ / 3.6)) for _ in velocity_kph]
    return times

times = DistVel2Time(13, 15, 14)

dates = ["%00d.%00d.%000d" % dmy for dmy in [(1,2,2019), (2,2,2019), (7,2,2019)]]

def format_func(x, pos):
    #hours = int(x//3600)
    minutes = int((x%3600)//60)
    seconds = int(x%60)
    return "{:02d}:{:02d}".format(minutes, seconds)

formatter = FuncFormatter(format_func)

fig, ax = plt.subplots()

ax.plot(dates, times, 'D--')
ax.yaxis.set_major_formatter(formatter)
fig.autofmt_xdate()

plt.show()

Это короче и, возможно, легче понять.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...