Changeset 285

Show
Ignore:
Timestamp:
11/05/08 11:05:43 (2 months ago)
Author:
bruederle
Message:

Moved image processing functions from 'utilites' to 'plotting', added unit tests, docstrings etc, plus did further cleaning of 'utilities'. Some FACETS specific functions are moved from 'utilities' to a new file facets.mixedutils.py.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/plotting.py

    r283 r285  
    22plotting.py 
    33 
    4 Routines that make nice plotting with Matplotlib easier. 
     4Routines and classes that make plotting and image processing  
     5with Matplotlib and the Python Imaging Library (PIL) easier. 
    56""" 
    67 
     
    1112 
    1213 
    13 # Check availability of pylab 
     14# Check availability of pylab (essential!) 
    1415try : 
    1516    import pylab 
     
    1920except ImportError: 
    2021    MATPLOTLIB_ERROR = \ 
    21 " ----------------- MATPLOTLIB Warning : ---------------------\n \ 
    22 Matplolib NOT detected. The module NeuroTools.plotting depends on this package.\n \ 
    23 Please install the Matplotlib package\n \ 
    24 --> http://matplotlib.sourceforge.net/
     22""" 
     23ERROR: Matplolib not detected! The module NeuroTools.plotting depends on this package. 
     24Please install the Matplotlib package --> http://matplotlib.sourceforge.net/ 
     25""
    2526    raise Exception(MATPLOTLIB_ERROR) 
     27 
     28# Check availability of PIL 
     29try : 
     30    import PIL.Image as Image 
     31    PILIMAGEUSE = True 
     32except ImportError: 
     33    PILIMAGE_WARNING = \ 
     34""" 
     35WARNING: Python Imaging Library PIL not detected! Functions that make use of PIL will not be supported! 
     36""" 
     37    PILIMAGEUSE = False 
     38    print PILIMAGE_WARNING 
    2639 
    2740 
     
    3043# UNIVERSAL FUNCTIONS AND CLASSES FOR NORMAL PYLAB USE # 
    3144######################################################## 
     45 
     46 
     47 
     48def get_display(display): 
     49    """ 
     50    Returns a pylab object with a plot() function to draw the plots. 
     51     
     52    Inputs: 
     53        display - if True, a new figure is created. Otherwise, if display is a 
     54                  subplot object, this object is returned. 
     55    """ 
     56    if display is False: 
     57        return None 
     58    elif display is True: 
     59        pylab.figure() 
     60        return pylab 
     61    else: 
     62        return display 
     63 
     64 
     65 
     66def progress_bar(progress): 
     67    """ 
     68    Prints a progress bar to stdout. 
     69 
     70    Inputs: 
     71        progress - a float between 0. and 1. 
     72    """ 
     73    progressConditionStr = "ERROR: The argument of function NeuroTools.plotting.progress_bar(...) must be a float between 0. and 1.!" 
     74    assert (type(progress) == float) and (progress >= 0.) and (progress <= 1.), progressConditionStr 
     75    length = 50 
     76    filled = int(round(length*progress)) 
     77    print "|" + "=" * filled + " " * (length-filled) + "|\r", 
     78    sys.stdout.flush() 
    3279 
    3380 
     
    67114 
    68115 
    69 def set_pylab_params(fig_width_pt=246.0, 
    70                     ratio=(numpy.sqrt(5)-1.0)/2.0,# Aesthetic golden mean ratio by default 
    71                     text_fontsize=10, tick_labelsize=8, useTex=False): 
    72     """ 
    73     Updates a set of parameters within the the pylab run command parameters dictionary 'pylab.rcParams'  
    74     in order to achieve nicely formatted figures. 
    75  
    76     Inputs: 
    77         fig_width_pt   - Figure width in points. If you want to use your figure inside LaTeX, 
    78                          get this value from LaTeX using '\showthe\columnwidth'. 
    79         ratio          - Ratio between the height and the width of the figure. 
    80         text_fontsize  - Size of axes and in-pic text fonts. 
    81         tick_labelsize - Size of tick label font. 
    82         useTex         - Enables or disables the use of LaTeX for all labels and texts 
    83                          (for details on how to do that, see http://www.scipy.org/Cookbook/Matplotlib/UsingTex). 
    84  
    85     """ 
    86     pylab.rcParams.update(pylab_params(fig_width_pt=fig_width_pt, ratio=ratio, text_fontsize=text_fontsize, \ 
    87         tick_labelsize=tick_labelsize, useTex=useTex)) 
    88  
    89  
    90  
    91 def get_display(display): 
    92     """ 
    93     Returns a pylab object with a plot() function to draw the plots. 
     116def set_axis_limits(subplot, xmin, xmax, ymin, ymax): 
     117    """ 
     118    Defines the axis limits in a plot. 
    94119     
    95120    Inputs: 
    96         display - if True, a new figure is created. Otherwise, if display is a 
    97                   subplot object, this object is returned. 
    98     """ 
    99     if display is False: 
    100         return None 
    101     elif display is True: 
    102         pylab.figure() 
    103         return pylab 
    104     else: 
    105         return display 
     121        subplot     - the targeted plot 
     122        xmin, xmax  - the limits of the x axis 
     123        ymin, ymax  - the limits of the y axis 
     124    """ 
     125    if hasattr(subplot, 'xlim'): 
     126        subplot.xlim(xmin, xmax) 
     127        subplot.ylim(ymin, ymax) 
     128    elif hasattr(subplot, 'set_xlim'): 
     129        subplot.set_xlim(xmin, xmax) 
     130        subplot.set_ylim(ymin, ymax) 
     131    else:  
     132        raise Exception('ERROR: The plot passed to function NeuroTools.plotting.set_axis_limits(...) does not provide limit defining functions.') 
    106133 
    107134 
     
    127154 
    128155 
    129 def set_axis_limits(subplot, xmin, xmax, ymin, ymax): 
    130     """ 
    131     Defines the axis limits in a plot. 
    132      
    133     Inputs: 
    134         subplot     - the targeted plot 
    135         xmin, xmax  - the limits of the x axis 
    136         ymin, ymax  - the limits of the y axis 
    137     """ 
    138     if hasattr(subplot, 'xlim'): 
    139         subplot.xlim(xmin, xmax) 
    140         subplot.ylim(ymin, ymax) 
    141     elif hasattr(subplot, 'set_xlim'): 
    142         subplot.set_xlim(xmin, xmax) 
    143         subplot.set_ylim(ymin, ymax) 
    144     else:  
    145         raise Exception('ERROR: The plot passed to function NeuroTools.plotting.set_axis_limits(...) does not provide limit defining functions.') 
     156def set_pylab_params(fig_width_pt=246.0, 
     157                    ratio=(numpy.sqrt(5)-1.0)/2.0,# Aesthetic golden mean ratio by default 
     158                    text_fontsize=10, tick_labelsize=8, useTex=False): 
     159    """ 
     160    Updates a set of parameters within the the pylab run command parameters dictionary 'pylab.rcParams'  
     161    in order to achieve nicely formatted figures. 
     162 
     163    Inputs: 
     164        fig_width_pt   - Figure width in points. If you want to use your figure inside LaTeX, 
     165                         get this value from LaTeX using '\showthe\columnwidth'. 
     166        ratio          - Ratio between the height and the width of the figure. 
     167        text_fontsize  - Size of axes and in-pic text fonts. 
     168        tick_labelsize - Size of tick label font. 
     169        useTex         - Enables or disables the use of LaTeX for all labels and texts 
     170                         (for details on how to do that, see http://www.scipy.org/Cookbook/Matplotlib/UsingTex). 
     171 
     172    """ 
     173    pylab.rcParams.update(pylab_params(fig_width_pt=fig_width_pt, ratio=ratio, text_fontsize=text_fontsize, \ 
     174        tick_labelsize=tick_labelsize, useTex=useTex)) 
    146175 
    147176 
     
    150179# SPECIAL PLOTTING FUNCTIONS AND CLASSES FOR SPECIFIC REQUIREMENTS # 
    151180#################################################################### 
     181 
     182 
     183 
     184def save_2D_image(mat, filename): 
     185    """ 
     186    Saves a 2D numpy array of gray shades between 0 and 1 to a PNG file. 
     187 
     188    Inputs: 
     189        mat      - a 2D numpy array of floats between 0 and 1 
     190        filename - string specifying the filename where to save the data, has to end on '.png' 
     191    """ 
     192    assert PILIMAGEUSE, "ERROR: Since PIL has not been detected, the function NeuroTools.plotting.save_2D_image(...) is not supported!" 
     193    matConditionStr = "ERROR: First argument of function NeuroTools.plotting.imsave(...) must be a 2D numpy array of floats between 0. and 1.!" 
     194    filenameConditionStr = "ERROR: Second argument of function NeuroTools.plotting.imsave(...) must be a string ending on \".png\"!" 
     195    assert (type(mat) == numpy.ndarray) and (mat.ndim == 2) and (mat.min() >= 0.) and (mat.max() <= 1.), matConditionStr 
     196    assert (type(filename) == str) and (len(filename) > 4) and (filename[-4:].lower() == '.png'), filenameConditionStr 
     197    mode = 'L' 
     198    # PIL asks for a permuted (col,line) shape coresponding to the natural (x,y) space 
     199    pilImage = Image.new(mode, (mat.shape[1], mat.shape[0])) 
     200    data = numpy.floor(numpy.ravel(mat) * 256.) 
     201    pilImage.putdata(data) 
     202    pilImage.save(filename) 
     203 
     204 
     205 
     206def save_2D_movie(frame_list, filename, frame_duration): 
     207    """ 
     208    Saves a list of 2D numpy arrays of gray shades between 0 and 1 to a zipped tree of PNG files. 
     209     
     210    Inputs: 
     211        frame_list     - a list of 2D numpy arrays of floats between 0 and 1 
     212        filename       - string specifying the filename where to save the data, has to end on '.zip' 
     213        frame_duration - specifier for the duration per frame, will be stored as additional meta-data 
     214    """ 
     215    try: 
     216        import zipfile 
     217    except ImportError: 
     218        raise ImportError("ERROR: Python module zipfile not found! Needed by NeuroTools.plotting.save_2D_movie(...)!") 
     219    try: 
     220        import StringIO 
     221    except ImportError: 
     222        raise ImportError("ERROR: Python module StringIO not found! Needed by NeuroTools.plotting.save_2D_movie(...)!") 
     223    assert PILIMAGEUSE, "ERROR: Since PIL has not been detected, the function NeuroTools.plotting.save_2D_movie(...) is not supported!" 
     224    filenameConditionStr = "ERROR: Second argument of function NeuroTools.plotting.save_2D_movie(...) must be a string ending on \".zip\"!" 
     225    assert (type(filename) == str) and (len(filename) > 4) and (filename[-4:].lower() == '.zip'), filenameConditionStr 
     226    zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) 
     227    container = filename[:-4] # remove .zip 
     228    frame_name_format = "frame%s.%dd.png" % ("%", pylab.ceil(pylab.log10(len(frame_list)))) 
     229    for frame_num, frame in enumerate(frame_list): 
     230        frame_data = [(p,p,p) for p in frame.flat] 
     231        im = Image.new('RGB', frame.shape, 'white') 
     232        im.putdata(frame_data) 
     233        io = StringIO.StringIO() 
     234        im.save(io, format='png') 
     235        pngname = frame_name_format % frame_num 
     236        arcname = "%s/%s" % (container, pngname) 
     237        io.seek(0) 
     238        zf.writestr(arcname, io.read()) 
     239        progress_bar(float(frame_num)/len(frame_list)) 
     240 
     241    # add 'parameters' and 'frames' files to the zip archive 
     242    zf.writestr("%s/parameters" % container, 
     243                'frame_duration = %s' % frame_duration) 
     244    zf.writestr("%s/frames" % container, 
     245                '\n'.join(["frame%.3d.png" % i for i in range(len(frame_list))])) 
     246    zf.close() 
    152247 
    153248 
  • trunk/src/utilities/__init__.py

    r225 r285  
    1 #!/usr/bin/env python 
    2 # -*- coding: utf8 -*- 
    31""" 
    42utilities.py 
    5 ======== 
    63 
    7 This is a generic set of tools to handle images. 
    8  
    9 Laurent Perrinet, INCM, CNRS 
    10  
    11 $ Id $ 
    12  
     4Routines and classes that make life easier. 
    135""" 
    146 
    157def imsave(mat,filename): 
    16     """ saves a matrix of gray shades between 0 and 1 to a PNG file 
    178 
    18 OBSOLETE: I would use scipy.misc.imsave instead... (and imread, ndimage etc...
     9    raise Exception("This function has been moved to NeuroTools.plotting and is now called save_2D_image(...)!"
    1910 
    20     See http://www.scipy.org/Cookbook/Matplotlib/LoadImage 
    21  
    22         mat should be a numpy array of floats between 0 and 1 
    23  
    24         TODO : have exact reconstruction? 
    25         TODO : compare with pylab's i.write_png('essai.png') 
    26         TODO : save 3D and 4D images 
    27  
    28         from PIL import Image 
    29         save(’my.png’) 
    30      """ 
    31     import Image,numpy 
    32     mode = 'L' 
    33     # PIL asks for a permuted (col,line) shape coresponding to the natural (x,y) space 
    34     pilImage =Image.new(mode , (mat.shape[1],mat.shape[0])) 
    35     data = numpy.floor(numpy.ravel(mat) * 256.) 
    36     pilImage.putdata(data) 
    37     #pilImage = Image.fromarray(mat, 'L')#‘RGBA’) 
    38     pilImage.save(filename) 
    3911 
    4012 
    4113def progress_bar(progress): 
    42     length = 50 
    43     filled = int(round(length*progress)
    44     print "|" + "="*filled + " "*(length-filled) + "|\r", 
    45     sys.stdout.flush() 
     14     
     15    raise Exception("This function has been moved to NeuroTools.plotting!"
     16 
     17 
    4618 
    4719def exportPNGZip(frame_list, filename, frame_duration): 
    48     """ 
    49     Given a list of movie frames as 2D numpy arrays, save each frame in 
    50     PNG format within a zip archive. 
    51     """ 
    52     import zipfile 
    53     import PIL.Image 
    54     import StringIO 
    55     import pylab 
    56     zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) 
    57     container = filename[:-4] # remove .zip 
    58     frame_name_format = "frame%s.%dd.png" % ("%", pylab.ceil(pylab.log10(len(frame_list)))) 
    59     for frame_num, frame in enumerate(frame_list): 
    60         frame_data = [(p,p,p) for p in frame.flat] 
    61         im = PIL.Image.new('RGB', frame.shape, 'white') 
    62         im.putdata(frame_data) 
    63         io = StringIO.StringIO() 
    64         im.save(io, format='png') 
    6520 
    66         #pngname = "frame%.3d.png" % frame_num 
    67         pngname = frame_name_format % frame_num 
    68         #im.save(pngname, format='png') 
    69         arcname = "%s/%s" % (container, pngname) 
    70         io.seek(0) 
    71         zf.writestr(arcname, io.read()) 
    72         progress_bar(float(frame_num)/len(frame_list)) 
     21    raise Exception("This function has been moved to NeuroTools.plotting and is now called save_2D_movie(...)!") 
    7322 
    74     # add 'parameters' and 'frames' files to the zip archive 
    75     zf.writestr("%s/parameters" % container, 
    76                 'frame_duration = %s' % frame_duration) 
    77     zf.writestr("%s/frames" % container, 
    78                 '\n'.join(["frame%.3d.png" % i for i in range(len(frame_list))])) 
    79     zf.close() 
     23 
     24 
     25def show(url): 
     26 
     27    raise Exception("This function has been moved to 'facets.mixedutils' because it contains FACETS specific code!") 
     28 
     29 
    8030 
    8131def save_image(arr, filename): 
    82     assert filename[-3:] == "png" 
    83     import pylab 
    84     fig = pylab.figure() 
    85     pylab.imshow(arr) 
    86     if arr.min() != arr.max(): 
    87         pylab.colorbar() 
    88     fig.savefig(filename) 
    8932 
    90 """ 
    91 Convert between FACETS movie (image sequence) formats 
    92 At the moment, these are: 
    93 * zipped directory containing png files, a frames text file and a parameters text file 
    94 * HDF5 
    95 """ 
    96  
    97 try: 
    98     from NeuroTools.facets import FileExtension as file_extension 
    99 except ImportError: 
    100     print "Warning: unable to import FileExtension" 
    101 try: 
    102     from NeuroTools.facets.fkbtools import png_to_hdf5, hdf5_to_png 
    103 except ImportError: 
    104     print "Warning: unable to import fkbtools" 
    105 import os 
    106 import sys 
    107  
    108 def show(url): 
    109     """Display an HDF5 movie.""" 
    110     file = file_extension.openHDF5File(url, "r") 
    111     file.showMovie("/Movie") 
    112     file.close() 
    113  
    114 #=============================================================================== 
    115 if __name__ == "__main__": 
    116     if len(sys.argv) > 1: 
    117         if sys.argv[1] == 'convert': 
    118             input_file = "file://" + os.path.join(os.getcwd(),sys.argv[2]) 
    119             ext = os.path.splitext(input_file)[1] 
    120             if ext == '.h5': 
    121                 hdf5_to_png(input_file, input_file.replace('.h5','.zip')) 
    122             elif ext == '.zip': 
    123                 png_to_hdf5(input_file, input_file.replace('.zip','.h5')) 
    124             elif ext == '': # directory 
    125                 png_to_hdf5(input_file, input_file + '.h5') 
    126         elif sys.argv[1] == 'show': 
    127             show("file://" + os.path.join(os.getcwd(),sys.argv[2])) 
    128         else: 
    129             print "Valid commands are 'convert' and 'show'" 
    130     else: 
    131         print "Usage examples:\n  $ python movieformats.py convert teststim.zip\n  $ python movieformats.py convert teststim1.h5" 
     33    raise Exception("This function has been moved to 'facets.mixedutils' because it contains FACETS specific code!")