def test_plot_image(): mu = [3.5, 3] x, y = np.mgrid[0:15, 0:15] pos = np.dstack((x, y)) var = multivariate_normal(mean=mu, cov=[[1,0],[0,1]]) gauss = 5 * var.pdf(pos) - 0.05 # Make sure it has some negative values as well gauss[8,8] = np.NaN gauss[4,4] = -0.2 scales = ['linear', 'sqrt', 'log', 'asinh', 'histeq', 'sinh', 'squared'] fig, axes = plt.subplots(2, 4, figsize=(14, 8)) axes = axes.flatten() for k, scale in enumerate(scales): ax = axes[k] plot_image(gauss, ax=ax, scale=scale, title=scale, cbar='right') ax.plot(mu[1], mu[0], 'r+') # In the final plot: plot_image(gauss, ax=axes[-1], scale='log', title='log - Reds', cmap='Reds', cbar='right') fig.tight_layout() return fig
def test_plot_cbar_and_nans(): # Construct image: np.random.seed(42) img = np.random.rand(10, 10) img[2:8, 2:8] = np.NaN fig, (ax1, ax2, ax3, ax4) = plt.subplots(1, 4, figsize=(16, 6)) plot_image(img, ax=ax1, scale='linear', vmin=0.4, cbar='left') plot_image(img, ax=ax2, scale='sqrt', vmin=0.4, cbar='bottom') plot_image(img, ax=ax3, scale='log', vmin=0.4, cbar='right') plot_image(img, ax=ax4, scale='asinh', vmin=0.4, cbar='top') return fig
def test_plot_image_invalid(): mu = [3.5, 3] x, y = np.mgrid[0:10, 0:10] pos = np.dstack((x, y)) var = multivariate_normal(mean=mu, cov=[[1,0],[0,1]]) gauss = var.pdf(pos) fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6)) # Run with invalid scale: with pytest.raises(ValueError): plot_image(gauss, ax=ax1, scale='invalid-scale') # Plot with single NaN: gauss[1,1] = np.NaN plot_image(gauss, ax=ax1, scale='log') # Run with all-NaN image: gauss[:, :] = np.NaN plot_image(gauss, ax=ax2, cbar='right') return fig
def make_movie(hdf_file, fps=15, dpi=100, overwrite=False): """ Create animation of the contents of a HDF5 files produced by the photometry pipeline. The function will create a MP4 movie file with the same name as the input file, placed in the same directory, containing the animation. Parameters: hdf_file (string): Path to the HDF5 file to produce movie from. fps (integer): Frames per second of generated movie. Default=15. dpi (integer): DPI of the movie. Default=100. overwrite (boolean): Overwrite existing MP4 files? Default=False. .. codeauthor:: Rasmus Handberg <*****@*****.**> """ logger = logging.getLogger(__name__) tqdm_settings = {'disable': not logger.isEnabledFor(logging.INFO)} logger.info("Processing '%s'", hdf_file) # File to be created: output_file = os.path.splitext(hdf_file)[0] + '.mp4' if os.path.exists(output_file): if overwrite: logger.debug("Deleting existing output file") os.remove(output_file) else: logger.info("Movie file already exists") return output_file # Open HDF5 file: # We need to have write-privaledges because we are going to updated some attributes save_image_scales = False with h5py.File(hdf_file, 'r') as hdf: # Load the image scales if they have already been calculated: vmin = hdf['backgrounds'].attrs.get('movie_vmin') vmax = hdf['backgrounds'].attrs.get('movie_vmax') vmin2 = hdf['images'].attrs.get('movie_vmin') vmax2 = hdf['images'].attrs.get('movie_vmax') # Calculate scales to use for plotting the images: if not vmin: logger.info("Calculating image scales...") numfiles = len(hdf['images']) vmax = np.empty(numfiles) vmin = np.empty(numfiles) vmax2 = np.empty(numfiles) vmin2 = np.empty(numfiles) for k in trange(numfiles, **tqdm_settings): vmin[k], vmax[k] = np.nanpercentile( hdf['backgrounds/%04d' % k], [1.0, 99.0]) vmin2[k], vmax2[k] = np.nanpercentile(hdf['images/%04d' % k], [1.0, 99.0]) vmin = np.nanpercentile(vmin, 25.0) vmax = np.nanpercentile(vmax, 75.0) vmin2 = np.nanpercentile(vmin2, 25.0) vmax2 = np.nanpercentile(vmax2, 75.0) save_image_scales = True # If needed, reopen the file for saving the attributes: if save_image_scales: with h5py.File(hdf_file, 'r+') as hdf: # Save image scales to HDF5 file: hdf['backgrounds'].attrs['movie_vmin'] = vmin hdf['backgrounds'].attrs['movie_vmax'] = vmax hdf['images'].attrs['movie_vmin'] = vmin2 hdf['images'].attrs['movie_vmax'] = vmax2 hdf.flush() # We should now be ready for creating the movie, reopen the file as readonly: logger.info("Creating movie...") with h5py.File(hdf_file, 'r') as hdf: numfiles = len(hdf['images']) dummy_img = np.full_like(hdf['images/0000'], np.NaN) time = np.asarray(hdf['time']) cadenceno = np.asarray(hdf['cadenceno']) sector = hdf['images'].attrs.get('SECTOR') camera = hdf['images'].attrs.get('CAMERA') ccd = hdf['images'].attrs.get('CCD') with plt.style.context('dark_background'): plt.rc('axes', titlesize=15) fig, ax = plt.subplots(1, 4, figsize=(20, 6.8), dpi=dpi) # Colormap to use for FFIs: cmap = plt.get_cmap('viridis') cmap.set_bad('k', 1.0) # Colormap for Flags: viridis = plt.get_cmap('Dark2') newcolors = viridis(np.linspace(0, 1, 4)) newcolors[:1, :] = np.array([1, 1, 1, 1]) cmap_flags = ListedColormap(newcolors) imgs = [None] * 4 imgs[0] = plot_image(dummy_img, ax=ax[0], scale='sqrt', vmin=vmin, vmax=vmax, title='Original Image', cmap=cmap, cbar='bottom', cbar_pad=0.05) imgs[1] = plot_image(dummy_img, ax=ax[1], scale='sqrt', vmin=vmin, vmax=vmax, title='Background', cmap=cmap, cbar='bottom', cbar_pad=0.05) imgs[2] = plot_image(dummy_img, ax=ax[2], scale='sqrt', vmin=vmin2, vmax=vmax2, title='Background subtracted', cmap=cmap, cbar='bottom', cbar_pad=0.05) imgs[3] = plot_image( dummy_img, ax=ax[3], scale='linear', vmin=-0.5, vmax=3.5, title='Pixel Flags', cmap=cmap_flags, cbar='bottom', cbar_pad=0.05, clabel='Flags', cbar_ticks=[0, 1, 2, 3], cbar_ticklabels=['None', 'Not used', 'Man Excl', 'Shenan']) for a in ax: a.set_xticks([]) a.set_yticks([]) figtext = fig.suptitle("to come\nt=???????", fontsize=16) fig.subplots_adjust(left=0.03, right=0.97, top=0.95, bottom=0.03, wspace=0.05) set_copyright(fig) metadata = { 'title': 'TESS Sector {sector:d}, Camera {camera:d}, CCD {ccd:d}'. format(sector=sector, camera=camera, ccd=ccd), 'artist': 'TASOC' } # Set up the writer (FFMpeg) WriterClass = animation.writers['ffmpeg'] writer = WriterClass(fps=fps, codec='h264', bitrate=-1, metadata=metadata) with writer.saving(fig, output_file, dpi): for k in trange(numfiles, **tqdm_settings): dset_name = '%04d' % k flux0 = np.asarray(hdf['images/' + dset_name]) bkg = np.asarray(hdf['backgrounds/' + dset_name]) # Plot original image, background and new image: imgs[0].set_data(flux0 + bkg) imgs[1].set_data(bkg) imgs[2].set_data(flux0) # Background Shenanigans flags, if available: if 'pixel_flags/' + dset_name in hdf: img = np.asarray(hdf['pixel_flags/' + dset_name]) flags = np.zeros_like(img, dtype='uint8') flags[img & PixelQualityFlags.NotUsedForBackground != 0] = 1 flags[img & PixelQualityFlags.ManualExclude != 0] = 2 flags[img & PixelQualityFlags.BackgroundShenanigans != 0] = 3 imgs[3].set_data(flags) # Update figure title with cadence information; figtext.set_text( "Sector {sector:d}, Camera {camera:d}, CCD {ccd:d}\ndset={dset:s}, cad={cad:d}, t={time:.6f}" .format(sector=sector, camera=camera, ccd=ccd, dset=dset_name, cad=cadenceno[k], time=time[k])) writer.grab_frame() plt.close(fig) return output_file
def make_combined_movie(input_dir, mode='images', fps=15, dpi=100, overwrite=False): """ Create animation of the combined contents of all HDF5 files in a directory, produced by the photometry pipeline. Parameters: input_dir (string): Path to the directory with HDF5 files to produce movie from. mode (string): Which images to show. Choices are `'originals'`, `'images'`, `'backgrounds'` or `'flags'`. Default=images. fps (integer): Frames per second of generated movie. Default=15. dpi (integer): DPI of the movie. Default=100. overwrite (boolean): Overwrite existing MP4 files? Default=False. .. codeauthor:: Rasmus Handberg <*****@*****.**> """ # Basic input checks: if mode not in ('originals', 'images', 'backgrounds', 'flags'): raise ValueError("Invalid MODE specified") logger = logging.getLogger(__name__) tqdm_settings = {'disable': not logger.isEnabledFor(logging.INFO)} logger.info("Processing '%s'", input_dir) camccdrot = [(1, 3, 1), (1, 2, 3), (2, 3, 1), (2, 2, 3), (3, 1, 1), (3, 4, 3), (4, 1, 1), (4, 4, 3), (1, 4, 1), (1, 1, 3), (2, 4, 1), (2, 1, 3), (3, 2, 1), (3, 3, 3), (4, 2, 1), (4, 3, 3)] # Find the sectors that are available: sectors = [] for fname in find_hdf5_files(input_dir): # Load the sector number from HDF5 file attributes: with h5py.File(fname, 'r') as hdf: s = hdf['images'].attrs.get('SECTOR') if s is not None and int(s) not in sectors: sectors.append(int(s)) else: # If the attribute doesn't exist try to find it from # parsing the file name: m = re.match(r'^sector(\d+)_camera\d_ccd\d\.hdf5$', os.path.basename(fname)) if int(m.group(1)) not in sectors: sectors.append(int(m.group(1))) # Create one movie per found sector: for sector in sectors: # Define the output file, and overwrite it if needed: output_file = os.path.join( input_dir, 'sector{sector:03d}_combined_{mode:s}.mp4'.format(sector=sector, mode=mode)) if os.path.exists(output_file): if overwrite: logger.debug("Deleting existing output file") os.remove(output_file) else: logger.info("Movie file already exists") return output_file try: hdf = [None] * 16 vmin = np.full(16, np.NaN) vmax = np.full(16, np.NaN) for k, (camera, ccd, rot) in enumerate(camccdrot): hdf_file = find_hdf5_files(input_dir, sector=sector, camera=camera, ccd=ccd) if hdf_file: hdf[k] = h5py.File(hdf_file[0], 'r') numfiles = len(hdf[k]['images']) dummy_img = np.full_like(hdf[k]['images/0000'], np.NaN) time = np.asarray(hdf[k]['time']) cadenceno = np.asarray(hdf[k]['cadenceno']) # Load the image scales if they have already been calculated: if mode == 'backgrounds': vmin[k] = hdf[k]['backgrounds'].attrs.get( 'movie_vmin', 0) vmax[k] = hdf[k]['backgrounds'].attrs.get( 'movie_vmax', 500) elif mode == 'images' or mode == 'originals': vmin[k] = hdf[k]['images'].attrs.get('movie_vmin', 0) vmax[k] = hdf[k]['images'].attrs.get('movie_vmax', 500) # Summarize the different CCDs into common values: vmin = np.nanpercentile(vmin, 25.0) vmax = np.nanpercentile(vmax, 75.0) logger.info("Creating combined %s movie...", mode) with plt.style.context('dark_background'): fig, axes = plt.subplots(2, 8, figsize=(25, 6.8), dpi=dpi) cmap = plt.get_cmap('viridis') cmap.set_bad('k', 1.0) # Colormap for Flags: viridis = plt.get_cmap('Dark2') newcolors = viridis(np.linspace(0, 1, 4)) newcolors[:1, :] = np.array([1, 1, 1, 1]) cmap_flags = ListedColormap(newcolors) imgs = [None] * 16 for k, ax in enumerate(axes.flatten()): if mode == 'flags': imgs[k] = plot_image(dummy_img, ax=ax, scale='linear', vmin=-0.5, vmax=4.5, cmap=cmap_flags) else: imgs[k] = plot_image(dummy_img, ax=ax, scale='sqrt', vmin=vmin, vmax=vmax, cmap=cmap) ax.set_xticks([]) ax.set_yticks([]) figtext = fig.suptitle("to come\nt=???????", fontsize=16) fig.subplots_adjust(left=0.03, right=0.97, top=0.90, bottom=0.05, wspace=0.05, hspace=0.05) set_copyright(fig) metadata = { 'title': 'TESS Sector {sector:d}, {mode:s}'.format(sector=sector, mode=mode), 'artist': 'TASOC' } # Set up the writer (FFMpeg) WriterClass = animation.writers['ffmpeg'] writer = WriterClass(fps=fps, codec='h264', bitrate=-1, metadata=metadata) with writer.saving(fig, output_file, dpi): for i in trange(numfiles, **tqdm_settings): dset_name = '%04d' % i for k in range(16): if hdf[k] is None: continue # Background Shenanigans flags, if available: if mode == 'flags': flags = np.asarray(hdf[k]['pixel_flags/' + dset_name]) img = np.zeros_like(flags, dtype='uint8') img[flags & PixelQualityFlags.NotUsedForBackground != 0] = 1 img[flags & PixelQualityFlags.ManualExclude != 0] = 2 img[flags & PixelQualityFlags.BackgroundShenanigans != 0] = 3 elif mode == 'originals': img = np.asarray(hdf[k]['images/' + dset_name]) img += np.asarray(hdf[k]['backgrounds/' + dset_name]) else: img = np.asarray(hdf[k][mode + '/' + dset_name]) # Rotate the image: cam, ccd, rot = camccdrot[k] img = np.rot90(img, rot) # Update the image: imgs[k].set_data(img) # Update figure title with cadence information: figtext.set_text( "Sector {sector:d} - {mode:s}\ndset={dset:s}, cad={cad:d}, t={time:.6f}" .format(sector=sector, mode=mode, dset=dset_name, cad=cadenceno[i], time=time[i])) writer.grab_frame() plt.close(fig) except: # noqa: E722 raise finally: for k in range(16): if hdf[k] is not None: hdf[k].close() return output_file
#flags = np.asarray(hdf['pixel_flags/' + dset_name]) flags = np.zeros_like(flux0, dtype='int32') flags[512:1024, 512:1024] = 128 flags = np.where(flags == 0, 0, np.log2(flags) + 1) #flags = (flags & PixelQualityFlags.BackgroundShenanigans != 0) white = np.array([1, 1, 1, 1]) viridis = plt.get_cmap('viridis') newcolors = viridis(np.linspace(0, 1, int(np.max(flags)))) newcolors[:1, :] = white newcmp = ListedColormap(newcolors) fig, ax = plt.subplots(1, 4, figsize=(20, 6)) plot_image(flux0 + bkg, ax=ax[0], scale='sqrt', vmin=vmin, vmax=vmax, title='Original Image', xlabel=None, ylabel=None, cmap=plt.cm.viridis, make_cbar=True) plot_image(bkg, ax=ax[1], scale='sqrt', vmin=vmin,
def make_combined_movie(input_dir, mode='images', fps=15, dpi=100, overwrite=False): """ Create animation of the combined contents of all HDF5 files in a directory, produced by the photometry pipeline. Parameters: input_dir (string): Path to the directory with HDF5 files to produce movie from. mode (string): Which images to show. Choices are `'images'`, `'backgrounds'` or `'flags'`. Default=images. fps (integer): Frames per second of generated movie. Default=15. dpi (integer): DPI of the movie. Default=100. overwrite (boolean): Overwrite existing MP4 files? Default=False. .. codeauthor:: Rasmus Handberg <*****@*****.**> """ # Basic input checks: assert mode in ('images', 'backgrounds', 'flags'), "Invalid MODE specified" logger = logging.getLogger(__name__) logger.info("Processing '%s'", input_dir) camccdrot = [(1, 3, 1), (1, 2, 3), (2, 3, 1), (2, 2, 3), (3, 1, 1), (3, 4, 3), (4, 1, 1), (4, 4, 3), (1, 4, 1), (1, 1, 3), (2, 4, 1), (2, 1, 3), (3, 2, 1), (3, 3, 3), (4, 2, 1), (4, 3, 3)] # Find the sectors that are available: # TODO: Could we change this so we don't have to parse the filenames? sectors = [] for fname in find_hdf5_files(input_dir): m = re.match(r'^sector(\d+)_camera\d_ccd\d\.hdf5$', os.path.basename(fname)) if int(m.group(1)) not in sectors: sectors.append(int(m.group(1))) # Create one movie per found sector: for sector in sectors: # Define the output file, and overwrite it if needed: output_file = os.path.join( input_dir, 'sector{sector:03d}_combined_{mode:s}.mp4'.format(sector=sector, mode=mode)) if os.path.exists(output_file): if overwrite: logger.debug("Deleting existing output file") os.remove(output_file) else: logger.info("Movie file already exists") return output_file try: hdf = [None] * 16 vmin = np.full(16, np.NaN) vmax = np.full(16, np.NaN) for k, (camera, ccd, rot) in enumerate(camccdrot): hdf_file = find_hdf5_files(input_dir, sector=sector, camera=camera, ccd=ccd) if hdf_file: hdf[k] = h5py.File(hdf_file[0], 'r', libver='latest') numfiles = len(hdf[k]['images']) dummy_img = np.zeros_like(hdf[k]['images/0000']) time = np.asarray(hdf[k]['time']) cadenceno = np.asarray(hdf[k]['cadenceno']) # Load the image scales if they have already been calculated: if mode == 'backgrounds': vmin[k] = hdf[k]['backgrounds'].attrs.get( 'movie_vmin', 0) vmax[k] = hdf[k]['backgrounds'].attrs.get( 'movie_vmax', 500) elif mode == 'images': vmin[k] = hdf[k]['images'].attrs.get('movie_vmin', 0) vmax[k] = hdf[k]['images'].attrs.get('movie_vmax', 500) # Summarize the different CCDs into common values: vmin = np.nanpercentile(vmin, 25.0) vmax = np.nanpercentile(vmax, 75.0) logger.info("Creating movie...") with plt.style.context('dark_background'): fig, axes = plt.subplots(2, 8, figsize=(25, 7.3)) cmap = plt.get_cmap('viridis') cmap.set_bad('k', 1.0) # Colormap for Flags: viridis = plt.get_cmap('Dark2') newcolors = viridis(np.linspace(0, 1, 4)) newcolors[:1, :] = np.array([1, 1, 1, 1]) cmap_flags = ListedColormap(newcolors) imgs = [None] * 16 for k, ax in enumerate(axes.flatten()): if mode == 'flags': imgs[k] = plot_image(dummy_img, ax=ax, scale='linear', vmin=-0.5, vmax=4.5, xlabel=None, ylabel=None, cmap=cmap_flags, make_cbar=False) else: imgs[k] = plot_image(dummy_img, ax=ax, scale='sqrt', vmin=vmin, vmax=vmax, xlabel=None, ylabel=None, cmap=cmap, make_cbar=False) ax.set_xticks([]) ax.set_yticks([]) figtext = fig.suptitle("to come\nt=???????", fontsize=15) fig.set_tight_layout('tight') fig.subplots_adjust(top=0.85) set_copyright(fig) writer = animation.FFMpegWriter(fps=fps) with writer.saving(fig, output_file, dpi): for k in trange(numfiles): dset_name = '%04d' % k for k in range(16): if hdf[k] is None: continue # Background Shenanigans flags, if available: if mode == 'flags': flags = np.asarray(hdf[k]['pixel_flags/' + dset_name]) img = np.zeros_like(flags, dtype='uint8') img[flags & PixelQualityFlags.NotUsedForBackground != 0] = 1 img[flags & PixelQualityFlags.ManualExclude != 0] = 2 img[flags & PixelQualityFlags.BackgroundShenanigans != 0] = 3 else: img = np.asarray(hdf[k][mode + '/' + dset_name]) # Rotate the image: cam, ccd, rot = camccdrot[k] img = np.rot90(img, rot) # Update the image: imgs[k].set_data(img) # Update figure title with cadence information: figtext.set_text( "Sector {sector:d} - {mode:s}\ndset={dset:s}, cad={cad:d}, t={time:.6f}" .format(sector=sector, mode=mode, dset=dset_name, cad=cadenceno[k], time=time[k])) writer.grab_frame() plt.close(fig) except: raise finally: for k in range(16): if hdf[k] is not None: hdf[k].close() return output_file