views:

1128

answers:

2

So I'm representing a token ring network (doing the simulation in SimPy), I'm a totally newbie to matplotlib, but I was told that it'd be really good for representing my simulation visually.

So I googled around and found out how to draw shapes and lines - using add_patch and add_line respectively to the axes (I believe). So now I have this output which is absolutely fine:

(can't post images yet!!) http://img137.imageshack.us/img137/7822/screenshot20100121at120.png

But I'm getting this using the pylab.show() function, and what I think I want is to achieve this using the pylab.plot() function so that I can then update it as my simulation progresses using pylab.draw() afterward.

My code is as follows:

plab.ion()

plab.axes()

for circ in self.circleList:
    plab.gca().add_patch(circ)

for line in self.lineList:
    plab.gca().add_line(line)

plab.axis('scaled')
plab.show()

Where circleList and lineList are lists containing the circles and lines on the diagram

I'm probably misunderstanding something simple here, but I can't actually find any examples that aren't overtly graph based that use the plot() function.


Clarification:

How can I get that same output, using pylab.plot() instead of pylab.show() ?

+2  A: 

The core technique is to update the data of the elements being rendered using set_data. Then call draw(). See if your circle and line elements have set_data functions. Otherwise you can use pyvtk. The other option is to render and save the plots to png files and later build an animation from those.

whatnick
To add to this answer, I recently did something like this: I saved all my plots and later built a 'movie' out of it, using 'mencoder'
Amit
I know that there is a way of doing it 'on the fly': by turning interactive mode on you can call the pylab.draw() method which will redraw the plot each time.I've got a way of altering the data etc. already (I just change the colour of one of my circles)I just want to know, how do I SHOW the circles and lines in a plot using pylab.plot(), I don't know the syntax for pylab.plot() that lets you just draw a standard plot with some shapes, and no graph or anything.
Duncan Tait
+3  A: 

Replicating your image using the plot method:

from pylab import *

points = []
points.append((-0.25, -1.0))
points.append((0.7, -0.7))
points.append((1,0))
points.append((0.7,1))
points.append((-0.25,1.2))
points.append((-1,0.5))
points.append((-1,-0.5))
points.append((-0.25, -1.0))

a_line = plot(*zip(*points))[0]
a_line.set_color('g')
a_line.set_marker('o')
a_line.set_markerfacecolor('b')
a_line.set_markersize(30)
axis([-1.5,1.5,-1.5,1.5])

show()

EDIT BASED ON COMMENTS

This uses python multiprocessing library to run the matplotlib animation in a separate process. The main process uses a queue to pass data to it which then updates the plot image.

# general imports
import random, time
from multiprocessing import Process, Queue

# for matplotlib
import random
import numpy as np
import matplotlib
matplotlib.use('GTKAgg') # do this before importing pylab

import matplotlib.pyplot as plt
from matplotlib.patches import Circle


def matplotLibAnimate(q,points):

    # set up initial plot
    fig = plt.figure()
    ax = fig.add_subplot(111)


    circles = []
    for point in points:
        ax.add_patch(Circle(point,0.1))

    a_line, = ax.plot(*zip(*points))
    a_line.set_color('g')
    a_line.set_lw(2)

    currentNode = None  
    def animate(currentNode = currentNode):
        while 1:
            newNode = q.get()
            if currentNode: currentNode.remove()
            circle = Circle(newNode,0.1)
            currentNode = ax.add_patch(circle)
            circle.set_fc('r')
            fig.canvas.draw()

    # start the animation
    import gobject
    gobject.idle_add(animate)
    plt.show()

#initial points
points = ((-0.25, -1.0),(0.7, -0.7),(1,0),(0.7,1),(-0.25,1.2),(-1,0.5),(-1,-0.5),(-0.25, -1.0))
q = Queue()
p = Process(target = matplotLibAnimate, args=(q,points,))
p.start()

# feed animation data
while 1:
    time.sleep(random.randrange(4))
    q.put(random.sample(points,1)[0])

Of course, after doing this I think you'll be better served with whatnick's image solution. I'd create my own GUI and not use matplotlibs built in widget. I'd then "animate" my GUI by generating PNGs and swapping them.

Mark
Mark, thanks for all your help. To clarify- what I need this for is to change the colour of the circles as a token moves around them (ie the one with the token might be red and the others green) this is being driven by a simulation library, running in real time. I know you can redraw plots on the fly using the pylab.draw() method when interactive mode is on (pylab.ion) but you can't redraw a figure produced using pylab.show(), only one produced by pylab.plot() (I think!!) so I need a way of changing the circle's colours individually before redrawing. Hope that makes more sense! Thanks
Duncan Tait
@Duncan, pylab.draw() blocks the rest of the application, to animate with it you pass a callback function. How the function is passed depends on your backend. For example with the the default GTK, you call gobject.idle_add(animate); plt.show(). I think your main problem is how to keep a simulation running (in a seperate proccess or thread) and update the GTK window at the same time. I'll try and work out an example.
Mark
@Duncan, see edits to my answer.
Mark