我希望能够滚动表示日期/时间的x(水平)线。为此我正在使用slider widget。问题是,当我滚动太远(没有y值存在)时,我不再能够使用滑块小部件提供的滚动功能,并且整个绘制的线条消失并且仍然只是空图。我在终端上遇到的错误如下:
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()
输入(简短版)需要说这个简短版本也会导致描述错误:
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()
答案 0 :(得分:2)
您的问题在于轴的定义
如果你添加
print plt.axis()
在您的第一个情节之后,您将获得
(733955.0, 733955.75, 0.0, 50.0)
From the documentation of the slider widget您可以看到滑块正在创建0.1到90之间的值
然后滑块更新功能正在为图表创建新轴
ax.axis([pos,pos+10,-1,1])
其中pos是滑块的值。因此,新轴与形状和绘制数据的位置不匹配
因此,您应该更新滑块的范围和值以及更新轴的形状。
此外,错误是因为您尝试将非常小的数字解析为日期,但在这种情况下这是无关紧要的