This is the python script I used to generate the frames for this movie. I then made the animated gif using ImageMagick convert tool.
#!/usr/bin/env python import numpy import pylab import urllib #- Fetch the plain-text, fixed-column-width version of the Asiago Supernova #- Catalog (ASC) from the Asiago Supernova Group website. This group tries #- to maintain a comprehensive list of all supernovae discovered and announced #- publically via IAU circulars. #- #- Literature reference for the ASC: #- [Barbon et al., 1999, A&AS, 139, 531] #- #- The Asiago Supernova Group website is at: #- [http://graspa.oapd.inaf.it/] #- #- Another resource is the Sternberg Supernova Catalog: #- [http://www.sai.msu.su/sn/sncat/] stream = urllib.urlopen( "http://graspa.oapd.inaf.it/index.php?option=com_content&view=article&id=63&Itemid=82&dir=%2Fvar%2Fwww%2Fhtml%2Fjsmallfib_top%2Fcat&download_file=jsmallfib_top%2Fcat%2Fcat.txt" ) lines = [ line.rstrip( "\n\r" ) for line in stream ] stream.close() lines.pop( 0 ) #- We are interested in the supernova year, R.A. and Dec., and discoverer. The #- ASC has remained consistent since 1999 in formatting its plain-text edition, #- so in the spirit of keeping it simple we adopt the fixed fields as we find #- them on this day. Notice that we read both the coordinates of the host #- galaxy and the supernova in each case --- the host galaxy values are needed #- in case the supernova coordinates are not listed. bounds = { # The following column definitions are correct as of 2010-04-20. "year" : ( 2, 6 ), "gal_ra" : ( 32, 42 ), "gal_dec" : ( 42, 52 ), "sn_ra" : ( 52, 62 ), "sn_dec" : ( 62, 77 ), "disc" : ( 197, None ) } #- Process each row so that the supernova R.A. and Dec. fields are in radians. #- This means making sure that if no supernova coordinates are recorded in the #- ASC, we substitute in the host galaxy coordinates, which will be good enough #- for the figure we are going to make --- the error is much smaller than the #- size of the symbols we will use for plotting. years = [] ras = [] decs = [] discs = [] for line in lines : if not line.rstrip() : continue # Year and discoverer are easy. year = int( line[ bounds[ "year" ][ 0 ] : bounds[ "year" ][ 1 ] ] ) disc = line[ bounds[ "disc" ][ 0 ] : ] # Try for supernova R.A. and Decl. and use galaxy values only if needed. ra = line[ bounds[ "sn_ra" ][ 0 ] : bounds[ "sn_ra" ][ 1 ] ].strip( ": " ) dec = line[ bounds[ "sn_dec" ][ 0 ] : bounds[ "sn_dec" ][ 1 ] ].strip( ": " ) if not ( ra and dec ) : ra = line[ bounds[ "gal_ra" ][ 0 ] : bounds[ "gal_ra" ][ 1 ] ].strip( ": " ) dec = line[ bounds[ "gal_dec" ][ 0 ] : bounds[ "gal_dec" ][ 1 ] ].strip( ": " ) # Convert R.A. to float degrees. h, m, s = ra[ 0 : 2 ], ra[ 2 : 4 ], ra[ 4 : ] try : test = float( s ) except ValueError: s = "00" ra = 15.0 * ( float( h ) + ( float( m ) + float( s ) / 60.0 ) / 60.0 ) # Convert Dec. to float degrees. p, d, m, s = dec[ 0 ], dec[ 1 : 3 ], dec[ 3 : 5 ], dec[ 5 : ] try : test = float( s ) except ValueError: s = "00" dec = float( d ) + ( float( m ) + float( s ) / 60.0 ) / 60.0 if p != "+": dec = -dec # Push onto each array. years.append( year ) ras.append ( ra ) decs.append ( dec ) discs.append( disc ) years = numpy.array( years, dtype = "int" ) discs = numpy.array( discs ) ras = numpy.radians( numpy.array( ras ) ) decs = numpy.radians( numpy.array( decs ) ) ras[ ras > numpy.pi ] = ras[ ras > numpy.pi ] - 2.0 * numpy.pi #- Colors for some selected surveys --- not exhaustive by any stretch. colors = [] for i, disc in enumerate( discs ) : if "sdss" in disc.lower() : discs[ i ] = "SDSS" colors.append( "#C28800" ) elif "loss" in disc.lower() or "lotoss" in disc.lower() : discs[ i ] = "LOSS" colors.append( "#B20050" ) elif "hzsst" in disc.lower() : discs[ i ] = "High-Z" colors.append( "#FF9C00" ) elif "nsf" in disc.lower() : discs[ i ] = "SNfactory" colors.append( "#06D1AE" ) elif "essence" in disc.lower() : discs[ i ] = "ESSENCE" colors.append( "#0F00B2" ) elif "scp" in disc.lower() : discs[ i ] = "SCP" colors.append( "#8C8458" ) elif "cfht" in disc.lower() : discs[ i ] = "SNLS" colors.append( "#3B6642" ) else : discs[ i ] = "other" # could add others here colors.append( "#516587" ) colors = numpy.array( colors ) #- Generate a bunch of images to be run through ImageMagick convert to make an #- animated GIF. uniq_years = sorted( set( years ) ) discs_used = [] color_used = [] for i, year in enumerate( range( 1885, 2011 ) ) : fig = pylab.figure( figsize = ( 8, 4 ), dpi = 180 ) axes = pylab.axes( projection = "hammer" ) axes.grid( True ) selected = years < year print year, print selected.sum(), if any( selected ) : axes.scatter( ras[ selected ], decs[ selected ], c = colors[ selected ], edgecolors = "none", alpha = 0.5 ) selected = years == year print selected.sum() if any( selected ) : axes.scatter( ras[ selected ], decs[ selected ], c = colors[ selected ], edgecolors = "none", alpha = 1.0 ) labels = discs[ selected ] for disc, color in zip( discs[ selected ], colors[ selected ] ) : if disc == "other" : continue if disc not in discs_used : discs_used.append( disc ) color_used.append( color ) print discs_used for i, disc in enumerate( discs_used ) : pylab.text( 0.99, 0.32 - 0.06 * i, disc, color = color_used[ i ], transform = axes.transAxes ) pylab.title( year ) pylab.savefig( str( year ) + ".jpg" ) pylab.clf()