6

目的: グラフ (x,y) をプロットし、グラフ上で垂直線をタイマーに移動します。

matplotlib を使用してこれを実装し始めました。matplotlib の draw() 機能を使用してこれを実装することは可能ですが、毎回再描画するため CPU を消費し、グラフを操作できません。そこで、matplotlib のアニメーション機能を使用することにしました。将来的には動線も一時停止したいと思っています。だから私はmatplotlib.animation.FuncAnimatinを使うことができません

問題: canvas.copy_from_bbox(ax.bbox)、ax.draw_artist(line)、canvas.blit(ax.bbox) を使用しています。しかし、グラフをバックグラウンドで保存して、その上に線を移動することはできません。保存しようとすると、かなり奇妙な方法で上書きされます。

これは私が構築したコードです。誰でも私を助けてもらえますか?前もって感謝します。

import sys
import matplotlib.pyplot as p
import time
fig=p.figure();
ax = fig.add_subplot(1,1,1)

y=[];x=[];y1=[0,1000];x1=[0,0]
y=numpy.random.randn(1000,1)*100
x=numpy.arange(0,1000)
line1, = ax.plot(x,y,color='black');
ax.set_ylim(0, 1000);
line, = ax.plot(x1,y1,color='r',alpha=1,animated=True); # this is the line which i wanted to move over the graph w.r.t to time. ( i can also use axvline , but i guess its the same).
canvas = ax.figure.canvas
canvas.draw()
background = canvas.copy_from_bbox(ax.bbox); #my problem is here
starttime=time.time();
mytimer=0;
mytimer_ref=0;
def update(canvas,line,ax):
    canvas.restore_region(background) #my problem is here 
    t=time.time()-starttime;
    mytimer=t+mytimer_ref;
    x1=[mytimer,mytimer];
    line.set_xdata(x1);
    ax.draw_artist(line)
    canvas.blit(ax.bbox) #my problem is here

def onclick(event):
    global starttime
    starttime=time.time();
    global mytimer_ref;
    mytimer_ref=event.xdata;
    print "starttime",starttime;


cid=line1.figure.canvas.mpl_connect('button_press_event',onclick); # when i click the mouse over a point, line goes to that point and start moving from there. 
timer=fig.canvas.new_timer(interval=100);
args=[canvas,line,ax];
timer.add_callback(update,*args); # every 100ms it calls update function
timer.start();
p.show();
4

1 に答える 1

4

したがって、あなたが言及している「かなり奇妙な方法」は、本質的に間違った bbox がbackground = canvas.copy_from_bbox(ax.bbox). これは、ツールバーなどの追加が blit の bbox の位置に影響を与えるほとんどのバックエンドで既知の問題であると思います。

基本的に、ウィンドウがポップアップしたに背景をキャプチャできれば、すべてがうまく機能するはずです。これはいくつかの方法で行うことができます。あなたの場合、最も簡単なのは、canvas.draw()コマンドをに置き換えるplt.show(block=False)ことです。これにより、ウィンドウが表示され、ブロックコマンドにはなりません。

ちょっとした追加として、Pythonコードではセミコロンが必要ないことはご存知だと思いますが、デバッグ中にコードを少し整理しました(最後まで行きませんでした):

import sys
import matplotlib.pyplot as plt
import time
import numpy


fig = plt.figure()
ax = fig.add_subplot(111)


max_height = 100
n_pts = 100
y1 = [0, max_height]
x1 = [0, 0]
y = numpy.random.randn(n_pts) * max_height
x = numpy.arange(0, n_pts)

# draw the data
line1, = ax.plot(x, y, color='black')

# fix the limits of the plot
ax.set_ylim(0, max_height)
ax.set_xlim(0, n_pts)

# draw the plot so that we can capture the background and then use blitting
plt.show(block=False)

# get the canvas object
canvas = ax.figure.canvas
background = canvas.copy_from_bbox(ax.bbox)

# add the progress line.
# XXX consider using axvline
line, = ax.plot(x1, y1, color='r', animated=True) 


starttime=time.time()
mytimer=0
mytimer_ref=0

def update(canvas, line, ax):
    # revert the canvas to the state before any progress line was drawn
    canvas.restore_region(background)

    # compute the distance that the progress line has made (based on running time) 
    t = time.time() - starttime
    mytimer = t + mytimer_ref
    x1 = [mytimer,mytimer]
    # update the progress line with its new position
    line.set_xdata(x1)
    # draw the line, and blit the axes
    ax.draw_artist(line)
    canvas.blit(ax.bbox)

def onclick(event):
    global starttime
    starttime=time.time()
    global mytimer_ref
    mytimer_ref=event.xdata
    print "starttime",starttime


cid=line1.figure.canvas.mpl_connect('button_press_event',onclick) # when i click the mouse over a point, line goes to that point and start moving from there. 
timer=fig.canvas.new_timer(interval=100)
args=[canvas,line,ax]
timer.add_callback(update,*args) # every 100ms it calls update function
timer.start()
plt.show()

HTH

于 2012-08-14T07:41:11.630 に答える