matplotlib 中带有滑块小部件的日期时间 [英] datetime with slider widget in matplotlib

查看:100
本文介绍了matplotlib 中带有滑块小部件的日期时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够滚动表示日期/时间的 x(水平)线.为此,我正在使用滑块小部件.问题是,当我滚动太远(不存在y值)时,我将无法再使用滑块小部件提供的滚动功能,并且整个绘制的线条都消失了,只是空白.我在终端上收到的错误如下:

I want to be able to scroll across x (horizontal) line which represents date/time. For this purpose I'm using slider widget. The problem is that when I scroll too far (where no y values exists) I am no more able to use scrolling feature provided by slider widget and the whole plotted lines disappear and remains just empty figure. The error I get on terminal is following:

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) Need to say that this short version also causes described errors:

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的最大大小或某些限制有关.

I suspect that this has something to do with maximum size of Slider or some of it's limits.

这是可行的解决方案,以防万一(对较短代码的随机生成器代替了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()

在您完成第一个情节之后,您会得到

Just after your first plots, you'll get

(733955.0, 733955.75, 0.0, 50.0)

从滑块小部件的文档你可以看到您的滑块正在创建0.1到90之间的值

From the documentation of the slider widget you can see that your slider is creating values from 0.1 to 90

然后,滑块更新功能将在以下位置为图形创建新轴

And then the slider update function is creating new axes to your graph at

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

其中 pos 是滑块的值.因此,新轴与绘图数据的形状,位置都不匹配

Where pos is the value of your slider. So the new axis does not match nor the shape nor the position of your plotted data

因此,您应该更新滑块的范围和值以及更新后的轴的形状.

So you should update the range and values of your slider and the shape of the updated axis.

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

Also the errors are because you are trying to parse a very small number as a date, but that is irrelevant in this case

这篇关于matplotlib 中带有滑块小部件的日期时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆