Is really matplotlib this slooow for displaying images ? (sorry again)

This change alone gives me more than a 2x speedup. So with

    > GTKAgg + a custom normalizer (in this case a do nothing
    > normalizer) you'll be running 4-5 times faster than you were
    > before, me thinks.

Of the remaining time, about half of it, on my system, is spent in the
colormapping. Almost all of this is in
LinearSegmentedColormap.__call__, and is split between these numerix
methods

  0.12s zeros : create the RGBA colormapped output array
  0.23s where : make sure the data are in the [0,1] interval
  0.49s take + makeMappingArray - actually doing the mapping

You may not want or need some of the overhead and extra checking that
matplotlib does in the colormapping. Do you want colormapping at all
by the way?

If not, you can special case colormapping by simply converting to RGB
in the 0-255 interval. Note, as I said it is a bit inelegant that
everything has to go through RGB even if you don't need it. I have
some ideas here, but that will have to wait a bit.

from pylab import *

def mynorm(X):
    return X

class mycmap:
    name = "my gray"

    def __call__(self, X, alpha=None):
        # what is the fastest way to make an MxNx3 array simply
        # duplicating MxN on the last dimension?
        m,n = X.shape
        Z = zeros((m,n,3), typecode=X.typecode())

        Z[...,0] = X
        Z[...,1] = X
        Z[...,2] = X

        return Z

#norm = None # default
norm = mynorm

#cmap = None # default
cmap = mycmap()

ion()

rc('figure', figsize=(13,12))
X = rand(1600,1600)
figimage(X, cmap=cmap, norm=norm)

With the following numbers

# default cmap
peds-pc311:~/python/projects/matplotlib> time python ~/test.py --numarray -dGTKAgg
1.630u 0.430s 0:02.12 97.1% 0+0k 0+0io 4746pf+0w

# custom cmap
peds-pc311:~/python/projects/matplotlib> time python ~/test.py --numarray -dGTKAgg
1.080u 0.290s 0:01.42 96.4% 0+0k 0+0io 4745pf+0w

Of this 1.42 seconds, the big chunks are

  0.660 The time it takes to do from pylab import *; half of this is
        initializing the colormaps and dicts in cm. We should do some
        work to get this number down. But it is a fixed cost that
        doesn't scale with array size

  0.320 RandomArray2.py:97(random) # creating the dummy data. We can
        ignore this

  0.540 backend_gtkagg.py:33(draw) # this creates the entire figure,
        of this, 0.420s is in the function FigureImage.make_image,
        most of which is in the extension code _image.fromarray

So ignoring for now the fixed cost of loading modules and creating
your arrays (Eg by running in pylab using the "run" function you only
pay the module loading costs once), the next place where a big win is
going to come from is in optimizing fromarray.

Note, the matplotlib figure canvas is a drawable widget. If you want
bare metal speed and don't want any of the features matplotlib offers
(interpolation, normalization, colormapping, etc), you can always dump
your image directly to the gtk canvas, especially if you compile gtk
with image support. This may be useful enough for us to consider a
backend figimage pipeline which would bypass a number of extra
copies. Currently we have for gtkagg

numarray -> agg image buffer -> figure canvas agg buffer -> gtk canvas

With some care, we might be able to simplify this, ideally doing for
the canvas

numarray -> gtk canvas # for screen

numarray -> agg buffer # for dumping to PNG

There are some subtleties to think through as to how this would work.
It would probably need to be a canvas method and not a renderer
method, for one thing, which would take a bit of redesign.

And then Midas would have to watch its back!

JDH

Hi again,
thanks a lot for the fixing and comments on figimage. This looks much
much better now. Indeed a local matplotlib user had also pointed
out to me the time it spent on cmap.

By the way, the problem I have now is that I would like to have a quick
way of looking at my images (the 1600x1600) but being able to
size it INTO the actual opened window (so basically this calls for using imshow
and not figimage). Just to be clear here is what I usually do (e.g. with Midas):

1/ I create a display window with the size (and location on my desktop) I wish
2/ I ''load'' my big image in there. Depending on the size it will take the full window or not.
3/ then depending on the region I wish to look at I scale and recenter the image
   to e.g., have it all in the window or just zoom in some regions.
4/ then I can interact with the cursor to e.g. make a cut of the image (and display it
in another window) or get some coordinates

so this would look like this in Midas:

1/ create/disp 1 600,600 # create the display window number 1 with 600x600 px
2/ load image.fits # load the image: from a fits file
3/ load image.fits scale=-2 center=0,0 # center the image at coord 0,0 and
                                               # scale it down by a factor of 2, (- = down, + = up)
4/ get/curs #activate the cursor on the image so that a click
                                       # prints out the corresponding coordinates

By using imshow in matplotlib I think I can solve all these things
(and as soon as the .key fields are activated so I can use the keyboard
to interact with the display), but then it will show again its very slow behaviour
(interpolation, etc...) ? Would there be a way to have such a command
but with a much quicker loading / interacting? (note that the pan and zoom
things would probably do it - although it would need to keep the coordinates right
so there is no confusion there - , but at the moment this is not usable in imshow
with large images as it is much too slow)

Cheers,
Eric

···

--

Observatoire de Lyon emsellem@...419...
9 av. Charles-Andre tel: +33 4 78 86 83 84
69561 Saint-Genis Laval Cedex fax: +33 4 78 86 83 86
France http://www-obs.univ-lyon1.fr/eric.emsellem

Hi Eric,

Hi again,
thanks a lot for the fixing and comments on figimage. This looks much
much better now. Indeed a local matplotlib user had also pointed
out to me the time it spent on cmap.

By the way, the problem I have now is that I would like to have a quick
way of looking at my images (the 1600x1600) but being able to
size it INTO the actual opened window (so basically this calls for using
imshow
and not figimage).

Just a few thoughts:
- you could gain a speed-up by displaying a reduced image,
  e.g. by passing image_mat[::2,::2]
  which would correspond to a 800x800 image
  (but latest when zooming one would need the full image ;-(.
- maybe you have to code the zooming youself in terms of figimage
  (In particular if you are still aiming at the 20000x20000 case)
- Is it right that from imshow you would only need
  the """ extent is a data xmin, xmax, ymin, ymax for making image plots
  registered with data plots. Default is the image dimensions in pixels"""?
  Somehow I would guess that this should not be a part
  which is too slow, so maybe one could do
  something like this (without any interpolation) also for
  figimage.

Not-more-than-0.5-cents-this-time-ly yours,

Arnd

···

On Tue, 21 Dec 2004, Eric Emsellem wrote: