[newbie] "live" plots of multiple lines

Hi All,

Apologies if I'm missing anything obvious...

How do I plot lines point-by-point as opposed to by passing arrays?

I'm guessing something like:

plot([x],[y])

...but that feels a bit weird to me.

In any case, using that, I don't know how to plot more than one line at a time, so thought I'd ask here...

Hope you can help!

cheers,

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Hello Chris,

you may try something like

plot([x1], [y1], "bo", [x2], [y2], "r+")

or you have to iterate through your data.

best regards
Matthias

···

On Friday 07 March 2008 10:11, Chris Withers wrote:

Hi All,

Apologies if I'm missing anything obvious...

How do I plot lines point-by-point as opposed to by passing arrays?

I'm guessing something like:

plot([x],[y])

...but that feels a bit weird to me.

In any case, using that, I don't know how to plot more than one line at
a time, so thought I'd ask here...

Hope you can help!

cheers,

Chris

Matthias Michler wrote:

plot([x1], [y1], "bo", [x2], [y2], "r+")

This didn't work :-S

- the first time I call show(), execution never comes back to my script so the code never gets to plot any further points

- if I put the "show" after the plotting loop (which means I don't get the "live plotting" I'm after) then there are no lines between the points (well, the points don't show at all, but I'm guessing it's because there's no lines between the points)

- looking at the example, I'm left wondering how to pass keyword parameters such as "label" or use other methods such as plot_date

Any help greatfully received!

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

http://matplotlib.sourceforge.net/faq.html#SHOW

hth,
Alan Isaac

···

On Tue, 11 Mar 2008, Chris Withers apparently wrote:

the first time I call show()

Alan G Isaac wrote:

the first time I call show()

http://matplotlib.sourceforge.net/faq.html#SHOW

Okay, that tells me that I prettymuch don't want to be using show(), but I don't think I want interactive mode either...

What I'm trying to do is run a script and plot-and-show as I go.
The script reads the data to be plotted, but each set of points takes up to 20 minutes to generate, so I want to see the points appear on the graph as they arrive.

Is this possible? If so, how?

cheers,

Chris

···

On Tue, 11 Mar 2008, Chris Withers apparently wrote:

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Chris Withers wrote:

Matthias Michler wrote:

plot([x1], [y1], "bo", [x2], [y2], "r+")

This didn't work :-S

- the first time I call show(), execution never comes back to my script so the code never gets to plot any further points

Okay, thanks to Ryan, I now have this point fixed, however, with the following code:

ion()
i = 1
while i < 5:
     plot([i],[i],'go',[i],[i+2],'ro')
     print i
     i+=1
     sleep(0.5)
     draw()

- there are no lines between the points, how do I get the lines to show?

- how would I pass keyword parameters such as "label" or use other methods such as plot_date?

Also, when the above script finishes, I get:

Fatal Python error: PyEval_RestoreThread: NULL tstate

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

What does that mean?

cheers,

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Hello Chris,

maybe I don't know exactly what you want to do - let me try once more:
You try to plot a line where point need to be added, isn't it?
My first idea was that there should be independent points.

maybe something like the following helps you:

···

-----------------------------------------------------------------------------------------
from pylab import *
from time import sleep

ion() # interactive mode 'on'
figure()
ax = subplot(111, autoscale_on=True)

x, y = [0], [0]
line = plot(x, y, label="my_data")[0]
                                    # get the line-object as the first element
                                    # of the tuple returned by plot
legend()
for i in arange(10):
    x.append(i) # append new values
    y.append(i**2)
    line.set_data(x,y) # reset data
    ax.relim() # reset axes limits
    ax.autoscale_view() # rescale axes
    draw() # redraw current figure
    sleep(0.5) # wait 0.5 seconds

ioff()
show()
--------------------------------------------------------------------------------

I don't know how to make this somehow interactive concerning the data input.
but maybe you save the data to a file and read them every 15 or 20 minutes.

best regards
Matthias

On Tuesday 11 March 2008 19:37, Chris Withers wrote:

Chris Withers wrote:
> Matthias Michler wrote:
>> plot([x1], [y1], "bo", [x2], [y2], "r+")
>
> This didn't work :-S
>
> - the first time I call show(), execution never comes back to my script
> so the code never gets to plot any further points

Okay, thanks to Ryan, I now have this point fixed, however, with the
following code:

ion()
i = 1
while i < 5:
     plot([i],[i],'go',[i],[i+2],'ro')
     print i
     i+=1
     sleep(0.5)
     draw()

- there are no lines between the points, how do I get the lines to show?

see above - please

- how would I pass keyword parameters such as "label" or use other
methods such as plot_date?

Also, when the above script finishes, I get:

Fatal Python error: PyEval_RestoreThread: NULL tstate

This application has requested the Runtime to terminate it in an unusual
way.
Please contact the application's support team for more information.

What does that mean?

Sorry I have no idea why that happens on your system

cheers,

Chris

Matthias Michler wrote:

Hello Chris,

maybe I don't know exactly what you want to do - let me try once more:
You try to plot a line where point need to be added, isn't it?
My first idea was that there should be independent points.

maybe something like the following helps you:
-----------------------------------------------------------------------------------------
from pylab import *
from time import sleep

ion() # interactive mode 'on'
figure()
ax = subplot(111, autoscale_on=True)

x, y = [0], [0]
line = plot(x, y, label="my_data")[0] # get the line-object as the first element # of the tuple returned by plot
legend()
for i in arange(10):
    x.append(i) # append new values
    y.append(i**2)
    line.set_data(x,y) # reset data
    ax.relim() # reset axes limits
    ax.autoscale_view() # rescale axes
    draw() # redraw current figure
    sleep(0.5) # wait 0.5 seconds

ioff()
show()
--------------------------------------------------------------------------------

I don't know how to make this somehow interactive concerning the data input. but maybe you save the data to a file and read them every 15 or 20 minutes.

You could combine this with the stuff in dynamic_demo* and dynamic_image* in the examples directory. Basically, you write some kind of handler that the gui mainloop repeatedly calls, which would handle reading the data and updating the plot like you did above.

Ryan

···

--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma

Hey Matthias,

Matthias Michler wrote:

maybe something like the following helps you:
-----------------------------------------------------------------------------------------
from pylab import *
from time import sleep

ion() # interactive mode 'on'
figure()
ax = subplot(111, autoscale_on=True)

x, y = [0], [0]
line = plot(x, y, label="my_data")[0] # get the line-object as the first element # of the tuple returned by plot
legend()
for i in arange(10):
    x.append(i) # append new values
    y.append(i**2)
    line.set_data(x,y) # reset data
    ax.relim() # reset axes limits
    ax.autoscale_view() # rescale axes
    draw() # redraw current figure
    sleep(0.5) # wait 0.5 seconds

ioff()

This is perfect, except for one little thing...

My x-axis is time, and as new points are plotted, even though I'm following the above recipe pretty closely, the x-tick spacing isn't getting sorted out, so I end up with just a jumble as the tick labels for the x-axis. Do you know why this might be?

I don't know how to make this somehow interactive concerning the data input. but maybe you save the data to a file and read them every 15 or 20 minutes.

This isn't a problem, I just run in a "while True" loop and leave it running until I close the plot window.

Shame I get that horrible exception when I do close the plot window, wish I knew how to make it stop :-S

cheers,

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Hey Chris,

Matthias Michler wrote:
> maybe something like the following helps you:
> -------------------------------------------------------------------------
>---------------- from pylab import *
> from time import sleep
>
> ion() # interactive mode 'on'
> figure()
> ax = subplot(111, autoscale_on=True)
>
> x, y = [0], [0]
> line = plot(x, y, label="my_data")[0]
> # get the line-object as the first
> element # of the tuple returned by plot legend()
> for i in arange(10):
> x.append(i) # append new values
> y.append(i**2)
> line.set_data(x,y) # reset data
> ax.relim() # reset axes limits
> ax.autoscale_view() # rescale axes
> draw() # redraw current figure
> sleep(0.5) # wait 0.5 seconds
>
> ioff()

This is perfect, except for one little thing...

My x-axis is time, and as new points are plotted, even though I'm
following the above recipe pretty closely, the x-tick spacing isn't
getting sorted out, so I end up with just a jumble as the tick labels
for the x-axis. Do you know why this might be?

I'm not sure I understand correctly, but if the number of xticks increases
dramatically (nobody could see the individual ticks), the above script leads
to a different behaviour on my system.

> I don't know how to make this somehow interactive concerning the data
> input. but maybe you save the data to a file and read them every 15 or 20
> minutes.

This isn't a problem, I just run in a "while True" loop and leave it
running until I close the plot window.

Shame I get that horrible exception when I do close the plot window,
wish I knew how to make it stop :-S

I don't know which exception you refer to, but sometimes if gives problems if
the interactive mode wasn't switched off ("ioff()") before the scripts ends
or "show()" is called.

regards
Matthias

···

On Saturday 22 March 2008 03:36, Chris Withers wrote:

Matthias Michler wrote:

My x-axis is time, and as new points are plotted, even though I'm
following the above recipe pretty closely, the x-tick spacing isn't
getting sorted out, so I end up with just a jumble as the tick labels
for the x-axis. Do you know why this might be?

I'm not sure I understand correctly, but if the number of xticks increases dramatically (nobody could see the individual ticks),

Indeed, it looks like the Tick spacing is staying as it was when the first point was plotted, so when hundreds more points are plotted, I just get a jumble of labels on the x-axis.

the above script leads to a different behaviour on my system.

What is that behaviour and what version of matplotlib are you using?

Shame I get that horrible exception when I do close the plot window,
wish I knew how to make it stop :-S

I don't know which exception you refer to, but sometimes if gives problems if the interactive mode wasn't switched off ("ioff()") before the scripts ends or "show()" is called.

If I run the attached script, and hit Ctrl-C in the DOS box running it, I get:

C:\>python mpltest.py
Traceback (most recent call last):
   File "mpltest.py", line 3, in <module>
     show()
   File "C:\Python25\Lib\site-packages\matplotlib\backends\backend_tkagg.py", li
e 76, in show
     Tk.mainloop()
   File "C:\Python25\lib\lib-tk\Tkinter.py", line 328, in mainloop
     _default_root.tk.mainloop(n)
KeyboardInterrupt
Fatal Python error: PyEval_RestoreThread: NULL tstate

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

I've had a similar error when I hit the red cross in the corner of the window with other scripts, although not this one :-S

cheers,

Chris

mpltest.py (45 Bytes)

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Matthias Michler wrote:
>> My x-axis is time, and as new points are plotted, even though I'm
>> following the above recipe pretty closely, the x-tick spacing isn't
>> getting sorted out, so I end up with just a jumble as the tick labels
>> for the x-axis. Do you know why this might be?
>
> I'm not sure I understand correctly, but if the number of xticks
> increases dramatically (nobody could see the individual ticks),

Indeed, it looks like the Tick spacing is staying as it was when the
first point was plotted, so when hundreds more points are plotted, I
just get a jumble of labels on the x-axis.

> the above script leads
> to a different behaviour on my system.

What is that behaviour and what version of matplotlib are you using?

I think it is the expected behaviour. The number of xtick is aproximately
constant and some tick get sorted out, when the xlimits are increasing.
I'm using matplotlib-svn r5024 on Debian etch.

>> Shame I get that horrible exception when I do close the plot window,
>> wish I knew how to make it stop :-S
>
> I don't know which exception you refer to, but sometimes if gives
> problems if the interactive mode wasn't switched off ("ioff()") before
> the scripts ends or "show()" is called.

If I run the attached script, and hit Ctrl-C in the DOS box running it,
I get:

C:\>python mpltest.py
Traceback (most recent call last):
   File "mpltest.py", line 3, in <module>
     show()
   File
"C:\Python25\Lib\site-packages\matplotlib\backends\backend_tkagg.py", li
e 76, in show
     Tk.mainloop()
   File "C:\Python25\lib\lib-tk\Tkinter.py", line 328, in mainloop
     _default_root.tk.mainloop(n)
KeyboardInterrupt
Fatal Python error: PyEval_RestoreThread: NULL tstate

This application has requested the Runtime to terminate it in an unusual
way.
Please contact the application's support team for more information.

I've had a similar error when I hit the red cross in the corner of the
window with other scripts, although not this one :-S

sorry. I have no idea where this problems comes from. I have seen that using
idle and the latest release of matplotlib on and winxp, but I can't reproduce
it on my linux system.

Matthias

···

On Wednesday 26 March 2008 19:39, Chris Withers wrote:

Matthias Michler wrote:

the above script leads
to a different behaviour on my system.

What is that behaviour and what version of matplotlib are you using?

I think it is the expected behaviour. The number of xtick is aproximately constant and some tick get sorted out, when the xlimits are increasing.
I'm using matplotlib-svn r5024 on Debian etch.

Hmm, do you have a code snippet to demonstrate this?
Maybe I'm missing some vital step that causes the axis to re-calculate its ticks?

sorry. I have no idea where this problems comes from. I have seen that using idle and the latest release of matplotlib on and winxp, but I can't reproduce it on my linux system.

*sigh* :wink:

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Hello Chris,

···

On Thursday 27 March 2008 12:22, Chris Withers wrote:

Matthias Michler wrote:
>>> the above script leads
>>> to a different behaviour on my system.
>>
>> What is that behaviour and what version of matplotlib are you using?
>
> I think it is the expected behaviour. The number of xtick is aproximately
> constant and some tick get sorted out, when the xlimits are increasing.
> I'm using matplotlib-svn r5024 on Debian etch.

Hmm, do you have a code snippet to demonstrate this?
Maybe I'm missing some vital step that causes the axis to re-calculate
its ticks?

I'm not sure that I understand you correctly. The code I refering is the one
which I attached some mails ago. The following works for me:
---------------------------------------------------------------------------------
from pylab import *
from time import sleep

ion() # interactive mode 'on'
figure()
ax = subplot(111, autoscale_on=True)

x, y = [0], [0]
line = plot(x, y, label="my_data")[0]
                                    # get the line-object as the first element
                                    # of the tuple returned by plot
legend()
for i in arange(30):
    x.append(i) # append new values
    y.append(i**2)
    line.set_data(x,y) # reset data
    ax.relim() # reset axes limits
    ax.autoscale_view() # rescale axes
    draw() # redraw current figure
    sleep(0.3) # wait 0.3 seconds

ioff()
show()
----------------------------------------------------------------------------------

And your mpltest.py works as well for me.

best regards
Matthias

Matthias Michler wrote:

I'm not sure that I understand you correctly. The code I refering is the one which I attached some mails ago. The following works for me:

Ah, okay, to get the problem I was having, change your script as follows:

---------------------------------------------------------------------------------
from pylab import *

> from datetime import datetime

from time import sleep

ion() # interactive mode 'on'
figure()
ax = subplot(111, autoscale_on=True)

x, y = [datetime.now()], [0]
line = plot(x, y, label="my_data")[0] # get the line-object as the first element # of the tuple returned by plot
legend()
for i in arange(30):
    x.append(datetime.now()) # append new values
    y.append(i**2)
    line.set_data(x,y) # reset data
    ax.relim() # reset axes limits
    ax.autoscale_view() # rescale axes
    draw() # redraw current figure
    sleep(0.3) # wait 0.3 seconds

ioff()
show()

So, basically make the x axis time instead of numbers.
I think the problem is actually that the daets are quite long in their format. If they were rotated through 90 degress it'd likely be fine.
How would I do this?

Also, how would I get this kind of updating with bar charts or errorbars?

cheers,

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Hello Chris,
Hello list,

Matthias Michler wrote:
> I'm not sure that I understand you correctly. The code I refering is the
> one which I attached some mails ago. The following works for me:

Ah, okay, to get the problem I was having, change your script as follows:
> -------------------------------------------------------------------------
>-------- from pylab import *
>
> from datetime import datetime
>
> from time import sleep
>
> ion() # interactive mode 'on'
> figure()
> ax = subplot(111, autoscale_on=True)
>
> x, y = [datetime.now()], [0]
> line = plot(x, y, label="my_data")[0]
> # get the line-object as the first
> element # of the tuple returned by plot legend()
> for i in arange(30):
> x.append(datetime.now()) # append new values
> y.append(i**2)
> line.set_data(x,y) # reset data
> ax.relim() # reset axes limits
> ax.autoscale_view() # rescale axes
> draw() # redraw current figure
> sleep(0.3) # wait 0.3 seconds
>
> ioff()
> show()

So, basically make the x axis time instead of numbers.
I think the problem is actually that the daets are quite long in their
format. If they were rotated through 90 degress it'd likely be fine.
How would I do this?

I'm not sure it is the easiest way, but it works for me:

for label in ax.xaxis.get_majorticklabels():
    label.set_rotation(+90)

Also, how would I get this kind of updating with bar charts or errorbars?

In the case of bar charts and errorbars it is quite difficult to reset the
data.
e.g. errobar (from the docstring)
Return value is a length 3 tuple. The first element is the
    Line2D instance for the y symbol lines. The second element is
    a list of error bar cap lines, the third element is a list of
    line collections for the horizontal and vertical error ranges
I think it is quite expensive to reset all x/ydata of the lines by yourself
and I have no idea how to reset data of line collections.

I would replot the errorbars, but maybe somebody else knows a good way to
reset the data of errorbars.

regards
Matthias

···

On Thursday 27 March 2008 18:26, Chris Withers wrote:

Matthias Michler wrote:

I'm not sure it is the easiest way, but it works for me:

for label in ax.xaxis.get_majorticklabels():
    label.set_rotation(+90)

Yes, that's what I was using, just wondered if there was a better way...

Also, how would I get this kind of updating with bar charts or errorbars?

In the case of bar charts and errorbars it is quite difficult to reset the data.

Oh, I also meant to ask about scatter, can the data be easilly reset there?

For bar charts and errorbar plots, I agree :wink: How would I just blank the figure and replot?
(I have just been calling errorbar lots, but I'm guessing that if I add a legend, I'll have one entry for each time I called errorbar :-S)

cheers,

Chris

···

--
Simplistix - Content Management, Zope & Python Consulting
            - http://www.simplistix.co.uk

Matthias Michler wrote:
> I'm not sure it is the easiest way, but it works for me:
>
> for label in ax.xaxis.get_majorticklabels():
> label.set_rotation(+90)

Yes, that's what I was using, just wondered if there was a better way...

At least I don't know a better way, but I'm not an expert.

>> Also, how would I get this kind of updating with bar charts or
>> errorbars?
>
> In the case of bar charts and errorbars it is quite difficult to reset
> the data.

Oh, I also meant to ask about scatter, can the data be easilly reset there?

Scatter returns a line collection and I don't know if there is a method to
reset their x/ydata.

For bar charts and errorbar plots, I agree :wink: How would I just blank
the figure and replot?

I'm not sure, but maybe clf() to clear the whole figure and cla() to clear the
axes does the job.

(I have just been calling errorbar lots, but I'm guessing that if I add
a legend, I'll have one entry for each time I called errorbar :-S)

regards,
Matthias

···

On Friday 28 March 2008 13:57, Chris Withers wrote:

Chris Withers wrote:

So, basically make the x axis time instead of numbers.
I think the problem is actually that the daets are quite long in their
format. If they were rotated through 90 degress it'd likely be fine.
How would I do this?

I'm not sure it is the easiest way, but it works for me:

for label in ax.xaxis.get_majorticklabels():
    label.set_rotation(+90)

To adjust tick labels when using dates, you could also try Figure.autofmt_xdate (I added it to the example code you were using below). Internally it sets the rotation of the xticklabels as described above, but also sets horizontal alignment of the labels and is especially useful if you have multiple subplots.

-Ryan

from datetime import datetime
from time import sleep

ion() # interactive mode 'on'

fig = figure()

ax = fig.add_subplot(111, autoscale_on=True)

x, y = [datetime.now()], [0]
line = plot(x, y, label="my_data")[0]
# get the line-object as the first element
# of the tuple returned by plot legend()
for i in arange(30):
     x.append(datetime.now()) # append new values
     y.append(i**2)
     line.set_data(x,y) # reset data
     ax.relim() # reset axes limits
     ax.autoscale_view() # rescale axes

     fig.autofmt_xdate() # adjust the xtick labels

     draw() # redraw current figure
     sleep(0.3) # wait 0.3 seconds

ioff()
show()

We do not have good built in support for this kind of thing (though we
should add it). One approach is to write a custom artist, as in this
example. I'm using GTK only for the idle handling callback, but you
can use whatever approach works for you. The important part is the
example showing how to write a custom artist for dynamic data:

import gtk
import numpy as np

import matplotlib
matplotlib.use('GTKAgg')
import matplotlib.pyplot as plt
import matplotlib.artist as artist
import matplotlib.colors as colors
import matplotlib.agg as agg

class DynamicMarkers(artist.Artist):
    def __init__(self, buffersize=30):
        artist.Artist.__init__(self)
        self.buffersize = buffersize
        self.x = []
        self.y = []
        self.count = 0
        self.path = None
        self.markersize = 10.
        self.facecolor = colors.colorConverter.to_rgb('blue')
        self.edgecolor = colors.colorConverter.to_rgb('black')

    def add(self, x, y):
        self.count+=1
        self.x.append(x)
        self.y.append(y)
        if self.count>self.buffersize:
            del self.x[0]
            del self.y[0]

    def draw(self, renderer):
        if self.axes is None:
            raise RuntimeError('you must first add me to the axes')

        if self.path is None:
            # use square markers
            side = renderer.points_to_pixels(self.markersize)
            offset = side*0.5

            path = agg.path_storage()
            path.move_to(-offset, -offset)
            path.line_to(-offset, offset)
            path.line_to(offset, offset)
            path.line_to(offset, -offset)
            path.end_poly()
            self.path = path

        gc = renderer.new_gc()
        self._set_gc_clip(gc) # Artist method
        gc.set_foreground(self.edgecolor)

        renderer.draw_markers(gc, self.path, self.facecolor, self.x,
self.y, self.get_transform())

fig = plt.figure()
ax = fig.add_subplot(111)
myline = DynamicMarkers(30)
ax.add_artist(myline)
ax.set_xlim(-20, 1)

ax.set_ylim(0,1)

def animate(*args):

    i = animate.i
    print 'animate', i
    myline.add(i, np.random.rand())
    ax.set_xlim(i-30, i+1)
    fig.canvas.draw()
    animate.i += 1

    if animate.i<200: return True
    else: return False

gtk.idle_add(animate)
animate.i = 0

plt.show()

···

On Fri, Mar 28, 2008 at 8:20 AM, Matthias Michler <MatthiasMichler@...361...> wrote:

On Friday 28 March 2008 13:57, Chris Withers wrote:
> Matthias Michler wrote:
> > I'm not sure it is the easiest way, but it works for me:
> >
> > for label in ax.xaxis.get_majorticklabels():
> > label.set_rotation(+90)
>
> Yes, that's what I was using, just wondered if there was a better way...

At least I don't know a better way, but I'm not an expert.

> >> Also, how would I get this kind of updating with bar charts or
> >> errorbars?
> >
> > In the case of bar charts and errorbars it is quite difficult to reset
> > the data.
>
> Oh, I also meant to ask about scatter, can the data be easilly reset there?

Scatter returns a line collection and I don't know if there is a method to
reset their x/ydata.