Example #1
0
def play_movie(x, y, images=None, extent=None, aspect='equal', color='blue', edgecolor='none', orientation=None, save=False, save_movie_path='', nskip=0, artists=[[]], xlim=None, ylim=None, colornorm=None, colormap='jet', ghost_tail=20, ax=None, wedge_radius=0.01, circle_radius=0.005, deg=False, flip=False, imagecolormap='jet', mono=True, flipimgx=False, flipimgy=False):
    '''
    Show an animation of N x,y trajectories with color, orientation, and a tail. And optionally background images.
    
    x               -- list or np.array for x position of trajectory, OR, if multiple trajectories, list of lists/np.arrays
    y               -- list or np.array for y position of trajectory, OR, if multiple trajectories, list of lists/np.arrays
    images          --      - list of images to set as the background for the animation
                            - or a single static image
                            - or path to a directory with a sequence of pyplot.imread readable images (jpeg, png, etc), numbered in order
                            - or a type with a __call__ attribute (eg. a function or class method). 
                              The function __call__ attribute should take a single input, the frame number, and return the image to be used.
                            
    extent, aspect  --     see matplotlib.pyplot.imshow for details - note "origin" from imshow does not work as expected, use flipimgx and flipimgy instead
    flipimgx        -- flip the image in along the "x" axis (eg. reverse image columns), default: False. 
    flipimgy        -- flip the image in along the "y" axis (eg. reverse image rows), default: False. 
    imagecolormap   -- colormap for images, eg. 'jet' or 'gray'
        mono        -- if the image is, or should be, mono (grayscale) set this to True (default: True). Required for colormaps to work properly
    color           -- list, OR list of lists/np.arrays, OR string
        colornorm   -- [min, max] to use for normalizing color
                       If None, uses first trajectory to set colornorm
    orientation     -- list, OR list of lists/np.arrays, OR None. 
                       If None, movie uses circles, else uses oriented wedges from fly_plot_lib.get_wedges...
    artists         -- optional list of matplotlib artists
    xlim            -- xlim for plot, if None, automatically generate limits based on trajectory
    ylim            -- ylim for plot, if None, automatically generate limits based on trajectory
    ghost_tail      -- number of frames of 'tail' to show
    ax              -- matplotlib axis, optional
    wedge_radius    -- size_radius used in fpl.get_wedges
    circle_radius   -- radius used in fpl.get_circles
                       currently changing size is NOT supported for animations. 
    deg             -- (bool) is orientation given in degrees? True means yes. Passed to fpl.get_wedges...
    flip            -- (bool) flip orientation? True means yes. Passed to fpl.get_wedges...
    
    '''
    plt.close('all')
    
    # prep plot
    if ax is None:
        fig = plt.figure()
        ax = fig.add_subplot(111)
    anim_params = {'frame': -1*(1+nskip)+1, 'movie_finished': False}
    
    # fix format for single trajectories
    if type(x) is list:
        if type(x[0]) is list or type(x[0]) is np.ndarray:
            print
            print type(x[0])
            print str(len(x)) + ' flies!'
        else:# type(x[0]) is float or type(x[0]) is int or type(x[0]) is long or type(x[0]):
            print
            print 'Just one fly!'
            x = [x]
            y = [y]
            color = [color]
            edgecolor = [edgecolor]
            orientation = [orientation]
    else:
        print
        print str(len(x)) + ' flies!'
                
    if len(color) != len(x):
        only_color = color[0]
        color = [only_color for i in range(len(x))]
        
    if type(edgecolor) is not list:
        edgecolor = [edgecolor]    
    if len(edgecolor) != len(x):
        only_edgecolor = edgecolor[0]
        edgecolor = [only_edgecolor for i in range(len(x))]
        
    if type(color[0]) is not str:
        if colornorm is None:
            colornorm = [np.min(color), np.max(color)]    
        norm = matplotlib.colors.Normalize(colornorm[0], colornorm[1])
        color_mappable = matplotlib.cm.ScalarMappable(norm, plt.get_cmap('jet'))
    else:
        colornorm = None
        colormap= None
        norm = None
        color_mappable = None
        
    flies = []
    for i, xpos in enumerate(x):
        if orientation[i] is None: # use circles from scatter
            radius = circle_radius
            alpha = 1
            radiusnorm = None
            maxradius = 1
            minradius = 0
            fly = fpl.get_circles_for_scatter(x[i], y[i], color=color[i], colormap=colormap, radius=radius, colornorm=colornorm, alpha=alpha, radiusnorm=radiusnorm, maxradius=maxradius, minradius=minradius, edgecolor=edgecolor)
        elif orientation[i] is not None: # use wedges from get_wedges
            fly = fpl.get_wedges_for_heading_plot(x[i], y[i], color[i], orientation[i], size_radius=wedge_radius, size_angle=20, colormap=colormap, colornorm=colornorm, alpha=1, flip=flip, deg=deg, nskip=0, center_offset_fraction=0.75, edgecolor=edgecolor)

        flies.append(fly)
    
    # add artists
    for artist in artists[i]:
        ax.add_artist(artist)
        
    # add images
    if images is not None:
        frame = 0
        if hasattr(images, '__call__'):
            imgdata = images(frame)
            if len(imgdata.shape) > 2:
                imgdata = imgdata[:,:,0]
            if flipimgx:
                if flipimgy:
                    imgdata = imgdata[::-1,::-1]
                else:
                    imgdata = imgdata[::-1,:]
            elif flipimgy:
                imgdata = imgdata[:,::-1]
            else:
                imgdata = imgdata[:,:]
         
        else:   
            imgdata = get_image_data(images, frame, mono=mono, flipimgx=flipimgx, flipimgy=flipimgy)
        img = ax.imshow( imgdata, extent=extent, cmap=plt.get_cmap(imagecolormap), zorder=-10)
    
    for fly in flies:
        ax.add_collection(fly)
    
    def init_plot(): 
        for fly in flies:
            fly.set_color('none')
        if images is None:
            return flies
        else:
            animation_objects = [fly for fly in flies]
            animation_objects.insert(0, img)
            return animation_objects
        
    def updatefig(*args):
        anim_params['frame'] += 1 + nskip
        print anim_params['frame'] 
        if anim_params['frame'] >= len(x[0])-1:
            anim_params['frame'] = 1
            anim_params['movie_finished'] = True
            
        frame_start = anim_params['frame'] - ghost_tail
        frame_end = anim_params['frame']

        if frame_start < 0:
            frame_start = 0
        frames = np.arange(frame_start, frame_end, 1).tolist()
        
        for i, fly in enumerate(flies):
            if frame_end > len(x[i]):
                colors = ['none' for f in range(len(x[i]))]
            else:
                colors = ['none' for f in range(len(x[i]))]
                for f in frames:
                    try:
                        colors[f] = color_mappable.to_rgba(color[i][f])
                    except:
                        colors[f] = color[i]
                    
            if frame_end > len(x[i]):
                edgecolors = ['none' for f in range(len(x[i]))]
            else:
                edgecolors = ['none' for f in range(len(x[i]))]
                for f in frames:
                    edgecolors[f] = edgecolor[i]
            
            fly.set_edgecolors(edgecolors)
            fly.set_facecolors(colors)
            
        if images is not None:
            if hasattr(images, '__call__'):
                imgdata = images(frames[-1])
                if len(imgdata.shape) > 2:
                    imgdata = imgdata[:,:,0]
                if flipimgx:
                    if flipimgy:
                        imgdata = imgdata[::-1,::-1]
                    else:
                        imgdata = imgdata[::-1,:]
                elif flipimgy:
                    imgdata = imgdata[:,::-1]
                else:
                    imgdata = imgdata[:,:]
             
            else:   
                imgdata = get_image_data(images, frames[-1], mono=mono, flipimgx=flipimgx, flipimgy=flipimgy)
            img.set_array(imgdata)
            
        if save and not anim_params['movie_finished']:
            print 'saving frame: ', str(anim_params['frame']), ' -- if the animation you see is strange, do not worry, look at the pngs'
            frame_prefix = '_tmp'
            frame_prefix = os.path.join(save_movie_path, frame_prefix)
            strnum = str(anim_params['frame'])
            num_frame_digits = np.ceil( np.log10(len(x[0]))) + 1
            while len(strnum) < num_frame_digits:
                strnum = '0' + strnum
            frame_name = frame_prefix + '_' + strnum + '_' + '.png'
            fig.savefig(frame_name, format='png')
            
        if save and anim_params['movie_finished']:
            print 
            print 'Movie finished saving! Close the plot screen now.'
            print 'PNGs are at: ', save_movie_path
            print 'To turn the PNGs into a movie, you can run this command from inside the directory with the tmp files: '
            print 'mencoder \'mf://*.png\' -mf type=png:fps=30 -ovc lavc -lavcopts vcodec=mpeg4 -oac copy -o animation.avi'
        
        if images is None:
            return flies
        else:
            animation_objects = [fly for fly in flies]
            animation_objects.insert(0, img)
            return animation_objects

    # generate and set limits:
    if xlim is None:
        xlim = [np.min(x[0]), np.max(x[0])]
    if ylim is None:
        ylim = [np.min(y[0]), np.max(y[0])]
    
    ax.set_xlim(xlim[0], xlim[1])
    ax.set_ylim(ylim[0], ylim[1])
    
    ax.set_aspect(aspect)
    #
    
    fpl.adjust_spines(ax, ['left', 'bottom'], xticks=xlim, yticks=ylim)
    ax.set_xlabel('x position, m')
    ax.set_ylabel('y position, m')    
    
    ani = animation.FuncAnimation(fig, updatefig, init_func=init_plot, fargs=anim_params, interval=50, blit=True)
    
    plt.show()
def play_movie_3_axes(x, y, z, color, orientation=None, save=False, save_movie_path='', nskip=0, images=[None, None, None], images_extents=[None, None, None], artists=[[], [], []], lims=[None, None, None], colornorm=None, colormap='jet', ghost_tail=20):
    '''
    Show an animation of an x,y,z trajectory with color and a tail. The axes are referred to in the following order: (xy, xz, yz)
    
    x, y, z         -- lists or arrays of length N
    color           -- list or array of length N, or color name string for constant color
    orientation     -- list of length N, or None. If None, movie uses circles, else uses oriented wedges from fly_plot_lib.get_wedges...
    artists         -- list of length 3, corresponding to x/y/z axes, each component should be a list of matplotlib artists
    lims            -- list of limits for the three axes (xy, xz, yz), if None, automatically generate limits based on trajectory
    ghost_tail      -- number of frames of 'tail' to show
    
    TODO: test and animate images, add image function instead of requiring premade list
    '''
    
    # prep plot
    fig = plt.figure()
    ax_xy = fig.add_subplot(221)
    ax_xz = fig.add_subplot(223)
    ax_yz = fig.add_subplot(224)
    axes = [ax_xy, ax_xz, ax_yz]
    anim_params = {'frame': -1*(1+nskip)}

    if colornorm is None:
        colornorm = [np.min(color), np.max(color)]    
    norm = matplotlib.colors.Normalize(colornorm[0], colornorm[1])
    color_mappable = matplotlib.cm.ScalarMappable(norm, plt.get_cmap('jet'))
    
    if orientation is None:
        radius = 0.01
        alpha = 1
        radiusnorm = None
        maxradius = 1
        minradius = 0
        flies_xy = fpl.get_circles_for_scatter(x, y, color=color, colormap=colormap, radius=radius, colornorm=colornorm, alpha=alpha, radiusnorm=radiusnorm, maxradius=maxradius, minradius=minradius)
        flies_xz = fpl.get_circles_for_scatter(x, z, color=color, colormap=colormap, radius=radius, colornorm=colornorm, alpha=alpha, radiusnorm=radiusnorm, maxradius=maxradius, minradius=minradius)
        flies_yz = fpl.get_circles_for_scatter(y, z, color=color, colormap=colormap, radius=radius, colornorm=colornorm, alpha=alpha, radiusnorm=radiusnorm, maxradius=maxradius, minradius=minradius)
        
    def get_images(f):
        ims = [None for i in range(3)]
        origin = 'lower'
        zorder_image = 0
        alpha_image = 0.5
        for i, image in enumerate(images):
            if image is not None:
                if image_extents[i] is None:
                    print 'Must include extent for image'
                    raise(ValueError)
                    
                if type(image) is list:
                    im = image[f]
                else:
                    im = image
                ims[i] = im
        return ims
        
    # initialize images:
    ims = get_images(0)
    ax_ims = [None for i in range(3)]
    for i, ax in enumerate(axes):
        if ims[i] is not None:
            im = ax.imshow(ims[i], extent=image_extens[i], origin='lower', cmap=plt.get_cmap(colormap), norm=norm, alpha=0.5, zorder=0)
            ax_ims[i] = im
    
    # add artists
    for i, ax in enumerate(axes):
        for artist in artists[i]:
            ax.add_artist(artist)
    
    ax_xy.add_collection(flies_xy)
    ax_xz.add_collection(flies_xz)
    ax_yz.add_collection(flies_yz)
    
    def init_plot(): 
        flies_xy.set_color('none')
        flies_xz.set_color('none')
        flies_yz.set_color('none')
        flies_xy.set_edgecolors('none')
        flies_xz.set_edgecolors('none')
        flies_yz.set_edgecolors('none')
        return flies_xy, flies_xz, flies_yz
    
    def updatefig(*args):
        #x = anim_params['x']
        #y = anim_params['y']
        #z = anim_params['z']
        #color = anim_params['color']
        print anim_params['frame']
        
        anim_params['frame'] += 1 + nskip
        frame_end = anim_params['frame'] + ghost_tail
        if frame_end > len(x):
            frame_end = len(x)
        if anim_params['frame'] >= len(x)-1:
            anim_params['frame'] = 0
            frame_end =  anim_params['frame'] + ghost_tail
        frames = np.arange(anim_params['frame'], frame_end, 1).tolist()
                                
        colors = ['none' for i in range(len(x))]
        for f in frames:
            colors[f] = color_mappable.to_rgba(color[f])
        
        flies_xy.set_facecolors(colors)
        flies_xz.set_facecolors(colors)
        flies_yz.set_facecolors(colors)
        
        if save:
            print anim_params['frame']
            frame_prefix = '_tmp'
            frame_prefix = os.path.join(save_movie_path, frame_prefix)
            strnum = str(anim_params['frame'])
            num_frame_digits = np.ceil(len(x) / 10.) + 1
            while len(strnum) < num_frame_digits:
                strnum = '0' + strnum
            frame_name = frame_prefix + '_' + strnum + '_' + '.png'
            fig.savefig(frame_name, format='png')
        
        return flies_xy, flies_xz, flies_yz

    # generate and set limits:
    maxs = [np.max(x), np.max(y), np.max(z)] 
    mins = [np.min(x), np.min(y), np.min(z)] 
    for i, lim in enumerate(lims):
        if lim is None:
            lims[i] = [mins[i], maxs[i]]
            
    ax_xy.set_xlim(lims[0][0], lims[0][1])
    ax_xy.set_ylim(lims[1][0], lims[1][1])
    
    ax_xz.set_xlim(lims[0][0], lims[0][1])
    ax_xz.set_ylim(lims[2][0], lims[2][1])
    
    ax_yz.set_xlim(lims[1][0], lims[1][1])
    ax_yz.set_ylim(lims[2][0], lims[2][1])
    
    for ax in axes:
        ax.set_aspect('equal')
    #
    
    fpl.adjust_spines(ax_xy, ['left'], yticks=[-.15, 0, .15])
    fpl.adjust_spines(ax_xz, ['left', 'bottom'], xticks=[-.2, 0, 1], yticks=[-.15, 0, .15])
    fpl.adjust_spines(ax_yz, ['right', 'bottom'], xticks=[-.15, 0, .15], yticks=[-.15, 0, .15])
    
    # top left plot
    ax_xy.set_ylabel('y position, m')
    
    # bottom left plot
    ax_xz.set_xlabel('x position, m')
    ax_xz.set_ylabel('z position, m')
    
    # bottom right plot
    ax_yz.set_xlabel('y position, m')
    #ax_yz.set_ylabel('z position, m') # I can't figure out how to make this appear on the right side...
    
    ani = animation.FuncAnimation(fig, updatefig, init_func=init_plot, fargs=anim_params, interval=50, blit=True)
    
    plt.show()
Example #3
0
def play_movie(x,
               y,
               images=None,
               extent=None,
               aspect='equal',
               color='blue',
               edgecolor='none',
               orientation=None,
               save=False,
               save_movie_path='',
               nskip=0,
               artists=[],
               xlim=None,
               ylim=None,
               colornorm=None,
               colormap='jet',
               ghost_tail=20,
               ax=None,
               wedge_radius=0.01,
               circle_radius=0.005,
               deg=False,
               flip=False,
               imagecolormap='jet',
               mono=True,
               flipimgx=False,
               flipimgy=False,
               strobe=False,
               sync_frames=None,
               figsize=(5, 3),
               dpi=72):
    '''
    Show an animation of N x,y trajectories with color, orientation, and a tail. And optionally background images.
    
    x               -- list or np.array for x position of trajectory, OR, if multiple trajectories, list of lists/np.arrays
    y               -- list or np.array for y position of trajectory, OR, if multiple trajectories, list of lists/np.arrays
    images          --      - list of images to set as the background for the animation
                            - or a single static image
                            - or path to a directory with a sequence of pyplot.imread readable images (jpeg, png, etc), numbered in order
                            - or a type with a __call__ attribute (eg. a function or class method). 
                              The function __call__ attribute should take a single input, the frame number, and return the image to be used.
                            
    extent, aspect  --     see matplotlib.pyplot.imshow for details - note "origin" from imshow does not work as expected, use flipimgx and flipimgy instead
    flipimgx        -- flip the image in along the "x" axis (eg. reverse image columns), default: False. 
    flipimgy        -- flip the image in along the "y" axis (eg. reverse image rows), default: False. 
    imagecolormap   -- colormap for images, eg. 'jet' or 'gray'
        mono        -- if the image is, or should be, mono (grayscale) set this to True (default: True). Required for colormaps to work properly
    color           -- list, OR list of lists/np.arrays, OR string
        colornorm   -- [min, max] to use for normalizing color
                       If None, uses first trajectory to set colornorm
    orientation     -- list, OR list of lists/np.arrays, OR None. 
                       If None, movie uses circles, else uses oriented wedges from fly_plot_lib.get_wedges...
    artists         -- optional list of matplotlib artists
    xlim            -- xlim for plot, if None, automatically generate limits based on trajectory
    ylim            -- ylim for plot, if None, automatically generate limits based on trajectory
    ghost_tail      -- number of frames of 'tail' to show
    ax              -- matplotlib axis, optional
    wedge_radius    -- size_radius used in fpl.get_wedges
    circle_radius   -- radius used in fpl.get_circles
                       currently changing size is NOT supported for animations. 
    deg             -- (bool) is orientation given in degrees? True means yes. Passed to fpl.get_wedges...
    flip            -- (bool) flip orientation? True means yes. Passed to fpl.get_wedges...
    
    '''
    x = copy.copy(x)
    y = copy.copy(y)
    orientation = copy.copy(orientation)

    if orientation is None:
        orientation = [None for i in range(len(x))]

    plt.close('all')

    # prep plot
    if ax is None:
        fig = plt.figure(figsize=figsize, dpi=dpi)
        ax = fig.add_subplot(111)
    anim_params = {
        'frame': -1 * (1 + nskip) + 1,
        'movie_finished': False,
        'strobe': strobe,
        'strobeimg': None,
        'frames': []
    }

    # fix format for single trajectories
    if type(x) is list:
        if type(x[0]) is list or type(x[0]) is np.ndarray:
            print
            print type(x[0])
            print str(len(x)) + ' flies!'

            if sync_frames is not None:
                largest_sync_frame = np.max(sync_frames)
                first_frames = []
                for i, xi in enumerate(x):
                    padding = [np.nan] * (largest_sync_frame - sync_frames[i])
                    x[i] = np.hstack((padding, x[i]))
                    y[i] = np.hstack((padding, y[i]))
                    color[i] = np.hstack((padding, color[i]))
                    if orientation[0] is not None:
                        orientation[i] = np.hstack((padding, orientation[i]))
                    first_frames.append(len(padding))
            else:
                first_frames = [0] * len(x)

            final_frames = []
            longest_trajectory = 0
            for i, xi in enumerate(x):
                if len(xi) > longest_trajectory:
                    longest_trajectory = len(xi)
            for i, xi in enumerate(x):
                final_frames.append(len(xi))
            for xi in x:
                print len(xi)
        else:  # type(x[0]) is float or type(x[0]) is int or type(x[0]) is long or type(x[0]):
            print
            print 'Just one fly!'
            x = [x]
            y = [y]
            color = [color]
            edgecolor = [edgecolor]
            orientation = [orientation]
            first_frames = [0]
            final_frames = [len(x[0])]
    else:
        print
        print 'Not sure what format x is!'

    anim_params.setdefault('final_frames', final_frames)
    anim_params.setdefault('first_frames', first_frames)

    print 'length color: ', len(color), 'n flies: ', len(x)

    if len(color) != len(x):
        only_color = color[0]
        color = [only_color for i in range(len(x))]

    if type(edgecolor) is not list:
        edgecolor = [edgecolor]
    if len(edgecolor) != len(x):
        only_edgecolor = edgecolor[0]
        edgecolor = [only_edgecolor for i in range(len(x))]

    if type(color[0]) is not str:
        if colornorm is None:
            colornorm = [np.min(color), np.max(color)]
        norm = matplotlib.colors.Normalize(colornorm[0], colornorm[1])
        color_mappable = matplotlib.cm.ScalarMappable(norm,
                                                      plt.get_cmap(colormap))
    else:
        colornorm = None
        colormap = None
        norm = None
        color_mappable = None

    flies = []
    for i, xpos in enumerate(x):
        if orientation[i] is None:  # use circles from scatter
            radius = circle_radius
            alpha = 1
            radiusnorm = None
            maxradius = 1
            minradius = 0
            fly = fpl.get_circles_for_scatter(x[i],
                                              y[i],
                                              color=color[i],
                                              colormap=colormap,
                                              radius=radius,
                                              colornorm=colornorm,
                                              alpha=alpha,
                                              radiusnorm=radiusnorm,
                                              maxradius=maxradius,
                                              minradius=minradius,
                                              edgecolor=edgecolor)
        elif orientation[i] is not None:  # use wedges from get_wedges
            fly = fpl.get_wedges_for_heading_plot(x[i],
                                                  y[i],
                                                  color[i],
                                                  orientation[i],
                                                  size_radius=wedge_radius,
                                                  size_angle=20,
                                                  colormap=colormap,
                                                  colornorm=colornorm,
                                                  alpha=1,
                                                  flip=flip,
                                                  deg=deg,
                                                  nskip=0,
                                                  center_offset_fraction=0.75,
                                                  edgecolor=edgecolor)

        flies.append(fly)

    # add artists
    for artist in artists:
        ax.add_artist(artist)

    # add images
    if images is not None:
        frame = 0
        if hasattr(images, '__call__'):
            imgdata = images(frame)
            if len(imgdata.shape) > 2:
                imgdata = imgdata[:, :, 0]
            if flipimgx:
                if flipimgy:
                    imgdata = imgdata[::-1, ::-1]
                else:
                    imgdata = imgdata[::-1, :]
            elif flipimgy:
                imgdata = imgdata[:, ::-1]
            else:
                imgdata = imgdata[:, :]

        else:
            imgdata = get_image_data(images,
                                     frame,
                                     mono=mono,
                                     flipimgx=flipimgx,
                                     flipimgy=flipimgy)

        img = ax.imshow(imgdata,
                        extent=extent,
                        cmap=plt.get_cmap(imagecolormap),
                        zorder=-10)

    for fly in flies:
        ax.add_collection(fly)

    def init_plot():
        for fly in flies:
            fly.set_color('none')
        if images is None:
            return flies
        else:
            animation_objects = [fly for fly in flies]
            animation_objects.insert(0, img)
            return animation_objects

    def updatefig(*args):
        anim_params['frame'] += 1 + nskip
        if anim_params['frame'] >= len(x[0]) - 1:
            anim_params['frame'] = 1
            anim_params['movie_finished'] = True
        anim_params['frames'].append(anim_params['frame'])
        print anim_params['frame']
        for i, fly in enumerate(flies):
            frame_start = anim_params['frame'] - ghost_tail
            frame_end = anim_params['frame']
            if frame_start < anim_params['first_frames'][i]:
                frame_start = anim_params['first_frames'][i]
            if frame_end > anim_params['final_frames'][i]:
                frame_end = anim_params['final_frames'][i]
            if frame_end < frame_start + nskip:
                continue
            frames = np.arange(frame_start, frame_end, nskip + 1).tolist()
            colors = ['none' for f in range(len(x[i]))]
            edgecolors = ['none' for f in range(len(x[i]))]
            for f in frames:
                try:
                    colors[f] = color_mappable.to_rgba(color[i][f])
                except:
                    colors[f] = color[i]
                edgecolors[f] = edgecolor[i]

            fly.set_edgecolors(edgecolors)
            fly.set_facecolors(colors)

        if images is not None:
            if hasattr(images, '__call__'):
                imgdata = images(frames[-1])
                if len(imgdata.shape) > 2:
                    imgdata = imgdata[:, :, 0]
                if flipimgx:
                    if flipimgy:
                        imgdata = imgdata[::-1, ::-1]
                    else:
                        imgdata = imgdata[::-1, :]
                elif flipimgy:
                    imgdata = imgdata[:, ::-1]
                else:
                    imgdata = imgdata[:, :]

            else:
                imgdata = get_image_data(images,
                                         frames[-1],
                                         mono=mono,
                                         flipimgx=flipimgx,
                                         flipimgy=flipimgy)

            if anim_params['strobe']:
                if anim_params['strobeimg'] is None:
                    anim_params['strobeimg'] = imgdata
                else:
                    anim_params['strobeimg'] = nim.darken(
                        [anim_params['strobeimg'], imgdata])
                img.set_array(anim_params['strobeimg'])
            else:
                img.set_array(imgdata)

        if save and not anim_params['movie_finished']:
            print 'saving frame: ', str(
                anim_params['frame']
            ), ' -- if the animation you see is strange, do not worry, look at the pngs'
            frame_prefix = '_tmp'
            frame_prefix = os.path.join(save_movie_path, frame_prefix)
            strnum = str(anim_params['frame'])
            num_frame_digits = np.ceil(np.log10(len(x[0]))) + 1
            while len(strnum) < num_frame_digits:
                strnum = '0' + strnum
            frame_name = frame_prefix + '_' + strnum + '_' + '.png'
            flytext.set_fontsize(fig, 8)
            fig.savefig(frame_name, format='png')

        if save and anim_params['movie_finished']:
            print
            print 'Movie finished saving! Close the plot screen now.'
            print 'PNGs are at: ', save_movie_path
            print 'To turn the PNGs into a movie, you can run this command from inside the directory with the tmp files: '
            print 'mencoder \'mf://*.png\' -mf type=png:fps=30 -ovc lavc -lavcopts vcodec=mpeg4 -oac copy -o animation.avi'

        if images is None:
            return flies
        else:
            animation_objects = [fly for fly in flies]
            animation_objects.insert(0, img)
            return animation_objects

    # generate and set limits:
    if xlim is None:
        xlim = [np.min(x[0]), np.max(x[0])]
    if ylim is None:
        ylim = [np.min(y[0]), np.max(y[0])]

    ax.set_xlim(xlim[0], xlim[1])
    ax.set_ylim(ylim[0], ylim[1])

    ax.set_aspect(aspect)
    #

    fpl.adjust_spines(ax, ['left', 'bottom'], xticks=xlim, yticks=ylim)
    ax.set_xlabel('x position, m')
    ax.set_ylabel('y position, m')

    ani = animation.FuncAnimation(fig,
                                  updatefig,
                                  init_func=init_plot,
                                  fargs=anim_params,
                                  interval=50,
                                  blit=True)

    plt.show()