Matplotlib plotting performance

I've been trying to profile and speed up an app that uses matplotlib.
I tried to write an example using simple pylab commands to reproduce
the slowness. What I found was I could get a huge speedup just
avoiding unnecessary redraws. I'm down now to passable behavior.
Plotting 6 series in two windows takes about one and a quarter
seconds. I would like to improve this further, however, if it is
possible which is why I am posting.

The results with show() in between plots are:

In [5]: run u:/tdennist/test2.py
10.128132637

In [6]: run u:/tdennist/test2.py
10.3122053602

And without the superfluous draws:

In [7]: run u:/tdennist/test2.py
1.83904865901

In [8]: run u:/tdennist/test2.py
1.86751011294

In [9]: run u:/tdennist/test2.py
1.84959890227

Where 1.85 seconds is the time to do 2 iteractions of drawing 2 plots
with 3 lines each. So about 0.9 to 1.0 sec to draw the plots once.

Is there anything obvious I can do to speed this up? I looked a
profile results of this and found most of the time is spent in "draw"
functions. I attached the profile results in kcachegrind format for
the faster method.

Under the animation section there is a suggestion that things are
faster if you pre allocate the line and then just update it's x or y
data. Given the profile results, however, I don't think this would
help much and it would be kinda inconvenient for my app because I
don't know how many series I am gonna plot up front.

Also at the very bottom is the contents of my rc params. I am using
WxAgg on windows with matplotlib 0.90.1 and python 2.5.

Code

plot.kcachegrind (203 KB)

···

-------

import timeit

setup='''
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.widgets import Cursor
import pylab, numpy
pylab.clf()
#pylab.show()
'''
code='''
fig = pylab.gcf()
p1 = fig.add_axes([0.075, 0.05, 0.8, .4], axisbg='#333333')
cursor = Cursor(p1, useblit=True, color='green', linewidth=2.5 )
p2 = fig.add_axes([0.075, 0.55, 0.8, .4], axisbg='#333333')
def test(n):
    for i in range(3):
        p1.plot(numpy.random.rand(n))
        #pylab.show()

    for i in range(3):
        p2.plot(numpy.random.rand(n))
        #pylab.show()

test(1000)
pylab.show()
'''

print timeit.Timer(code, setup=setup).timeit(2)

rc Params
----------------

figure.subplot.right 0.9
mathtext.cal cmsy10.ttf
font.fantasy fantasy
xtick.minor.pad 3
tk.pythoninspect False
legend.labelsep 0.005
image.aspect equal
font.cursive cursive
figure.subplot.hspace 0.2
xtick.direction in
axes.facecolor w
ytick.direction in
legend.pad 0.2
axes.axisbelow False
lines.markersize 6
figure.dpi 80
text.usetex False
text.fontangle normal
patch.edgecolor k
ps.useafm False
lines.solid_joinstyle miter
font.monospace monospace
xtick.minor.size 2
figure.subplot.wspace 0.2
savefig.edgecolor w
text.fontvariant normal
image.cmap jet
axes.edgecolor k
tk.window_focus False
text.fontsize medium
font.serif serif
savefig.facecolor w
ytick.minor.size 2
mathtext.mathtext2 False
numerix numpy
font.stretch normal
text.dvipnghack False
ytick.color k
lines.linestyle -
xtick.color k
xtick.major.pad 3
text.fontweight normal
patch.facecolor b
figure.figsize (8, 6)
axes.linewidth 1.0
lines.linewidth 0.5
savefig.dpi 150
verbose.fileo sys.stdout
svg.image_noscale False
font.size 12.0
lines.antialiased True
polaraxes.grid True
toolbar toolbar2
pdf.compression 6
grid.linewidth 0.5
figure.facecolor 0.75
ps.usedistiller False
legend.isaxes True
figure.edgecolor w
mathtext.tt cmtt10.ttf
contour.negative_linestyle (6.0, 6.0)
image.interpolation bilinear
lines.markeredgewidth 0.5
legend.axespad 0.02
lines.marker None
lines.solid_capstyle projecting
axes.titlesize large
backend TkAgg
xtick.major.size 5
legend.fontsize small
legend.shadow False
mathtext.it cmmi10.ttf
font.variant normal
xtick.labelsize small
legend.handletextsep 0.02
ps.distiller.res 6000
patch.linewidth 0.5
lines.dash_capstyle butt
lines.color b
figure.subplot.top 0.9
legend.markerscale 0.6
patch.antialiased True
font.style normal
grid.linestyle :
axes.labelcolor k
text.color k
mathtext.rm cmr10.ttf
interactive True
savefig.orientation portait
svg.image_inline True
ytick.major.size 5
axes.grid False
plugins.directory .matplotlib_plugins
grid.color k
timezone UTC
ytick.major.pad 3
legend.handlelen 0.05
lines.dash_joinstyle miter
datapath c:\local\python25\lib\site-packages\matplotlib-0.87.7-py2.5-win32.egg\matplotlib\mpl-data
image.lut 256
figure.subplot.bottom 0.1
legend.numpoints 4
font.sans-serif sans-serif
font.family serif
axes.labelsize medium
ytick.minor.pad 3
axes.hold True
verbose.level silent
mathtext.nonascii cmex10.ttf
figure.subplot.left 0.125
text.fontstyle normal
font.weight normal
mathtext.mit cmmi10.ttf
ytick.labelsize small
ps.papersize letter
ima
ge.origin upper

Oops that was the TKAgg profile results. These are the WxAgg results
attached. Sorry about that.

draw.kcachegrind.gz (15.3 KB)

···

On 7/5/07, Tom Denniston <tom.denniston@...660...> wrote:

I've been trying to profile and speed up an app that uses matplotlib.
I tried to write an example using simple pylab commands to reproduce
the slowness. What I found was I could get a huge speedup just
avoiding unnecessary redraws. I'm down now to passable behavior.
Plotting 6 series in two windows takes about one and a quarter
seconds. I would like to improve this further, however, if it is
possible which is why I am posting.

The results with show() in between plots are:

In [5]: run u:/tdennist/test2.py
10.128132637

In [6]: run u:/tdennist/test2.py
10.3122053602

And without the superfluous draws:

In [7]: run u:/tdennist/test2.py
1.83904865901

In [8]: run u:/tdennist/test2.py
1.86751011294

In [9]: run u:/tdennist/test2.py
1.84959890227

Where 1.85 seconds is the time to do 2 iteractions of drawing 2 plots
with 3 lines each. So about 0.9 to 1.0 sec to draw the plots once.

Is there anything obvious I can do to speed this up? I looked a
profile results of this and found most of the time is spent in "draw"
functions. I attached the profile results in kcachegrind format for
the faster method.

Under the animation section there is a suggestion that things are
faster if you pre allocate the line and then just update it's x or y
data. Given the profile results, however, I don't think this would
help much and it would be kinda inconvenient for my app because I
don't know how many series I am gonna plot up front.

Also at the very bottom is the contents of my rc params. I am using
WxAgg on windows with matplotlib 0.90.1 and python 2.5.

Code
-------

import timeit

setup='''
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.widgets import Cursor
import pylab, numpy
pylab.clf()
#pylab.show()
'''
code='''
fig = pylab.gcf()
p1 = fig.add_axes([0.075, 0.05, 0.8, .4], axisbg='#333333')
cursor = Cursor(p1, useblit=True, color='green', linewidth=2.5 )
p2 = fig.add_axes([0.075, 0.55, 0.8, .4], axisbg='#333333')
def test(n):
   for i in range(3):
       p1.plot(numpy.random.rand(n))
       #pylab.show()

   for i in range(3):
       p2.plot(numpy.random.rand(n))
       #pylab.show()

test(1000)
pylab.show()
'''

print timeit.Timer(code, setup=setup).timeit(2)

rc Params
----------------

figure.subplot.right 0.9
mathtext.cal cmsy10.ttf
font.fantasy fantasy
xtick.minor.pad 3
tk.pythoninspect False
legend.labelsep 0.005
image.aspect equal
font.cursive cursive
figure.subplot.hspace 0.2
xtick.direction in
axes.facecolor w
ytick.direction in
legend.pad 0.2
axes.axisbelow False
lines.markersize 6
figure.dpi 80
text.usetex False
text.fontangle normal
patch.edgecolor k
ps.useafm False
lines.solid_joinstyle miter
font.monospace monospace
xtick.minor.size 2
figure.subplot.wspace 0.2
savefig.edgecolor w
text.fontvariant normal
image.cmap jet
axes.edgecolor k
tk.window_focus False
text.fontsize medium
font.serif serif
savefig.facecolor w
ytick.minor.size 2
mathtext.mathtext2 False
numerix numpy
font.stretch normal
text.dvipnghack False
ytick.color k
lines.linestyle -
xtick.color k
xtick.major.pad 3
text.fontweight normal
patch.facecolor b
figure.figsize (8, 6)
axes.linewidth 1.0
lines.linewidth 0.5
savefig.dpi 150
verbose.fileo sys.stdout
svg.image_noscale False
font.size 12.0
lines.antialiased True
polaraxes.grid True
toolbar toolbar2
pdf.compression 6
grid.linewidth 0.5
figure.facecolor 0.75
ps.usedistiller False
legend.isaxes True
figure.edgecolor w
mathtext.tt cmtt10.ttf
contour.negative_linestyle (6.0, 6.0)
image.interpolation bilinear
lines.markeredgewidth 0.5
legend.axespad 0.02
lines.marker None
lines.solid_capstyle projecting
axes.titlesize large
backend TkAgg
xtick.major.size 5
legend.fontsize small
legend.shadow False
mathtext.it cmmi10.ttf
font.variant normal
xtick.labelsize small
legend.handletextsep 0.02
ps.distiller.res 6000
patch.linewidth 0.5
lines.dash_capstyle butt
lines.color b
figure.subplot.top 0.9
legend.markerscale 0.6
patch.antialiased True
font.style normal
grid.linestyle :
axes.labelcolor k
text.color k
mathtext.rm cmr10.ttf
interactive True
savefig.orientation portait
svg.image_inline True
ytick.major.size 5
axes.grid False
plugins.directory .matplotlib_plugins
grid.color k
timezone UTC
ytick.major.pad 3
legend.handlelen 0.05
lines.dash_joinstyle miter
datapath c:\local\python25\lib\site-packages\matplotlib-0.87.7-py2.5-win32.egg\matplotlib\mpl-data
image.lut 256
figure.subplot.bottom 0.1
legend.numpoints 4
font.sans-serif sans-serif
font.family serif
axes.labelsize medium
ytick.minor.pad 3
axes.hold True
verbose.level silent
mathtext.nonascii cmex10.ttf
figure.subplot.left 0.125
text.fontstyle normal
font.weight normal
mathtext.mit cmmi10.ttf
ytick.labelsize small
ps.papersize letter
ima
ge.origin upper

What is your hold state? In your test function you may want to make
sure you are not repeatedly adding data to the same figure. Eg

p1.plot(something, hold=False)

repeated calls to plot where hold is True can cause significant
slowing... In mpl hold is True by default and in matlab it is False by
default but you can set the default as an Axes property or in your rc
file.

JDH

···

On 7/5/07, Tom Denniston <tom.denniston@...660...> wrote:

Oops that was the TKAgg profile results. These are the WxAgg results
attached. Sorry about that.

On 7/5/07, Tom Denniston <tom.denniston@...660...> wrote:
> I've been trying to profile and speed up an app that uses matplotlib.
> I tried to write an example using simple pylab commands to reproduce
> the slowness. What I found was I could get a huge speedup just
> avoiding unnecessary redraws. I'm down now to passable behavior.
> Plotting 6 series in two windows takes about one and a quarter
> seconds. I would like to improve this further, however, if it is
> possible which is why I am posting.