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

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):

Well, for quick and dirty interactive work, you can use imshow with
nearest neighbor interpolation for this, right? With the tweaks from
the last email (GTKAgg over TkAgg, a custom colormap and normalizer),
and using nearest neighbor interpolation, the performance hit for
imshow over figimage is probably sufferable.

    # imshow
    peds-pc311:~> time python test.py -dGTKAgg --numarray
    1.530u 0.440s 0:01.95 101.0% 0+0k 0+0io 4815pf+0w

    # figimage
    peds-pc311:~> time python test.py -dGTKAgg --numarray
    1.230u 0.200s 0:01.43 100.0% 0+0k 0+0io 4745pf+0w

So you pay a 25-30% performance hit for imshow in the initial display.
I added an image cache to the AxesImage class (which supports imshow)
so that the image doesn't have to be recreated during interaction.
Previous version recreated, normalized and colormapped the image for
each interactive redraw. OK, I feel stupid, don't rub it in. This
*significantly* improves the performance of interaction with images,
though it's harder to measure. Replace image.py with the code
attached below to take advantage of the caching.

In the modified test script below, I had to make mynorm and mycmap
proper instances of normalize and Colormap, since imshow is a little
pickier than figimage and actually tests isinstance. But the logic is
the same as the figimage code.

I think there might be a faster way to take an MxN matrix and repeat
it three times for grayscale than what I do below in mycmap. Perhaps
a resident numarray guru can advise.

You still haven't answered my question if you typically want grayscale
or colormapped images ....

from pylab import *
from matplotlib.colors import Colormap

class mynorm(normalize):

    def __call__(self, X):
        return X

class mycmap(Colormap):

    def __init__(self, name='my gray', N=256):
        self.name = name
    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)
imshow(X, cmap=cmap, norm=norm, interpolation='nearest')
#figimage(X, cmap=cmap, norm=norm)
#show()

    > 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)

Well, test it out under the configuration above and let me know if
it's usable. I think there are a few things I can do in the
_image.fromarray function as I mentioned, and it would be nice to not
have to duplicate the intensity 3 times at the colormapping level,
which is a wasted step. So there will be more optimizations coming
down the pipeline, but I think with the image caching and the
suggestions above, it may be getting close to usable for imshow with
interaction on largish images (on my system, which is 2-4x as fast as
yours, it works great). Let me know.

image.py (10.4 KB)

just to answer your question:

You still haven't answered my question if you typically want grayscale
or colormapped images ....

I am using colourmaps.
Usually a 256 levels is usually more than enough! Here is what I did when
I transformed the midas lut and itt files (3 columns RGB in ascii files see below)
into local python lut (pglut for ppgplot lut).

I am now thinking of using another suggestion (from Arnd) on top of what you said.
If the image is very large then I only load the central region in imshow
(so I extract the central part, ''central'' meaning center with respect to
some predefined center, by default the centre of the image). Then if I want
to see the full image in the window I scale it (factor N)
by only plotting 1 out of N pixels.... This should reproduce what Midas did I think
(not so sure, but Midas has a timed display of < 0.2 sec there in fact whatever
the scale is / size of the window)

One note from a local neird: it seems that the normalisation (colour.py)
in the matplotlib 0.65 version
is doing a divide by (vmax - vmin) and this was timed to be quite long
(see previous mails...). But a numarray division should be instantaneous even
for such a big image so there is something wrong there. Maytbe first
do : dv = vmax - vmin and divide by dv? (maybe this is not the reason,
using ''divide" and '/' may be different too?)

Eric

"""######################################
   # MIDAS-LIKE LUT and ITT
   ######################################"""
class MidasLut:
    def __init__(self):
        self.LUT_PATH = '/soft/python/pcral/plotutils/midaslut/'
        self.R = arange(256)/255.
        self.G = arange(256)/255.
        self.B = arange(256)/255.
        self.L = arange(256)/255.
    def lut(self,name): sname = str(name)
        sname = self.LUT_PATH+sname+".lasc"
  if os.path.isfile(sname):
           f = open(sname)
           list = f.readlines()
           for i in range(256):
             self.R[i] = float(list[i].split()[0])
             self.G[i] = float(list[i].split()[1])
             self.B[i] = float(list[i].split()[2])
           f.close
  else :
     print 'ERROR: Lut file', name,'does not exist'
    def itt(name): sname = str(name)
        sname = LUT_PATH+sname+".iasc"
  if os.path.isfile(sname):
           f = open(sname)
           list = f.readlines()
           for i in range(256):
             L[i] = float(list[i].split()[0])
           f.close
  else :
     print 'ERROR: ITT file', name,'does not exist'

pglut = MidasLut()

···

--

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,

Please consider this code in colors.py (from 546) :
     if vmin is None or vmax is None:
           rval = ravel(val)
           if vmin is None:
               vmin = min(rval)
           if vmax is None:
               vmax = max(rval)

On my computer to be much faster without using rval :

       if vmin is None or vmax is None:
           #rval = ravel(val)
           if vmin is None:
               vmin = val.min()
           if vmax is None:
               vmax = val.max()

I am now able to do a "A=rand(2000,2000) figimage(A)" in a almost acceptable duration.

Hope this helps

Xavier.
ps : may be in double. sorry.

But note that .min and .max are only supported under numarray (I believe). There are a number of things we would like to take advantage of (especially with regard to array indexing) that we can't in matplotlib since the code must work with both Numeric and numarray.

Perry

···

On Dec 21, 2004, at 1:02 PM, Xavier Gnata wrote:

Hi,

Please consider this code in colors.py (from 546) :
   if vmin is None or vmax is None:
          rval = ravel(val)
          if vmin is None:
              vmin = min(rval)
          if vmax is None:
              vmax = max(rval)

On my computer to be much faster without using rval :

      if vmin is None or vmax is None:
          #rval = ravel(val)
          if vmin is None:
              vmin = val.min()
          if vmax is None:
              vmax = val.max()