[Matplotlib-users] Real-time graph, redrawing a changing Y axis

Thomas Caswell tcaswell at gmail.com
Wed Jun 29 21:15:05 EDT 2016


If you are re-computing the limits and re-drawing the yticks anyway, you
are not getting much benefit from being fancy about re-drawing.  You might
as well do

self.plot.set_data(self.x[:size], self.y[:size])
lo = self.y[:size].min()
hi = self.y[:size].max()
if hi - lo > 150:
    self.ax.set_ylim(lo-25, hi+25)
else:
    mid = self.y[:size].mean()
    self.ax.set_ylim(mid-100, mid+100)
self.ax.relim()
self.ax.autoscale_view(None, False, True)
self.ax.figure.canvas.draw_idle()

which will schedule a full re-draw the next time that the GUI repaints (and
requests the the GUI do so 'some time soon').  Depending on your data-rates
this may allow multiple draws to be squashed into one. This assumes that
each of your axes is in it's own figure.

Failing that, you will have to do something like, on first draw / or resize
turn off the y-ticks, use `copy_from_bbox` to grab the empty region and the
use blit to restore it before drawing the next frame.

You might also get away with just keeping better track of when the view
limits _need_ to change and then only triggering the `draw_idle` for that.

Tom

On Wed, Jun 29, 2016 at 7:23 PM John Ladasky <jladasky at itu.edu> wrote:

> Hi Jody,
>
> Thanks for your reply.  I'm aware of Matplotlib's animation API.  I'm not
> sure that it would help me.
>
> As far as I can tell, the purpose of animation.FuncAnimation() is to
> connect a data generating function to the update function of a MPL object,
> and to drive it all with a timer.  It's an event loop, for people who
> aren't already writing event-driven code (which I am, I have 1,200 lines of
> mostly-working PyQt5).  What actually gets done in the MPL update method is
> what I think is important to me.  I want to change only what needs to be
> changed.
>
> My approach is best described by this article:
>
> http://bastibe.de/2013-05-30-speeding-up-matplotlib.html
>
> The article is a few years old, I know.  Still, using the advice I found
> in articles like this one, I limited redrawing, and everything updates in
> under 10 milliseconds, a 15-fold improvement over my original
> redraw-everything approach. In total, I have five live graphs on the
> screen. It's only this one self-adjusting time series graph that is
> misbehaving for me.
>
> On Wed, Jun 29, 2016 at 3:36 PM, Jody Klymak <jklymak at uvic.ca> wrote:
>
>>
>> On Jun 29, 2016, at  15:12 PM, John Ladasky <jladasky at itu.edu> wrote:
>>
>> I am using MPL 1.4.2, Python 3.4, and Ubuntu 15.04.  I am developing a
>> program which displays real-time data.  On each update cycle, the graph
>> needs to adjust the y-axis scale.  I have code that mostly works, but when
>> it re-renders the y-axis, it is not completely erasing the old one.  I get
>> tick labels written on top of each other, until everything is an unreadable
>> smear, like this:
>>
>>
>> I think thats because `redraw_in_frame()` doesn’t update any of the axes
>> data…
>>
>> Have you looked into the animation API?  Its meant for this sort of
>> thing, and seems pretty snappy.  Most of what you are doing below would
>> just go into the `animate` function.
>>
>> http://matplotlib.org/examples/animation/simple_anim.html
>>
>> Cheers,   Jody
>>
>>
>>
>>
>> <For matplotlib-users.png>
>>
>> Here is the relevant part of my update method:
>>
>> self.plot.set_data(self.x[:size], self.y[:size])
>> lo = self.y[:size].min()
>> hi = self.y[:size].max()
>> if hi - lo > 150:
>>     self.ax.set_ylim(lo-25, hi+25)
>> else:
>>     mid = self.y[:size].mean()
>>     self.ax.set_ylim(mid-100, mid+100)
>> self.ax.relim()
>> self.ax.autoscale_view(None, False, True)
>> self.ax.redraw_in_frame()
>> # Something which erases the Y axis should go here?
>> self.ax.get_yaxis().draw(self.parent.get_renderer())
>>
>>
>> I think that the details of setting the Y limits are unimportant, but
>> I've included that code anyway, so that you can see my set_data() method
>> call at the top, and you can also see that I'm continually adjusting the Y
>> range to track the data.
>>
>> I think that I am searching for a method in the axis class which would
>> erase the previously drawn tick marks and labels.  So far, I haven't found
>> one.  It would replace the comment line in my code.
>>
>> I am trying to avoid redrawing the entire canvas on which this plot is
>> embedded, since there are several other live data plots besides the one I
>> have shown. The first version of my program did a full redraw, and it took
>> over 150 milliseconds to complete an update call.  That's too slow for my
>> needs.
>>
>> Thanks for any help you can provide!
>>
>> --
>> *John J. Ladasky Jr., Ph.D.*
>> *Research Scientist*
>> *International Technological University*
>> *2711 N. First St, San Jose, CA 95134 USA*
>> _______________________________________________
>> Matplotlib-users mailing list
>> Matplotlib-users at python.org
>> https://mail.python.org/mailman/listinfo/matplotlib-users
>>
>>
>>
>
>
> --
> *John J. Ladasky Jr., Ph.D.*
> *Research Scientist*
> *International Technological University*
> *2711 N. First St, San Jose, CA 95134 USA*
> _______________________________________________
> Matplotlib-users mailing list
> Matplotlib-users at python.org
> https://mail.python.org/mailman/listinfo/matplotlib-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20160630/78aa3ec8/attachment.html>


More information about the Matplotlib-users mailing list