Source code for irisreader.utils.animate

#!/usr/bin/env python3

import matplotlib
from matplotlib import animation
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import HTML
import irisreader as ir

# set a huge animation limit for matplotlib
matplotlib.rcParams['animation.embed_limit'] = 2**128

[docs]def animate( data_cube, raster_pos=None, index_start=None, index_stop=None, interval_ms=50, gamma=0.4, figsize=(7,7), cutoff_percentile=99.9, save_path=None ): """ Creates an animation from the individual images of a data cube. This function can be pretty slow and take 1-2 minutes. Faster alternatives than matplotlib will be researched in the future. Parameters ---------- data_cube : iris_data_cube instance of sji_cube or raster_cube raster_pos : int If not None, only display images at raster postion *raster_pos* index_start : int index where to start animation (defaults to None -> will be set to 0) index_stop : int index where to stop animation (defaults to None -> will be set to n) interval_ms : int number of milliseconds between two frames gamma : float gamma correction for plotting: number between 0 (infinitely gamma correction) and 1 (no gamma correction) figsize : tuple figure size: (width,height) cutoff_percentile : float Often the maximum pixels shine out everything else, even after gamma correction. In order to reduce this effect, the percentile at which to cut the intensity off can be specified with cutoff_percentile in a range between 0 and 100. save_path : str path to file where animation output will be written to (use .mp4 extension) Returns ------- IPython.HTML : HTML object with the animation """ # get number of steps if raster_pos is None: n = data_cube.shape[0] else: n = data_cube.get_raster_pos_steps( raster_pos ) # set default values for index_start and index_stop if index_start is None: index_start=0 if index_stop is None: index_stop=n # raise exception if there is a problem with i_start / i_stop if index_stop > n or index_stop <= index_start: raise Exception("Please make sure that index_start < index_stop < n_steps") # release a duration warning if index_stop-index_start > 100 and ir.config.verbosity_level >= 1: print( "Creating animation with {} frames (this may take while)".format(index_stop-index_start) ) # initialize plot fig = plt.figure( figsize=figsize ) image = data_cube.get_image_step( 0, raster_pos ).clip(min=0.01)**gamma vmax = np.percentile( image, cutoff_percentile ) im = plt.imshow( image, cmap="gist_heat", vmax=vmax, origin='lower' ) # do nothing in the initialization function def init(): return im, # animation function def animate(i, index_start): xcenix = data_cube.headers[i+index_start]['XCENIX'] ycenix = data_cube.headers[i+index_start]['YCENIX'] date_obs = data_cube.headers[i+index_start]['DATE_OBS'] im.axes.set_title( "Frame {}: {}\nXCENIX: {:.3f}, YCENIX: {:.3f}".format( i+index_start, date_obs, xcenix, ycenix ) ) im.set_data( data_cube.get_image_step( i+index_start, raster_pos ).clip(min=0.01)**gamma ) return im, # Call the animator. blit=True means only re-draw the parts that have changed. anim = animation.FuncAnimation(fig, lambda i: animate(i, index_start), init_func=init, frames=index_stop-index_start, interval=interval_ms, blit=True) # Close the plot plt.close(anim._fig) # Save animation if requested if save_path is not None: anim.save( save_path ) return HTML(anim.to_html5_video())