python - matplotlib 中带有 slider 小部件的日期时间

标签 python matplotlib

我希望能够滚动代表日期/时间的 x(水平)线。为此,我使用 slider widget .问题是,当我滚动得太远(没有 y 值存在)时,我无法再使用 slider 小部件提供的滚动功能,并且整个绘制的线条消失并且仍然只是空图。我在终端上得到的错误如下:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1535, in __call__
    return self.func(*args)
  File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 586, in callit
    func(*args)
  File "/usr/lib/python2.7/dist-packages/matplotlib/backends/backend_tkagg.py", line 365, in idle_draw
    self.draw()
  File "/usr/lib/python2.7/dist-packages/matplotlib/backends/backend_tkagg.py", line 349, in draw
    FigureCanvasAgg.draw(self)
  File "/usr/lib/python2.7/dist-packages/matplotlib/backends/backend_agg.py", line 469, in draw
    self.figure.draw(self.renderer)
  File "/usr/lib/python2.7/dist-packages/matplotlib/artist.py", line 59, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/matplotlib/figure.py", line 1079, in draw
    func(*args)
  File "/usr/lib/python2.7/dist-packages/matplotlib/artist.py", line 59, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/matplotlib/axes/_base.py", line 2092, in draw
    a.draw(renderer)
  File "/usr/lib/python2.7/dist-packages/matplotlib/artist.py", line 59, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/matplotlib/axis.py", line 1114, in draw
    ticks_to_draw = self._update_ticks(renderer)
  File "/usr/lib/python2.7/dist-packages/matplotlib/axis.py", line 957, in _update_ticks
    tick_tups = [t for t in self.iter_ticks()]
  File "/usr/lib/python2.7/dist-packages/matplotlib/axis.py", line 901, in iter_ticks
    majorLocs = self.major.locator()
  File "/usr/lib/python2.7/dist-packages/matplotlib/dates.py", line 867, in __call__
    return self._locator()
  File "/usr/lib/python2.7/dist-packages/matplotlib/dates.py", line 676, in __call__
    start = dmin - delta
  File "/usr/local/lib/python2.7/dist-packages/dateutil/relativedelta.py", line 309, in __rsub__
    return self.__neg__().__radd__(other)
  File "/usr/local/lib/python2.7/dist-packages/dateutil/relativedelta.py", line 306, in __radd__
    return self.__add__(other)
  File "/usr/local/lib/python2.7/dist-packages/dateutil/relativedelta.py", line 293, in __add__
    microseconds=self.microseconds))
OverflowError: date value out of range
Exception in Tkinter callback

代码:

#!/usr/bin/python

import csv
import sys
import datetime
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

if len(sys.argv[1:]) != 1:
  print "Pass csv file(s) to read from"
  sys.exit(1)

x  = []
y1 = []
y2 = []

# read csv
with open(sys.argv[1], 'rt') as inputFile:
  csvReader = csv.reader(inputFile)

  # skip header row
  csvReader.next()

  for row in csvReader:
    timestamp = datetime.datetime.strptime(row[0], "%Y-%m-%d %H:%M:%S")
    x.append(timestamp)
    y1.append(row[1])
    y2.append(row[2])


# plot
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)

# I've also tried convert the dates to matplotlib format but did not help
# import matplotlib
# x = matplotlib.dates.date2num(x)
# matplotlib.pyplot.plot_date(x, y1)

consumption, = plt.plot(x, y1, "b-", label="kw_energy_consumption")
prediction,  = plt.plot(x, y2, "r-", label="prediction")

axcolor = 'lightgoldenrodyellow'
axpos = plt.axes([0.2, 0.1, 0.65, 0.03], axisbg=axcolor)
spos = Slider(axpos, 'Pos', 0.1, 90.0)

def update(val):
    pos = spos.val
    ax.axis([pos,pos+10,-1,1])
    fig.canvas.draw_idle()

spos.on_changed(update)

plt.gcf().autofmt_xdate()
plt.show()

Input (short version) 需要说明的是这个short version也会导致描述的错误:

timestamp,kw_energy_consumption,prediction
2010-07-02 00:00:00,21.2,21.2
2010-07-02 01:00:00,16.4,16.4
2010-07-02 02:00:00,4.7,16.4
2010-07-02 03:00:00,4.7,4.7
2010-07-02 04:00:00,4.6,4.7
2010-07-02 05:00:00,23.5,4.67
2010-07-02 06:00:00,47.5,47.5
2010-07-02 07:00:00,45.4,47.5
2010-07-02 08:00:00,46.1,45.4
2010-07-02 09:00:00,41.5,45.61
2010-07-02 10:00:00,43.4,45.61
2010-07-02 11:00:00,43.8,45.61
2010-07-02 12:00:00,37.8,43.519999999999996
2010-07-02 13:00:00,36.6,43.519999999999996
2010-07-02 14:00:00,35.7,37.44
2010-07-02 15:00:00,38.9,37.44
2010-07-02 16:00:00,36.2,38.9
2010-07-02 17:00:00,36.6,38.9
2010-07-02 18:00:00,37.2,37.188

我怀疑这与 Slider 的最大尺寸或它的某些限制有关。

编辑:这是可行的解决方案,以防有人感兴趣(csv 阅读器被随机生成器取代以获得更短的代码)

#!/usr/bin/python

import sys
import numpy as np
import datetime
import random
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)

x = [datetime.datetime(2015,6,25) + datetime.timedelta(hours=i) for i in range(25)]
y = [i+random.gauss(0,1) for i,_ in enumerate(x)]

l, = plt.plot(x,y)

x_min_index = 0
x_max_index = 5

x_min = x[x_min_index]
x_max = x[x_max_index]

# timedelta
x_dt = x_max - x_min

# plt.axis(x_min, x_max, y_min, y_max)
y_min = plt.axis()[2]
y_max = plt.axis()[3]

plt.axis([x_min, x_max, y_min, y_max])


axcolor = 'lightgoldenrodyellow'
axpos = plt.axes([0.2, 0.1, 0.65, 0.03], axisbg=axcolor)

slider_max = len(x) - x_max_index - 1

# Slider(axes, name, min, max)
spos = Slider(axpos, 'Pos', matplotlib.dates.date2num(x_min), matplotlib.dates.date2num(x[slider_max]))

# pretty date names
plt.gcf().autofmt_xdate()

def update(val):
    pos = spos.val
    xmin_time = matplotlib.dates.num2date(pos)
    xmax_time = matplotlib.dates.num2date(pos) + x_dt
    # print "x_min: %s, x_max: %s" % (xmin_time.strftime("%H:%M:%S.%f"), xmax_time.strftime("%H:%M:%S.%f"))

    ########################################################
    # RETURNS THE SAME RESULT:

    # xmin_time is datetime.datetime
    # print type(xmin_time)
    # ax.axis([xmin_time, xmax_time, y_min, y_max])

    # xmin_time is numpy.float64
    xmin_time = pos
    print type(xmin_time)
    ax.axis([xmin_time, xmax_time, y_min, y_max])
    ########################################################
    fig.canvas.draw_idle()

spos.on_changed(update)

plt.show()

最佳答案

你的问题是你的轴的定义

如果你添加

print plt.axis()

在你的第一个情节之后,你会得到

(733955.0, 733955.75, 0.0, 50.0)

From the documentation of the slider widget你可以看到你的 slider 正在创建从 0.1 到 90 的值

然后 slider 更新功能正在为您的图形创建新轴

ax.axis([pos,pos+10,-1,1])

其中 pos 是 slider 的值。所以新轴既不匹配也不匹配你绘制的数据的形状和位置

因此您应该更新 slider 的范围和值以及更新轴的形状。

此外,错误是因为您试图将非常小的数字解析为日期,但这在这种情况下无关紧要

关于python - matplotlib 中带有 slider 小部件的日期时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31015755/

相关文章:

Python - 识别列表中的负数

python - hadoopy.launch_frozen无法执行脚本

python - 设置在 matplotlib 中使用 plt.subplots 创建的图形的高度和宽度?

python - 如何设置 axvlines 使用与 matplotlib 中的 axes.color_cycle 相同的颜色?

python - 等效的 vmin vmax matplotlib Bokeh

python - print(input() + input()) 在 python 中如何工作?没有变量赋值?

python - 使用 Postgresql 数据库创建 Azure Web 应用程序(这可能吗?)

pandas - 如何清晰地绘制 statsmodels 线性回归 (OLS)

python - Python 中 x = y = z 的背后是什么?

python - 在四维 matplotlib 曲面中更改 Facecolors