【问题标题】:Plotting times versus dates while skipping unwanted dates in Python在 Python 中跳过不需要的日期时绘制时间与日期
【发布时间】:2019-06-02 23:05:29
【问题描述】:

我想制作一个程序来监控我的 5000 米进度。受到thisthis 的启发,我尝试通过组合一些答案来使其工作,但没有任何运气。

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')

我从@ascripter(来自第二个链接)窃取了equidate_ax,因为我想跳过所有我不运行的日期。

如果我运行这段代码并保存这些数字,我最终会得到以下两个相当奇怪的数字,因为 y 轴不区分较低或较高的值(图 1 和 2),并且图 2 的 x 轴在重复。 图 1:来自上述代码的fig_1 图 2:来自上述代码的fig_2

  • 为什么 y 轴不能正确绘制较低或较高的值?
  • 如何防止 equidate_ax 函数重复自身,而跳过不需要的日期?

如果有人能帮我收拾残局,我将不胜感激。

【问题讨论】:

    标签: python datetime matplotlib


    【解决方案1】:

    结合所链接问题的答案:

    你基本上必须确保 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()
    

    它会产生这样的情节:

    【讨论】:

      【解决方案2】:

      虽然@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()
      

      这更短,也许更容易理解。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-29
        • 2019-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-26
        • 1970-01-01
        相关资源
        最近更新 更多