Axises autoscaling in animated plot

Could please anyone help me to get axises autoscaling in following example? I took it from the examples and slightly modified it to remove all unecessary things trying to make it as short as possible.

Thanks in advance!

import sys

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

from PyQt4 import QtGui

import numpy as np
import time

class BlitQT(FigureCanvas):
     def __init__(self):
         FigureCanvas.__init__(self, Figure())

         self.ax = self.figure.add_subplot(111)
         self.ax.grid()
         self.draw()

         self.ax_background = self.copy_from_bbox(self.ax.bbox)
         self.cnt = 0

         self.x = np.arange(0,2*np.pi,0.01)
         self.sin_line, = self.ax.plot(self.x, np.sin(self.x), animated=True)
         self.cos_line, = self.ax.plot(self.x, np.cos(self.x), animated=True)

         self.tstart = time.time()
         self.startTimer(10)

     def timerEvent(self, evt):
         self.restore_region(self.ax_background, bbox=self.ax.bbox)

         # update the data
         self.sin_line.set_ydata(np.sin(self.x+self.cnt/10.0))
         self.cos_line.set_ydata((self.x+self.cnt)/50.0)
         # just draw the animated artist
         self.ax.draw_artist(self.sin_line)
         self.ax.draw_artist(self.cos_line)
         # just redraw the axes rectangle
         self.blit(self.ax.bbox)

         if self.cnt == 0:
             self.draw()
         self.cnt += 1

app = QtGui.QApplication(sys.argv)
widget = BlitQT()
widget.show()

sys.exit(app.exec_())

The problem here is probably with the blitting. You make a copy of the background before plotting the data. Before you plot the data, the axes have no clue what’s its limits are supposed to be. In your example, it won’t know until you do the plotting. Then when you restore the background, it is restoring the background that never knew the limits.

I suggest calling ax.set_xlim() and ax.set_ylim() before doing the copy_from_bbox().

I hope that helps,
Ben Root

···

On Thu, Jul 22, 2010 at 3:30 AM, aliko <ali.tlisov@…287…> wrote:

Could please anyone help me to get axises autoscaling in following

example? I took it from the examples and slightly modified it to remove

all unecessary things trying to make it as short as possible.

Thanks in advance!

import sys

from matplotlib.figure import Figure

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as

FigureCanvas

from PyQt4 import QtGui

import numpy as np

import time

class BlitQT(FigureCanvas):

 def __init__(self):

     FigureCanvas.__init__(self, Figure())



     [self.ax](http://self.ax) = self.figure.add_subplot(111)

     self.ax.grid()

     self.draw()



     self.ax_background = self.copy_from_bbox(self.ax.bbox)

     self.cnt = 0



     self.x = np.arange(0,2*np.pi,0.01)

     self.sin_line, = self.ax.plot(self.x, np.sin(self.x),

animated=True)

     self.cos_line, = self.ax.plot(self.x, np.cos(self.x),

animated=True)

     self.tstart = time.time()

     self.startTimer(10)



 def timerEvent(self, evt):

     self.restore_region(self.ax_background, bbox=self.ax.bbox)



     # update the data

     self.sin_line.set_ydata(np.sin(self.x+self.cnt/10.0))

     self.cos_line.set_ydata((self.x+self.cnt)/50.0)

     # just draw the animated artist

     self.ax.draw_artist(self.sin_line)

     self.ax.draw_artist(self.cos_line)

     # just redraw the axes rectangle

     self.blit(self.ax.bbox)



     if self.cnt == 0:

         self.draw()

     self.cnt += 1

app = QtGui.QApplication(sys.argv)

widget = BlitQT()

widget.show()

sys.exit(app.exec_())

The problem here is probably with the blitting. You make a copy of the background before plotting the data. Before you plot the data, the axes have no clue what's its limits are supposed to be. In your example, it won't know until you do the plotting. Then when you restore the background, it is restoring the background that never knew the limits.

I suggest calling ax.set_xlim() and ax.set_ylim() before doing the copy_from_bbox().

I hope that helps,
Ben Root

Thank you very much Ben Root for your prompt response and valuable assistance! Now I can set the limits using set_ylim. I call it just before self.restore_region(...). But I should calculate limits myself in order to provide them to that function.
In my case it looks like this:

y1 = np.sin(self.x+self.cnt/10.0)
y2 = (self.x+self.cnt)/50.0
self.ax.set_ylim(min(y1.min(), y2.min()), max(y1.max(), y2.max()))

another way I've discovered is to call plot() function in every step. But this approach is little slowly the difference is about 5%.

Although the curves now are fitting in the box, the axes data does not updated and freezes at some initial values. I'm also reworked example in order to use two Y axises one to the left and one at the right. And the second plot attached to the right axis is not autoscaled as the first does. Those the two things stops me now.
Any suggestions is highly appreciated!

# -*- coding: utf-8 -*-
"""
Created on Fri Jul 23 10:53:59 2010

@author: ali
"""

import sys

from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

from PyQt4 import QtGui

import numpy as np
import time

ITERS = 1000

class BlitQT(FigureCanvas):
     def __init__(self):
         FigureCanvas.__init__(self, Figure())
         self.figure.subplots_adjust(right=0.75)

         self.ax1 = self.figure.add_subplot(111)
         self.ax1.set_ylabel("Func1")
         self.ax2 = self.ax1.twinx()
         self.ax2.set_ylabel("Func2")

         self.ax1.grid()
         self.draw()

         self.ax1_background = self.copy_from_bbox(self.ax1.bbox)
         self.ax2_background = self.copy_from_bbox(self.ax2.bbox)
         self.cnt = 0

         self.x = np.arange(0,2*np.pi,0.01)
         self.line1, = self.ax1.plot(self.x, np.sin(self.x), 'b', animated=True)
         self.line2, = self.ax2.plot(self.x, np.cos(self.x), 'r', animated=True)

         self.tstart = time.time()
         self.startTimer(10)

     def timerEvent(self, evt):
         y1 = self.x * np.sin(self.x+self.cnt/10.0)
         y2 = np.cos(self.x+self.cnt/10.0) / self.x
         self.ax1.set_ylim(y1.min(), y1.max())
         self.ax2.set_ylim(y2.min(), y2.max())
         self.restore_region(self.ax1_background, bbox=self.ax1.bbox)
# self.restore_region(self.ax2_background, bbox=self.ax2.bbox)

         # update the data
         self.line1.set_ydata(y1)
         self.line2.set_ydata(y2)
         # just draw the animated artist
         self.ax1.draw_artist(self.line1)
         self.ax2.draw_artist(self.line2)
         # just redraw the axes rectangle
# self.blit(self.ax1.bbox)
         self.blit(self.ax2.bbox)

         if self.cnt == 0:
             self.draw()
         if self.cnt==ITERS:
             # print the timing info and quit
             print 'FPS:' , ITERS/(time.time()-self.tstart)
             sys.exit()
         else:
             self.cnt += 1

app = QtGui.QApplication(sys.argv)
widget = BlitQT()
widget.show()

sys.exit(app.exec_())

aliko,

By doing the plot() call at every iteration of the loop, you are causing conflicts with the blitting code, which is the source of the slowness. You need to remove the plot() calls you added and move the set_ylim() call to before “self.ax1_background = self.copy_from_bbox(self.ax1.bbox)”. Actually, it probably should also be before the call to “self.draw()”.

Here is why. When you create an axes, but have not yet plotted any data, the limits aren’t known. When you copy the background, it is copying whatever it knows at that time – which is that it does not know the limits. Then, each call to “restore_region()” restores that information – including the fact that it doesn’t know the limits.

Therefore, if you set the limits before drawing the background and copying it, then restore_region() will then know the proper axes limits and handle it correctly.

I hope this makes more sense.

Ben Root

···

On Fri, Jul 23, 2010 at 3:18 AM, aliko <ali.tlisov@…287…> wrote:

Although the curves now are fitting in the box, the axes data does not

updated and freezes at some initial values. I’m also reworked example in

order to use two Y axises one to the left and one at the right. And the

second plot attached to the right axis is not autoscaled as the first

does. Those the two things stops me now.

Any suggestions is highly appreciated!

-- coding: utf-8 --

“”"

Created on Fri Jul 23 10:53:59 2010

@author: ali
“”"

import sys

from matplotlib.figure import Figure

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as

FigureCanvas

from PyQt4 import QtGui

import numpy as np

import time

ITERS = 1000

class BlitQT(FigureCanvas):

 def __init__(self):

     FigureCanvas.__init__(self, Figure())

self.figure.subplots_adjust(right=0.75)

     self.ax1 = self.figure.add_subplot(111)

     self.ax1.set_ylabel("Func1")

     self.ax2 = self.ax1.twinx()

     self.ax2.set_ylabel("Func2")



     self.ax1.grid()

     self.draw()



     self.ax1_background = self.copy_from_bbox(self.ax1.bbox)

     self.ax2_background = self.copy_from_bbox(self.ax2.bbox)

self.cnt = 0

     self.x = np.arange(0,2*np.pi,0.01)

self.line1, = self.ax1.plot(self.x, np.sin(self.x), ‘b’,

animated=True)

     self.line2, = self.ax2.plot(self.x, np.cos(self.x), 'r',

animated=True)

     self.tstart = time.time()

     self.startTimer(10)





 def timerEvent(self, evt):

y1 = self.x * np.sin(self.x+self.cnt/10.0)

     y2 = np.cos(self.x+self.cnt/10.0) / self.x

     self.ax1.set_ylim(y1.min(), y1.max())

     self.ax2.set_ylim(y2.min(), y2.max())

     self.restore_region(self.ax1_background, bbox=self.ax1.bbox)

self.restore_region(self.ax2_background, bbox=self.ax2.bbox)

     # update the data

     self.line1.set_ydata(y1)

     self.line2.set_ydata(y2)

just draw the animated artist

self.ax1.draw_artist(self.line1)

     self.ax2.draw_artist(self.line2)

just redraw the axes rectangle

self.blit(self.ax1.bbox)

     self.blit(self.ax2.bbox)


     if self.cnt == 0:

         self.draw()

if self.cnt==ITERS:

         # print the timing info and quit

         print 'FPS:' , ITERS/(time.time()-self.tstart)

         sys.exit()

     else:

self.cnt += 1

app = QtGui.QApplication(sys.argv)

widget = BlitQT()

widget.show()

sys.exit(app.exec_())