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

John Ladasky jladasky at itu.edu
Wed Jun 29 23:25:12 EDT 2016


I thought ahead about the window resizing problem.  I can see how that
might complicate the process of blitting.  I fix the size of my application
window and its children on initialization, and disable window resizing.

On Wed, Jun 29, 2016 at 7:55 PM, Thomas Caswell <tcaswell at gmail.com> wrote:

> My go-to reference for blitting is either the animation.py source or Joe
> Kington's answers on stackoverflow.
>
> If you go down the blitting route you have to be careful to refresh your
> saved canvas areas on re-size.
>
> To extend on my comment about only re-drawing when you really have to.  If
> you mark an artist as `animated` (`art.set_animated(True)`) it will be
> excluded from the normal draw loop.  You can then, only when you have to,
> trigger a full redraw (via `draw_idle` ), in a draw_event callback re-draw
> the ticks, and then update the artists in the axes on every new data point.
>
> Tom
>
>
> On Wed, Jun 29, 2016 at 10:30 PM John Ladasky <jladasky at itu.edu> wrote:
>
>> Hi Thomas,
>>
>> Thanks for your reply.
>>
>> 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.
>>
>>
>> Alas, at least for now, each of my five axes is contained in a single
>> Figure.  I suppose that I could refactor my code and embed five separate
>> FigureCanvas objects, each containing one axes, in my PyQt object.  If, as
>> you say, I would gain very little by getting fancy with the redrawing of
>> this one object, that may be the way to go.
>>
>> I like your idea of blitting the empty region, though. Is anyone aware of
>> any example code that shows this being done?
>>
>> On Wed, Jun 29, 2016 at 6:15 PM, Thomas Caswell <tcaswell at gmail.com>
>> wrote:
>>
>>> 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
>>>>
>>>
>>
>>
>> --
>> *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*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20160629/9326d6c3/attachment-0001.html>


More information about the Matplotlib-users mailing list