How do I modify my matplotlib FuncAnimation init_func to remove artifacts that were introduced by using twinx? - animation

Summary: I created a script for drawing strip charts with the matplotlib animation framework to support multiple y-axes using the Axes.twinx(), which resulted in an artifact on the plot which I can't remove. I think I need to modify the animation init_func to account for the multiple axes.
Python 2.7, matplotlib 2.0.2 with the Qt backend, and conda 4.3.18, running on Ubuntu Linux 17.04.
Full Description: I created strip chart drawing program based on the matplotlib strip chart demo:
https://matplotlib.org/examples/animation/strip_chart_demo.html
I modified it to help some EE's on a project including rewriting it in a more procedural style so they were more comfortable working with it (not sure how successful that was, we're still talking about it), adding support for multiple lines, and changed it so it was continuously scrolling left.
The script includes a makeChart() function that creates a series of Line2D's in a loop, and adds them to a list, and returns them to the caller:
lines = []
for iline in range(0,linesPerPlot):
lines.append(makeLine(ax, maxt, dt, ymin, ymax, colors[iline % len(colors)]))
return lines
When I added multiple lines there was an artifact that appeared when running with blit=True that I got rid of by adding an init_function.
The init function is simple and looks like this:
def initDisplay(lines):
"""Init display."""
return lines
When the script executes makeChart() is called and returns a list of Line2D's that are being plotted, it creates a lambda that wraps the init function that is then passed to FuncAnimation:
lines = makeChart(ax, secondsPerPlot, secondsPerSample, linesPerPlot, ymin, ymax)
...
init = lambda: initDisplay(lines)
ani = animation.FuncAnimation(fig, update, emitter, init_func=init, interval=millisPerFrame, blit=True)
The result works reasonable well:
And an example with that displays some generated sin waves is here:
https://gist.github.com/mdkrajnak/f7cfd3f720453d53da4a80fa45df3b66
Later I made an additional modification so that each line had an independent y-axis by using Axes.twinx. After the modification there's now an artifact that I cannot remove that appears to be left over from the first time the first line is rendered.
The new inner loop in makeChart() looks like:
lines = []
lines.append(makeLine(ax, maxt, dt, ymin, ymax, colors[0]))
for iline in range(1,linesPerPlot):
twin_ax = ax.twinx()
lines.append(makeLine(twin_ax, maxt, dt, ymin, ymax, colors[iline % len(colors)]))
return lines
And the full code is here:
https://gist.github.com/mdkrajnak/e8b37300545f3ffea651d628933bd0ee
I tried modifying the init function so that it returned a list with both the lines and axes:
def initDisplay(lines, axs):
"""Init display."""
return lines + axs
And the makeChart() function so it returned the axes along with the lines in the sequence of artists that it returned:
lines = []
axs = []
# Add first line, then add subsequent lines sharing the x-axis.
lines.append(makeLine(ax, maxt, dt, ymin, ymax, colors[0]))
axs.append(ax)
for iline in range(1,linesPerPlot):
twin_ax = ax.twinx()
lines.append(makeLine(twin_ax, maxt, dt, ymin, ymax, colors[iline % len(colors)]))
axs.append(twin_ax)
return lines, axs
The full code is here:
https://gist.github.com/mdkrajnak/e6eaca509cd8321b9b56a4d25c3e1e80
But this version fails with "AttributeError: draw_artist can only be used after an initial draw which caches the render"
File "/home/mdk/opt/miniconda3/envs/p2/lib/python2.7/site-packages/matplotlib/animation.py", line 1123, in _post_draw self._blit_draw(self._drawn_artists, self._blit_cache)
File "/home/mdk/opt/miniconda3/envs/p2/lib/python2.7/site-packages/matplotlib/animation.py", line 1138, in _blit_draw a.axes.draw_artist(a)
File "/home/mdk/opt/miniconda3/envs/p2/lib/python2.7/site-packages/matplotlib/axes/_base.py", line 2441, in draw_artist raise AttributeError(msg)
AttributeError: draw_artist can only be used after an initial draw which caches the render
My thinking is still that the init function needs to return the axes along with the lines, but I need to somehow cause an initial draw of the axes before the init function is called. Is there something I can to to prerender the axes, or is there something else I need to do?

It seems that blitting is performed per axes. So it might be that the procedure is
for ax in all axes:
get axes background
draw line
This means that the first line is part of the background from the second axes and as such will be part of every successive frame.
The only solution I can think of at the moment is to make the lines invisible until the backgrounds of all axes have been stored for blitting.
line = Line2D(tdata, ydata, color=color, visible=False)
Only after the first call to updateLines turn them visible again.
n = [0]
def updateLines(lines, arrays):
"""Update individual lines and return a sequence of artists to the animator."""
artists = []
for iline in range(len(lines)):
artists.append(updateLine(lines[iline], arrays[iline]))
if n[0] > 0:
lines[iline].set_visible(True)
n[0] += 1
return artists
Complete code:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.lines import Line2D
import math
# Initalize script constants
ymin = -1.1
ymax = 1.1
linesPerPlot = 3
samplesPerFrame = 1
framesPerSecond = 20
secondsPerPlot = 5
# Calculate dependent constants
samplesPerSecond = samplesPerFrame * framesPerSecond
samplesPerPlot = samplesPerSecond * secondsPerPlot
secondsPerSample = 1.0/samplesPerSecond
millisPerFrame = 1000.0/framesPerSecond
# Define core functions
def makeLine(ax, maxt, dt, ymin, ymax, color):
"""Make an empty Line2D for the initial chart."""
nvalues = int(round(maxt/dt))
tdata = [dt*tm for tm in range(nvalues)]
ydata = [0 for tm in range(nvalues)]
line = Line2D(tdata, ydata, color=color, visible=False) ### <- visible false
ax.add_line(line)
ax.set_ylim(ymin, ymax)
return line
def makeChart(ax, maxt, dt, linesPerPlot, ymin, ymax):
"""Make a chart and return a list of the lines it contains."""
colors = [ 'r', 'b', 'g', 'k' ]
lines = []
# Add first line, then add subsequent lines sharing the x-axis.
lines.append(makeLine(ax, maxt, dt, ymin, ymax, colors[0]))
for iline in range(1,linesPerPlot):
twin_ax = ax.twinx()
lines.append(makeLine(twin_ax, maxt, dt, ymin, ymax, colors[iline % len(colors)]))
ax.set_xlim(0, maxt)
return lines
def initDisplay(lines):
"""Init display."""
return lines
def updateLine(line, ys):
"""Update the data in one line, popping off the last value."""
tdata, ydata = line.get_data()
for y in ys:
ydata.append(y)
ydata.pop(0)
line.set_data(tdata, ydata)
return line
n = [0]
def updateLines(lines, arrays):
"""Update individual lines and return a sequence of artists to the animator."""
artists = []
for iline in range(len(lines)):
artists.append(updateLine(lines[iline], arrays[iline]))
if n[0] > 0:
lines[iline].set_visible(True)
n[0] += 1
return artists
def emitData(linesPerPlot, samplesPerFrame):
"""Create the data that will be plotted."""
nsample = 0
while True:
samples = [[] for i in range(linesPerPlot)]
for isample in range(samplesPerFrame):
nsample = nsample + 1
for iline in range(linesPerPlot):
pi_increment = (math.pi/(10.0 * (iline+1)))
samples[iline].append(math.sin(nsample * pi_increment))
yield samples
# Make chart.
fig, ax = plt.subplots()
lines = makeChart(ax, secondsPerPlot, secondsPerSample, linesPerPlot, ymin, ymax)
# Start the animator.
update = lambda samples: updateLines(lines, samples)
emitter = lambda: emitData(linesPerPlot, samplesPerFrame)
init = lambda: initDisplay(lines)
ani = animation.FuncAnimation(fig, update, emitter, init_func=init, interval=millisPerFrame, blit=True)
plt.show()

Related

Visualzing the solution of a differential equation with an animation in Julia

I have solved a system of two second-order differential equations using an implementation of Euler's method in Julia. The below code shows how Euler's method has been called to solve the system in question.
θ1 = 1.1900518004210798; θ2 = 0.3807445263738167
f(t, y) = [y[2], -2(y[1] - θ1) - 4y[2] + 0.5sin(3pi*t),
y[4], -2(y[3] - θ2) - 4(y[4] + abs(y[2])) + 0.5sin(3pi*t)]
y0 = [pi/2, 0, pi/6, 0]; t0 = 0; tFinal = 50; h = 0.001
res = euler(f, y0, t0, tFinal, h)
The result, res, is a vector of four numbers
1.18798735437173
-0.0458294959470722
0.31530569612003573
-0.049213402534541074
The first entry is the angle that the bottom line segment forms with the x-axis while the third entry is the angle that the two line segments form with one another (see below figure).
To create this plot I called plot_robotarm([res[1], res[3]]) which is implemented according to the below code.
function plot_robotarm(thetav)
# Plots a robotarm with angles thetav
R = 1;
xv=zeros(length(thetav)+1)
yv=zeros(length(thetav)+1)
for i in 1:length(thetav)
xv[i+1]=xv[i]+R*cos(thetav[i])
yv[i+1]=yv[i]+R*sin(thetav[i])
end
# Plot with colors
opts = (:circle, 10, 1., :blue, stroke(7, 1., :red))
plt = plot(xv, yv,
marker = opts,
c = :red,
w = 5,
legend = false,
xlims = (0, 2.0),
ylims = (0, 2.0))
display(plt)
end
How can I create an animation that visualizes how consecutive iterations of Euler's method make the robot arm (i.e. the two line segments) move toward the final point at t = 50? (I do not need to plot every iteration, just enough so that it makes for an animation that captures the movement of the robot arm.)
You can use ffmpeg and Luxor.jl's animation features to make an animated GIF. The frame function needs to be modified to reflect graphical display of each step in your program. See the docs for Luxor for more.
using Luxor
using Colors
using BoundaryValueDiffEq
# constants for differential equations and movie
const g = 9.81
const L = 1.0 # pendulum length in meters
const bobd = 0.10 # pendulum bob diameter in meters
const framerate = 50.0 # intended frame rate/sec
const t0 = 0.0 # start time (s)
const tf = 2.3 # end simulation time (s)
const dtframe = 1.0/framerate # time increment per frame
const tspan = LinRange(t0, tf, Int(floor(tf*framerate))) # array of time points in animation
const bgcolor = "black" # gif background
const leaderhue = (0.80, 0.70, 0.20) # gif swing arm hue light gold
const hslcolors = [HSL(col) for col in (distinguishable_colors(
Int(floor(tf*framerate)+3),[RGB(1,1,1)])[2:end])]
const giffilename = "pendulum.gif" # output file
# differential equations copied from docs of DifferentialEquations.jl
simplependulum!(du, u, p, t) = (θ=u[1]; dθ=u[2]; du[1]=dθ; du[2]=-(g/L)*sin(θ))
bc1!(residual, u, p, t) = (residual[1] = u[div(end,2)][1] + pi/2; residual[2] = u[end][1] - pi/2)
bvp1 = TwoPointBVProblem(simplependulum!, bc1!, [pi/2,pi/2], (tspan[1],tspan[end]))
sol2 = solve(bvp1, GeneralMIRK4(), dt=dtframe)
# movie making background
backdrop(scene, framenumber) = background(bgcolor)
function frame(scene, framenumber)
u1, u2 = sol2.u[framenumber]
y, x = L*cos(u1), L*sin(u1)
sethue(leaderhue)
poly([Point(-4.0, 0.0), Point(4.0, 0.0),
Point(160.0x,160.0y)], :fill)
sethue(Colors.HSV(framenumber*4.0, 1, 1))
circle(Point(160.0x,160.0y), 160bobd, :fill)
text(string("frame $framenumber of $(scene.framerange.stop)"),
Point(0.0, -190.0),
halign=:center)
end
muv = Movie(400, 400, "Pendulum Demo", 1:length(tspan))
animate(muv, [Scene(muv, backdrop),
Scene(muv, frame, easingfunction=easeinoutcubic)],
creategif=true, pathname=giffilename)

Pygal: Change dot type/ symbol

I want to change the dots in my pygal chart from the default circles to rectangles (sounds weird but makes sense in my case) and be able to define the size of the rectangles. I couldn't find a solution in the docs. With the config module I can show/ hide the dots and change the dots size but as far as I can see I can't change the dot icon. I also coulndn't find a solution in the style module.
Is there an easy way to do it?
Thanks a lot
There's no way to achieve this using styles or configuration: the circular dots are hard-coded into the function that renders line charts. But, you can easily extend the line chart class and override this function to create a chart with any shape of dot.
If you view the source code of the Line class you will see the following code in the line function:
alter(
self.svg.transposable_node(
dots,
'circle',
cx=x,
cy=y,
r=serie.dots_size,
class_='dot reactive tooltip-trigger'
), metadata
)
This creates a circle for each dot and adds it to the SVG data that will be used to generate the chart.
Copy the whole function into your new class and replace those lines with the following code. This will add squares instead of circles, using the dots_size configuration to determine the width and height:
alter(
self.svg.transposable_node(
dots,
'rect',
x=x - serie.dots_size / 2,
y=y - serie.dots_size / 2,
width=serie.dots_size,
height=serie.dots_size,
class_='dot reactive tooltip-trigger'
), metadata
)
The complete class would look something like this (it looks like a lot of code, but most of it is copy-pasted):
from pygal.util import alter, decorate
class SquareDots(pygal.Line):
def __init__(self, *args, **kwargs):
super(SquareDots, self).__init__(*args, **kwargs)
def line(self, serie, rescale=False):
serie_node = self.svg.serie(serie)
if rescale and self.secondary_series:
points = self._rescale(serie.points)
else:
points = serie.points
view_values = list(map(self.view, points))
if serie.show_dots:
for i, (x, y) in enumerate(view_values):
if None in (x, y):
continue
if self.logarithmic:
if points[i][1] is None or points[i][1] <= 0:
continue
if (serie.show_only_major_dots and self.x_labels
and i < len(self.x_labels)
and self.x_labels[i] not in self._x_labels_major):
continue
metadata = serie.metadata.get(i)
classes = []
if x > self.view.width / 2:
classes.append('left')
if y > self.view.height / 2:
classes.append('top')
classes = ' '.join(classes)
self._confidence_interval(
serie_node['overlay'], x, y, serie.values[i], metadata
)
dots = decorate(
self.svg,
self.svg.node(serie_node['overlay'], class_="dots"),
metadata
)
val = self._format(serie, i)
# This is the part that needs to be changed.
alter(self.svg.transposable_node(
dots,
'rect',
x=x - serie.dots_size / 2,
y=y - serie.dots_size / 2,
width=serie.dots_size,
height=serie.dots_size,
class_='dot reactive tooltip-trigger'
), metadata
)
self._tooltip_data(
dots, val, x, y, xlabel=self._get_x_label(i)
)
self._static_value(
serie_node, val, x + self.style.value_font_size,
y + self.style.value_font_size, metadata
)
if serie.stroke:
if self.interpolate:
points = serie.interpolated
if rescale and self.secondary_series:
points = self._rescale(points)
view_values = list(map(self.view, points))
if serie.fill:
view_values = self._fill(view_values)
if serie.allow_interruptions:
sequences = []
cur_sequence = []
for x, y in view_values:
if y is None and len(cur_sequence) > 0:
sequences.append(cur_sequence)
cur_sequence = []
elif y is None:
continue
else:
cur_sequence.append((x, y))
if len(cur_sequence) > 0:
sequences.append(cur_sequence)
else:
sequences = [view_values]
if self.logarithmic:
for seq in sequences:
for ele in seq[::-1]:
y = points[seq.index(ele)][1]
if y is None or y <= 0:
del seq[seq.index(ele)]
for seq in sequences:
self.svg.line(
serie_node['plot'],
seq,
close=self._self_close,
class_='line reactive' +
(' nofill' if not serie.fill else '')
)
Your new class can then be used like any other pygal chart.
chart = SquareDots(dots_size=50)
chart.add("line", [1, 2, 3, 4, 3, 2])
chart.render_to_png("chart.png")

Matplotlib animate space vs time plot

I'm currently working on traffic jams analysis and was wondering if there's a way to animate the generation of a plot of such jams.
A plot of this things grow from up to the lower end of the figure, each 'row' is a time instance. The horizontal axis is just the road indicating at each point the position of each vehicle and, with a certain numeric value, the velocity of it. So applying different colors to different velocities, you get a plot that shows how a jam evolves through time in a given road.
My question is, how can I use matplotlib to generate an animation of each instance of the road in time to get such a plot?
The plot is something like this:
I'm simulating a road with vehicles with certain velocities through time, so I wish to animate a plot showing how the traffic jams evolve...
EDIT:
I add some code to make clear what I'm already doing
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation, rc
plt.rcParams['animation.ffmpeg_path'] = u'/usr/bin/ffmpeg'
# model params
vmax = 5
lenroad = 50
prob = 0.4
# sim params
numiters = 10
# traffic model
def nasch():
gaps = np.full(road.shape, -1)
road_r4 = np.full(road.shape, -1)
for n,x in enumerate(road):
if x > -1:
d = 1
while road[(n+d) % len(road)] < 0:
d += 1
d -= 1
gaps[n] = d
road_r1 = np.where(road!=-1, np.minimum(road+1, vmax), -1)
road_r2 = np.where(road_r1!=-1, np.minimum(road_r1, gaps), -1)
road_r3 = np.where(road_r2!=-1, np.where(np.random.rand() < prob, np.maximum(road-1, 0), road), -1)
for n,x in enumerate(road_r3):
if x > -1:
road_r4[(n+x) % len(road_r3)] = x
return road_r4
def plot_nasch(*args):
road = nasch()
plot.set_array([road])
return plot,
# init road
road = np.random.randint(-10, vmax+1, [lenroad])
road = np.where(road>-1, road, -1)
# simulate
fig = plt.figure()
plot = plt.imshow([road], cmap='Pastel2', interpolation='nearest')
for i in range(numiters):
ani = animation.FuncAnimation(fig, plot_nasch, frames=100, interval=500, blit=True)
plt.show()
And I get the following figure, just one road instead of each road painted at the bottom of the previous one:
This is possibly what you want, although I'm not sure why you want to animate the time, since time is already one of the axes in the plot.
The idea here is to store the simulation results of a time-step row by row in an array and replot this array. Thereby previous simulation results are not lost.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation, rc
# model params
vmax = 5
lenroad = 50
prob = 0.4
# sim params
numiters = 25
# traffic model
def nasch():
global road
gaps = np.full(road.shape, -1)
road_r4 = np.full(road.shape, -1)
for n,x in enumerate(road):
if x > -1:
d = 1
while road[(n+d) % len(road)] < 0:
d += 1
d -= 1
gaps[n] = d
road_r1 = np.where(road!=-1, np.minimum(road+1, vmax), -1)
road_r2 = np.where(road_r1!=-1, np.minimum(road_r1, gaps), -1)
road_r3 = np.where(road_r2!=-1, np.where(np.random.rand() < prob, np.maximum(road-1, 0), road), -1)
for n,x in enumerate(road_r3):
if x > -1:
road_r4[(n+x) % len(road_r3)] = x
return road_r4
def plot_nasch(i):
print i
global road
road = nasch()
#store result in array
road_over_time[i+1,:] = road
# plot complete array
plot.set_array(road_over_time)
# init road
road = np.random.randint(-10, vmax+1, [lenroad])
road = np.where(road>-1, road, -1)
# initiate array
road_over_time = np.zeros((numiters+1, lenroad))*np.nan
road_over_time[0,:] = road
fig = plt.figure()
plot = plt.imshow(road_over_time, cmap='Pastel2', interpolation='nearest', vmin=-1.5, vmax=6.5)
plt.colorbar()
ani = animation.FuncAnimation(fig, plot_nasch, frames=numiters, init_func=lambda : 1, interval=400, blit=False, repeat=False)
plt.show()

Matplotlib Animation: updating radial view limit for polar plot

I'm trying to create an animated polar plot that, where the radial view limit increases/decreases to accommodate the radius. The yaxis updates just fine if I set polar=False, but it doesn't work correctly for a polar axis.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def data_gen():
t = data_gen.t
cnt = 0
while cnt < 1000:
cnt+=1
t += 0.05
yield t, 1.1 + np.sin(2*np.pi*t) * np.exp(t/10.)
data_gen.t = 0
plt.rc ('grid', color='g', lw=1, ls='-')
plt.rc ('xtick', labelsize=15, color='b')
plt.rc ('ytick', labelsize=15, color='b')
fig = plt.figure(figsize=(8,8))
ax1 = fig.add_axes([.05, .90, .9, .08], polar=False, axisbg='#BFBFBF', xticks=[], yticks=[])
ax2 = fig.add_axes([.05, .05, .9, .8], polar=True, axisbg='k')
#ax = fig.add_axes([.1,.1,.8,.8], polar=False, axisbg='k')
line, = ax2.plot([], [], lw=2)
ax2.set_ylim(0, 2.2)
ax2.set_xlim(0, 140)
ax2.grid(1)
xdata, ydata = [], []
title = ax1.text (0.02, 0.5, '', fontsize=14, transform=ax1.transAxes)
def init():
line.set_data([], [])
title.set_text ('')
return line, title
def run(data):
# update the data
t,y = data
xdata.append(t)
ydata.append(y)
ymin, ymax = ax2.get_ylim()
if y >= ymax:
ax2.set_ylim (ymin, 2*ymax)
ax2.figure.canvas.draw()
title.set_text ("time = %.3f, y(t) = 1.1 + sin(2*pi*t) + exp(t/10) = %.3f" % (t, y))
line.set_data(xdata, ydata)
return line, title
ani = animation.FuncAnimation(fig, run, data_gen, init, blit=True, interval=100, repeat=False)
Actually, the view limit does adjust, but the tick labels stay the same. Inserting raw_input() after the canvas is redrawn reveals that everything is redrawn correctly, but then the tick labels revert back to what they were before. Stranger still, this doesn't occur until the update() function is called a second time and returns.
I didn't have this problem when I animated the plot the old way, by calling draw() repeatedly. But I'd rather do it the right way with the animation module, as the old way had performance problems (The above code block is only to demonstrate the problem, and isn't the actual program that I'm writing).
I should note that I'm still learning MPL, so I apologize if some of my terminology is wrong.
If you use blit, the background is saved in cache for fast draw, you can clear the cache when the axis range is changed, add ani._blit_cache.clear():
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def data_gen():
t = data_gen.t
cnt = 0
while cnt < 1000:
cnt+=1
t += 0.05
yield t, 1.1 + np.sin(2*np.pi*t) * np.exp(t/10.)
data_gen.t = 0
plt.rc ('grid', color='g', lw=1, ls='-')
plt.rc ('xtick', labelsize=15, color='b')
plt.rc ('ytick', labelsize=15, color='b')
fig = plt.figure(figsize=(8,8))
ax1 = fig.add_axes([.05, .90, .9, .08], polar=False, axisbg='#BFBFBF', xticks=[], yticks=[])
ax2 = fig.add_axes([.05, .05, .9, .8], polar=True, axisbg='k')
#ax = fig.add_axes([.1,.1,.8,.8], polar=False, axisbg='k')
line, = ax2.plot([], [], lw=2)
ax2.set_ylim(0, 2.2)
ax2.set_xlim(0, 140)
ax2.grid(1)
xdata, ydata = [], []
title = ax1.text (0.02, 0.5, '', fontsize=14, transform=ax1.transAxes)
def init():
line.set_data([], [])
title.set_text ('')
return line, title
def run(data):
# update the data
t,y = data
xdata.append(t)
ydata.append(y)
ymin, ymax = ax2.get_ylim()
if y >= ymax:
ax2.set_ylim (ymin, 2*ymax)
ani._blit_cache.clear() # <- add to clear background from blit cache
title.set_text('') # <- eliminate text artifact in title
ax2.figure.canvas.draw()
title.set_text ("time = %.3f, y(t) = 1.1 + sin(2*pi*t) + exp(t/10) = %.3f" % (t, y))
line.set_data(xdata, ydata)
return line, title
ani = animation.FuncAnimation(fig, run, data_gen, init, blit=True, interval=100, repeat=False)

how to get a live updating graph line

i'm trying to create a program which reads some randomly generated data, the xax and yax lists, as plots them live as it reads it in an animated fashion. Here is the code:
from matplotlib.pylab import *
import time, random
ion()
xax = []
yax = []
axes
for j in range (0,20):
xax.append(j)
r = random.randrange(0, 20)
yax.append(r)
maxx = max(xax)
maxy = max(yax)
print maxx, maxy
axis([0,maxx,0,maxy])
line, = plot(xax[0],yax[0])
draw()
for i in xax:
print i, yax[i]
line.set_ydata(yax[i])
draw()
Following the discussion in the comments to the question and in chat, try the following to update a line, extending it for each iteration of a loop. The problem in the original code was that only one point at a time was being draw, so obviously no line was drawn to screen. In the following I extend the x and y data at each iteration of the loop using numpy.append (part of matplotlib.pylab).
from matplotlib.pylab import *
import time, random
ion()
xax = range(0, 20)
yax = [random.randrange(0, 20) for _ range(0, 20)]
axes()
xlim(xmax=max(xax))
ylim(ymax=max(yax))
line, = plot(xax[0], yax[0])
for i, x in enumerate(xax):
line.set_ydata(append(line.get_ydata(), yax[i]))
line.set_xdata(append(line.get_xdata(), x))
draw()
time.sleep(1.)

Resources