hdul[0].data[ind0:ind1, :, :] = data[dataslice, slices[1], slices[2]] log.info("Flushing") hdul.flush() log.info("Done with iteration for {0}".format(fn)) if debug_mode: log.setLevel(lvl) if __name__ == "__main__": for spw in (0, 1, 2, 3): mxind = get_max_ind('OrionSourceI.B3.spw{0}.lines*fits'.format(spw, )) if mxind < min_nchans: log.critical("Skipping {0} b/c only {1} chans".format(spw, mxind)) continue nchans_total[spw] = mxind log.info("nchans_total[{0}] = {1}".format(spw, mxind)) if os.path.exists( 'OrionSourceI.B3.spw{0}.lines0-60.clarkclean1000.image.pbcor.fits' .format(spw)): make_spw_cube( spw='spw{0}', spwnum=spw, fntemplate='full_OrionSourceI_B3', overwrite_existing=False, bmaj_limits=None, fnsuffix="",
def fits2bitmap(filename, exten=0, out_fn=None, scale='linear', power=1.0, noise_level=None, min_cut=None, max_cut=None, min_percent=None, max_percent=None, percent=None, cmap='Greys_r'): """ Create a bitmap file from a FITS image, applying a scaling/stretching transform between minimum and maximum cut levels and a matplotlib colormap. Parameters ---------- filename : str The filename of the FITS file. exten : int FITS extension number of the image to convert. The default is 0. out_fn : str The filename of the output bitmap image. The type of bitmap is determined by the filename extension (e.g. '.jpg', '.png'). The default is a PNG file with the same name as the FITS file. scale : {{'linear', 'sqrt', 'power', log', 'asinh'}} The scaling/stretch function to apply to the image. The default is 'linear'. power : float, optional The power index for the image scaling. The default is 1.0. noise_level : float, optional The noise level of the image. Pixel values less than ``noise_level`` will approximately be linearly scaled, while pixel values greater than ``noise_level`` will approximately be logarithmically scaled. If ``noise_level`` is not input, an estimate of the 2-sigma level above the background will be used. min_cut : float, optional The pixel value of the minimum cut level. Data values less than ``min_cut`` will set to ``min_cut`` before scaling the image. The default is the image minimum. ``min_cut`` overrides ``min_percent``. max_cut : float, optional The pixel value of the maximum cut level. Data values greater than ``min_cut`` will set to ``min_cut`` before scaling the image. The default is the image maximum. ``max_cut`` overrides ``max_percent``. min_percent : float, optional The percentile value used to determine the pixel value of minimum cut level. The default is 0.0. ``min_percent`` overrides ``percent``. max_percent : float, optional The percentile value used to determine the pixel value of maximum cut level. The default is 100.0. ``max_percent`` overrides ``percent``. percent : float, optional The percentage of the image values used to determine the pixel values of the minimum and maximum cut levels. The lower cut level will set at the ``(100 - percent) / 2`` percentile, while the upper cut level will be set at the ``(100 + percent) / 2`` percentile. The default is 100.0. ``percent`` is ignored if either ``min_percent`` or ``max_percent`` is input. cmap : str The matplotlib color map name. The default is 'Greys_r'. """ hdulist = fits.open(filename) image = hdulist[exten].data hdulist.close() if out_fn is None: out_fn = filename.replace('.fits', '.png') if cmap not in cm.datad.keys(): log.critical('{0} is not a valid matplotlib colormap ' 'name'.format(cmap)) raise SystemExit() image_scaled = imageutils.scale_image(image, scale=scale, power=power, noise_level=noise_level, min_cut=min_cut, max_cut=max_cut, min_percent=min_percent, max_percent=max_percent, percent=percent) mimg.imsave(out_fn, image_scaled, cmap=cmap) log.info('Saved file to {0}'.format(out_fn)) return
def fits2bitmap(filename, ext=0, out_fn=None, stretch='linear', power=1.0, asinh_a=0.1, min_cut=None, max_cut=None, min_percent=None, max_percent=None, percent=None, cmap='Greys_r'): """ Create a bitmap file from a FITS image, applying a stretching transform between minimum and maximum cut levels and a matplotlib colormap. Parameters ---------- filename : str The filename of the FITS file. ext : int FITS extension name or number of the image to convert. The default is 0. out_fn : str The filename of the output bitmap image. The type of bitmap is determined by the filename extension (e.g. '.jpg', '.png'). The default is a PNG file with the same name as the FITS file. stretch : {{'linear', 'sqrt', 'power', log', 'asinh'}} The stretching function to apply to the image. The default is 'linear'. power : float, optional The power index for ``stretch='power'``. The default is 1.0. asinh_a : float, optional For ``stretch='asinh'``, the value where the asinh curve transitions from linear to logarithmic behavior, expressed as a fraction of the normalized image. Must be in the range between 0 and 1. The default is 0.1. min_cut : float, optional The pixel value of the minimum cut level. Data values less than ``min_cut`` will set to ``min_cut`` before stretching the image. The default is the image minimum. ``min_cut`` overrides ``min_percent``. max_cut : float, optional The pixel value of the maximum cut level. Data values greater than ``min_cut`` will set to ``min_cut`` before stretching the image. The default is the image maximum. ``max_cut`` overrides ``max_percent``. min_percent : float, optional The percentile value used to determine the pixel value of minimum cut level. The default is 0.0. ``min_percent`` overrides ``percent``. max_percent : float, optional The percentile value used to determine the pixel value of maximum cut level. The default is 100.0. ``max_percent`` overrides ``percent``. percent : float, optional The percentage of the image values used to determine the pixel values of the minimum and maximum cut levels. The lower cut level will set at the ``(100 - percent) / 2`` percentile, while the upper cut level will be set at the ``(100 + percent) / 2`` percentile. The default is 100.0. ``percent`` is ignored if either ``min_percent`` or ``max_percent`` is input. cmap : str The matplotlib color map name. The default is 'Greys_r'. """ import matplotlib import matplotlib.cm as cm import matplotlib.image as mimg # __main__ gives ext as a string try: ext = int(ext) except ValueError: pass try: image = getdata(filename, ext) except Exception as e: log.critical(e) return 1 if image.ndim != 2: log.critical('data in FITS extension {} is not a 2D array' .format(ext)) if out_fn is None: out_fn = os.path.splitext(filename)[0] if out_fn.endswith('.fits'): out_fn = os.path.splitext(out_fn)[0] out_fn += '.png' # need to explicitly define the output format due to a bug in # matplotlib (<= 2.1), otherwise the format will always be PNG out_format = os.path.splitext(out_fn)[1][1:] # workaround for matplotlib 2.0.0 bug where png images are inverted # (mpl-#7656) if (out_format.lower() == 'png' and LooseVersion(matplotlib.__version__) == LooseVersion('2.0.0')): image = image[::-1] try: cm.get_cmap(cmap) except ValueError: log.critical('{} is not a valid matplotlib colormap name.' .format(cmap)) return 1 norm = simple_norm(image, stretch=stretch, power=power, asinh_a=asinh_a, min_cut=min_cut, max_cut=max_cut, min_percent=min_percent, max_percent=max_percent, percent=percent) mimg.imsave(out_fn, norm(image), cmap=cmap, origin='lower', format=out_format) log.info(f'Saved file to {out_fn}.')
def fits2bitmap( filename, exten=0, out_fn=None, scale="linear", power=1.0, noise_level=None, min_cut=None, max_cut=None, min_percent=None, max_percent=None, percent=None, cmap="Greys_r", ): """ Create a bitmap file from a FITS image, applying a scaling/stretching transform between minimum and maximum cut levels and a matplotlib colormap. Parameters ---------- filename : str The filename of the FITS file. exten : int FITS extension number of the image to convert. The default is 0. out_fn : str The filename of the output bitmap image. The type of bitmap is determined by the filename extension (e.g. '.jpg', '.png'). The default is a PNG file with the same name as the FITS file. scale : {{'linear', 'sqrt', 'power', log', 'asinh'}} The scaling/stretch function to apply to the image. The default is 'linear'. power : float, optional The power index for the image scaling. The default is 1.0. noise_level : float, optional The noise level of the image. Pixel values less than ``noise_level`` will approximately be linearly scaled, while pixel values greater than ``noise_level`` will approximately be logarithmically scaled. If ``noise_level`` is not input, an estimate of the 2-sigma level above the background will be used. min_cut : float, optional The pixel value of the minimum cut level. Data values less than ``min_cut`` will set to ``min_cut`` before scaling the image. The default is the image minimum. ``min_cut`` overrides ``min_percent``. max_cut : float, optional The pixel value of the maximum cut level. Data values greater than ``min_cut`` will set to ``min_cut`` before scaling the image. The default is the image maximum. ``max_cut`` overrides ``max_percent``. min_percent : float, optional The percentile value used to determine the pixel value of minimum cut level. The default is 0.0. ``min_percent`` overrides ``percent``. max_percent : float, optional The percentile value used to determine the pixel value of maximum cut level. The default is 100.0. ``max_percent`` overrides ``percent``. percent : float, optional The percentage of the image values used to determine the pixel values of the minimum and maximum cut levels. The lower cut level will set at the ``(100 - percent) / 2`` percentile, while the upper cut level will be set at the ``(100 + percent) / 2`` percentile. The default is 100.0. ``percent`` is ignored if either ``min_percent`` or ``max_percent`` is input. cmap : str The matplotlib color map name. The default is 'Greys_r'. """ hdulist = fits.open(filename) image = hdulist[exten].data hdulist.close() if out_fn is None: out_fn = filename.replace(".fits", ".png") if cmap not in cm.datad.keys(): log.critical("{0} is not a valid matplotlib colormap " "name".format(cmap)) raise SystemExit() image_scaled = imageutils.scale_image( image, scale=scale, power=power, noise_level=noise_level, min_cut=min_cut, max_cut=max_cut, min_percent=min_percent, max_percent=max_percent, percent=percent, ) mimg.imsave(out_fn, image_scaled, cmap=cmap) log.info("Saved file to {0}".format(out_fn)) return
def chem_plot( linere, yslice=slice(367, 467), xslice=slice(114, 214), vrange=[51, 60] * u.km / u.s, sourcename='e2', filelist=glob.glob(paths.dpath('12m/cutouts/*e2e8*fits')), # 5,8 -> 12.8,8 # 6,8 -> 12.0,8.6 # 5,9 -> 15.0,8.0 # 6,9 -> 15,9.6 #plotgrid=(6,9), figsize=(15.0, 9.6), plotgrid=(6, 8), figsize=(12.0, 8.6), suffix="", vmax_m0=5.0, vmax_max=150, maxbeam=0.5 * u.arcsec, contourlevels=None, filetype='pdf', ): nplots = np.product(plotgrid) text_fontsize = 4.5 if filetype == 'png' else 9 for ii in range(1, 7): if not all( pl.figure(ii, figsize=figsize).get_size_inches() == figsize): pl.close(ii) fig1 = pl.figure(1, figsize=figsize) fig1.clf() gs1 = gridspec.GridSpec(*plotgrid) gs1.update(wspace=0.0, hspace=0.0) fig2 = pl.figure(2, figsize=figsize) fig2.clf() gs2 = gridspec.GridSpec(*plotgrid) gs2.update(wspace=0.0, hspace=0.0) fig3 = pl.figure(3, figsize=figsize) fig3.clf() gs3 = gridspec.GridSpec(*plotgrid) gs3.update(wspace=0.0, hspace=0.0) fig4 = pl.figure(4, figsize=figsize) fig4.clf() gs4 = gridspec.GridSpec(*plotgrid) gs4.update(wspace=0.0, hspace=0.0) fig5 = pl.figure(5, figsize=figsize) fig5.clf() gs5 = gridspec.GridSpec(*plotgrid) gs5.update(wspace=0.0, hspace=0.0) fig6 = pl.figure(6, figsize=figsize) fig6.clf() gs6 = gridspec.GridSpec(*plotgrid) gs6.update(wspace=0.0, hspace=0.0) figcounter = 0 for ii, fn in enumerate(ProgressBar(filelist)): linename = linere.search(fn).groups()[0] if linename not in labeldict: print() print("Skipping {0} because it's not in the label dict".format( linename)) continue label = labeldict[linename] # cache the results for use in other work, later use, ... m0fitsfn = paths.dpath( "chemslices/chemical_m0_slabs_{0}_{1}{2}.fits".format( sourcename, linename, suffix)) m1fitsfn = paths.dpath( "chemslices/chemical_m1_slabs_{0}_{1}{2}.fits".format( sourcename, linename, suffix)) m2fitsfn = paths.dpath( "chemslices/chemical_m2_slabs_{0}_{1}{2}.fits".format( sourcename, linename, suffix)) maxfitsfn = paths.dpath( "chemslices/chemical_max_slabs_{0}_{1}{2}.fits".format( sourcename, linename, suffix)) maxsubfitsfn = paths.dpath( "chemslices/chemical_max_sub_slabs_{0}_{1}{2}.fits".format( sourcename, linename, suffix)) madstdfitsfn = paths.dpath( "chemslices/chemical_madstd_slabs_{0}_{1}{2}.fits".format( sourcename, linename, suffix)) if not (os.path.exists(m0fitsfn) and os.path.exists(m2fitsfn) and os.path.exists(maxfitsfn) and os.path.exists(madstdfitsfn)): print() print("Extracting max/m0/m1/m2 for {0}".format(fn)) cube = SpectralCube.read(fn)[:, yslice, xslice] goodbeams = np.array([bm.major < maxbeam for bm in cube.beams], dtype='bool') if np.count_nonzero(goodbeams) < 5: print() print("Skipping {0} because it has too few good beams.".format( fn)) continue cube = cube.with_mask(goodbeams[:, None, None]) cube = cube.minimal_subcube() if cube.shape[0] == 0: print() print("Skipping {0} because it was masked out".format(fn)) continue bm = cube.beams[0] restfreq = cube.wcs.wcs.restfrq cube = cube.to(u.K, bm.jtok_equiv(restfreq * u.Hz)) slab = cube.spectral_slab(*vrange) cube.beam_threshold = 1 #contguess = cube.spectral_slab(0*u.km/u.s, 40*u.km/u.s).percentile(50, axis=0) #contguess = cube.spectral_slab(70*u.km/u.s, 100*u.km/u.s).percentile(50, axis=0) mask = (cube.spectral_axis < 40 * u.km / u.s) | (cube.spectral_axis > 75 * u.km / u.s) try: contguess = cube.with_mask(mask[:, None, None]).percentile(30, axis=0) except ValueError as ex: print() print("skipping {0}".format(fn)) print(ex) continue slabsub = (slab - contguess) slab.beam_threshold = 0.25 slabsub.beam_threshold = 0.25 m0 = slabsub.moment0() m1 = slabsub.moment1() m2 = slabsub.moment2() max_sub = slabsub.max(axis=0) max = slab.max(axis=0) madstd = cube.with_mask(mask[:, None, None]).apply_function( mad_std, axis=0, projection=True, progressbar=True, unit=cube.unit, ) m0.write(m0fitsfn, overwrite=True) m1.write(m1fitsfn, overwrite=True) m2.write(m2fitsfn, overwrite=True) max.write(maxfitsfn, overwrite=True) max_sub.write(maxsubfitsfn, overwrite=True) madstd.write(madstdfitsfn, overwrite=True) maxfh = max.hdu else: m0fh = fits.open(m0fitsfn) m1fh = fits.open(m1fitsfn) m2fh = fits.open(m2fitsfn) maxfh = fits.open(maxfitsfn)[0] maxsubfh = fits.open(maxsubfitsfn) madstdfh = fits.open(madstdfitsfn) m0 = Projection( value=m0fh[0].data, header=m0fh[0].header, wcs=wcs.WCS(m0fh[0].header), unit=u.Unit(m0fh[0].header['BUNIT']), ) m1 = Projection( value=m1fh[0].data, header=m1fh[0].header, wcs=wcs.WCS(m1fh[0].header), unit=u.Unit(m1fh[0].header['BUNIT']), ) m2 = Projection( value=m2fh[0].data, header=m2fh[0].header, wcs=wcs.WCS(m2fh[0].header), unit=u.Unit(m2fh[0].header['BUNIT']), ) max = Projection( value=maxfh.data, header=maxfh.header, wcs=wcs.WCS(maxfh.header), unit=u.Unit(maxfh.header['BUNIT']), ) max_sub = Projection( value=maxsubfh[0].data, header=maxsubfh[0].header, wcs=wcs.WCS(maxsubfh[0].header), unit=u.Unit(maxsubfh[0].header['BUNIT']), ) madstd = Projection( value=madstdfh[0].data, header=madstdfh[0].header, wcs=wcs.WCS(madstdfh[0].header), unit=u.Unit(madstdfh[0].header['BUNIT']), ) bm = radio_beam.Beam.from_fits_header(m0fh[0].header) restfreq = m0fh[0].header['RESTFRQ'] jtok = bm.jtok(restfreq * u.Hz) if figcounter >= nplots: print("Skipping {0}".format(fn)) break ax1 = fig1.add_subplot(gs1[figcounter]) im1 = ax1.imshow(m0.value, vmin=-1.25 * jtok.value, vmax=vmax_m0 * jtok.value, cmap=pl.cm.bone_r, interpolation='nearest', origin='lower') ax1.text(3, 0.87 * m0.shape[0], label, fontsize=text_fontsize) ax1.set_xticklabels([]) ax1.set_yticklabels([]) ax1.set_xticks([]) ax1.set_yticks([]) ax1.set_aspect('equal') ax2 = fig2.add_subplot(gs2[figcounter]) im2 = ax2.imshow(m1.value, vmin=vrange[0].value, vmax=vrange[1].value, cmap='seismic', interpolation='nearest', origin='lower') ax2.text(3, 0.87 * m0.shape[0], label, fontsize=text_fontsize, color='g') ax2.set_xticklabels([]) ax2.set_yticklabels([]) ax2.set_xticks([]) ax2.set_yticks([]) ax2.set_aspect('equal') ax3 = fig3.add_subplot(gs3[figcounter]) im3 = ax3.imshow(max_sub.value, vmin=-10, vmax=vmax_max, cmap=pl.cm.bone_r, interpolation='nearest', origin='lower') # add a contour to show the regions that are "saturated" above T_max if contourlevels is None: contourlevels = [vmax_max, 300, 400, 500] qcs = ax3.contour(max_sub.value, levels=contourlevels, colors=['r', 'g', 'b', 'y']) #print("levels: {0} = {1}".format(qcs.levels, contourlevels)) ax3.text(3, 0.87 * m0.shape[0], label, fontsize=text_fontsize, color='r') ax3.set_xticklabels([]) ax3.set_yticklabels([]) ax3.set_xticks([]) ax3.set_yticks([]) ax3.set_aspect('equal') ax5 = fig5.add_subplot(gs5[figcounter]) im5 = ax5.imshow(max.value, vmin=-10, vmax=vmax_max, cmap=pl.cm.bone_r, interpolation='nearest', origin='lower') # add a contour to show the regions that are "saturated" above T_max qcs = ax5.contour(max.value, levels=contourlevels, colors=['r', 'g', 'b', 'y']) if False: # debug print("levels: {0} = {1}".format(qcs.levels, contourlevels)) ax5.text(3, 0.87 * m0.shape[0], label, fontsize=text_fontsize, color='r') ax5.set_xticklabels([]) ax5.set_yticklabels([]) ax5.set_xticks([]) ax5.set_yticks([]) ax5.set_aspect('equal') ax4 = fig4.add_subplot(gs4[figcounter]) im4 = ax4.imshow(madstd.value, cmap=pl.cm.bone_r, interpolation='nearest', origin='lower') ax4.text(3, 0.87 * m0.shape[0], label, fontsize=text_fontsize, color='r') ax4.set_xticklabels([]) ax4.set_yticklabels([]) ax4.set_xticks([]) ax4.set_yticks([]) ax4.set_aspect('equal') ax6 = fig6.add_subplot(gs6[figcounter]) im6 = ax6.imshow((m2**0.5).to(u.km / u.s).value * SIGMA2FWHM, vmin=0, vmax=15, cmap='viridis', interpolation='nearest', origin='lower') ax6.text(3, 0.87 * m0.shape[0], label, fontsize=text_fontsize, color='k') ax6.set_xticklabels([]) ax6.set_yticklabels([]) ax6.set_xticks([]) ax6.set_yticks([]) ax6.set_aspect('equal') figcounter += 1 # add a continuum image to the 'max' plots # ax5 = fig5.add_subplot(gs5[figcounter]) if figcounter != nplots - 1: log.critical("Figcounter={0} but nplots={1}".format( figcounter, nplots)) ax5 = fig5.add_subplot(gs5[nplots - 1]) ax5.cla() cont = get_cont(maxfh.header) im5 = ax5.imshow(cont.value, vmin=-10, vmax=vmax_max, cmap=pl.cm.bone_r, interpolation='nearest', origin='lower') # add a contour to show the regions that are "saturated" above T_max ax5.contour(cont.value, levels=contourlevels, colors=['r', 'g', 'b', 'y']) ax5.text(3, 0.87 * m0.shape[0], 'Continuum', fontsize=text_fontsize, color='r') ax5.set_xticklabels([]) ax5.set_yticklabels([]) ax5.set_aspect('equal') cbs = {} for ii, fig, im, gs in ( (1, fig1, im1, gs1), (2, fig2, im2, gs2), (3, fig3, im3, gs3), (4, fig4, im4, gs4), (5, fig5, im5, gs5), (6, fig6, im6, gs6), ): bottom, top, left, right = gs.get_grid_positions(fig) cbar_ax = fig.add_axes([ np.max(right) + 0.01, np.min(bottom), 0.05, np.max(top) - np.min(bottom) ]) cbs[ii] = pl.colorbar(mappable=im, cax=cbar_ax) cbs[ii].ax.tick_params(labelsize=12) cbs[1].set_label("Flux Density (K km s$^{-1}$)", fontsize=12) cbs[2].set_label("Velocity (km s$^{-1}$)", fontsize=12) cbs[3].set_label("Peak Brightness (K)", fontsize=12) cbs[5].set_label("Peak Brightness (K)", fontsize=12) cbs[4].set_label("MAD StdDev (K)", fontsize=12) cbs[6].set_label("Velocity Dispersion (km s$^{-1}$)", fontsize=12) pl.draw() pl.show() fig1.savefig(paths.fpath("chemical_m0_slabs_{0}{1}.{2}".format( sourcename, suffix, filetype)), bbox_inches='tight', dpi=300) fig2.savefig(paths.fpath("chemical_m1_slabs_{0}{1}.{2}".format( sourcename, suffix, filetype)), bbox_inches='tight', dpi=300) fig3.savefig(paths.fpath("chemical_max_contsub_slabs_{0}{1}.{2}".format( sourcename, suffix, filetype)), bbox_inches='tight', dpi=300) fig4.savefig(paths.fpath("chemical_madstd_slabs_{0}{1}.{2}".format( sourcename, suffix, filetype)), bbox_inches='tight', dpi=300) fig5.savefig(paths.fpath("chemical_max_slabs_{0}{1}.{2}".format( sourcename, suffix, filetype)), bbox_inches='tight', dpi=300) fig6.savefig(paths.fpath("chemical_m2_slabs_{0}{1}.{2}".format( sourcename, suffix, filetype)), bbox_inches='tight', dpi=300)
slices[1], slices[2]] hdul.flush() if debug_mode: log.setLevel(lvl) if __name__ == "__main__": for robust in (0, 2): for spw in (0, 1, 2, 3): mxind = get_max_ind( 'piece_of_full_SgrB2_TETC7m_r{1}_cube.spw{0}.channels*fits'. format(spw, robust)) if mxind < min_nchans: log.critical("Skipping {0}:{1} b/c only {2} chans".format( robust, spw, mxind)) continue nchans_total[spw] = mxind log.info("nchans_total[{0},{1}] = {2}".format(spw, robust, mxind)) if os.path.exists( 'piece_of_full_SgrB2_TETC7m_r{1}_cube.spw{0}.channels0to75.image.pbcor.fits' .format(spw, robust)): make_spw_cube( spw='spw{0}', spwnum=spw, fntemplate='full_SgrB2_TETC7m_r{0}'.format(robust), overwrite_existing=False, bmaj_limits=None, fnsuffix="",
def fits2bitmap(filename, ext=0, out_fn=None, stretch='linear', power=1.0, asinh_a=0.1, min_cut=None, max_cut=None, min_percent=None, max_percent=None, percent=None, cmap='Greys_r'): """ Create a bitmap file from a FITS image, applying a stretching transform between minimum and maximum cut levels and a matplotlib colormap. Parameters ---------- filename : str The filename of the FITS file. ext : int FITS extension name or number of the image to convert. The default is 0. out_fn : str The filename of the output bitmap image. The type of bitmap is determined by the filename extension (e.g. '.jpg', '.png'). The default is a PNG file with the same name as the FITS file. stretch : {{'linear', 'sqrt', 'power', log', 'asinh'}} The stretching function to apply to the image. The default is 'linear'. power : float, optional The power index for ``stretch='power'``. The default is 1.0. asinh_a : float, optional For ``stretch='asinh'``, the value where the asinh curve transitions from linear to logarithmic behavior, expressed as a fraction of the normalized image. Must be in the range between 0 and 1. The default is 0.1. min_cut : float, optional The pixel value of the minimum cut level. Data values less than ``min_cut`` will set to ``min_cut`` before stretching the image. The default is the image minimum. ``min_cut`` overrides ``min_percent``. max_cut : float, optional The pixel value of the maximum cut level. Data values greater than ``min_cut`` will set to ``min_cut`` before stretching the image. The default is the image maximum. ``max_cut`` overrides ``max_percent``. min_percent : float, optional The percentile value used to determine the pixel value of minimum cut level. The default is 0.0. ``min_percent`` overrides ``percent``. max_percent : float, optional The percentile value used to determine the pixel value of maximum cut level. The default is 100.0. ``max_percent`` overrides ``percent``. percent : float, optional The percentage of the image values used to determine the pixel values of the minimum and maximum cut levels. The lower cut level will set at the ``(100 - percent) / 2`` percentile, while the upper cut level will be set at the ``(100 + percent) / 2`` percentile. The default is 100.0. ``percent`` is ignored if either ``min_percent`` or ``max_percent`` is input. cmap : str The matplotlib color map name. The default is 'Greys_r'. """ import matplotlib import matplotlib.cm as cm import matplotlib.image as mimg # __main__ gives ext as a string try: ext = int(ext) except ValueError: pass try: image = getdata(filename, ext) except Exception as e: log.critical(e) return 1 if image.ndim != 2: log.critical('data in FITS extension {0} is not a 2D array' .format(ext)) if out_fn is None: out_fn = os.path.splitext(filename)[0] if out_fn.endswith('.fits'): out_fn = os.path.splitext(out_fn)[0] out_fn += '.png' # need to explicitly define the output format due to a bug in # matplotlib (<= 2.1), otherwise the format will always be PNG out_format = os.path.splitext(out_fn)[1][1:] # workaround for matplotlib 2.0.0 bug where png images are inverted # (mpl-#7656) if (out_format.lower() == 'png' and LooseVersion(matplotlib.__version__) == LooseVersion('2.0.0')): image = image[::-1] if cmap not in cm.datad: log.critical('{0} is not a valid matplotlib colormap name.' .format(cmap)) return 1 norm = simple_norm(image, stretch=stretch, power=power, asinh_a=asinh_a, min_cut=min_cut, max_cut=max_cut, min_percent=min_percent, max_percent=max_percent, percent=percent) mimg.imsave(out_fn, norm(image), cmap=cmap, origin='lower', format=out_format) log.info('Saved file to {0}.'.format(out_fn))
def fits2bitmap(filename, exten=0, out_fn=None, scale='linear', power=1.0, asinh_a=0.1, min_cut=None, max_cut=None, min_percent=None, max_percent=None, percent=None, cmap='Greys_r'): """ Create a bitmap file from a FITS image, applying a scaling/stretching transform between minimum and maximum cut levels and a matplotlib colormap. Parameters ---------- filename : str The filename of the FITS file. exten : int FITS extension number of the image to convert. The default is 0. out_fn : str The filename of the output bitmap image. The type of bitmap is determined by the filename extension (e.g. '.jpg', '.png'). The default is a PNG file with the same name as the FITS file. scale : {{'linear', 'sqrt', 'power', log', 'asinh'}} The scaling/stretch function to apply to the image. The default is 'linear'. power : float, optional The power index for ``scale='power'`` image scaling. The default is 1.0. asinh_a : float, optional For ``scale='asinh'`` image scaling, the value where the asinh curve transitions from linear to logarithmic behavior, expressed as a fraction of the normalized image. Must be in the range between 0 and 1. min_cut : float, optional The pixel value of the minimum cut level. Data values less than ``min_cut`` will set to ``min_cut`` before scaling the image. The default is the image minimum. ``min_cut`` overrides ``min_percent``. max_cut : float, optional The pixel value of the maximum cut level. Data values greater than ``min_cut`` will set to ``min_cut`` before scaling the image. The default is the image maximum. ``max_cut`` overrides ``max_percent``. min_percent : float, optional The percentile value used to determine the pixel value of minimum cut level. The default is 0.0. ``min_percent`` overrides ``percent``. max_percent : float, optional The percentile value used to determine the pixel value of maximum cut level. The default is 100.0. ``max_percent`` overrides ``percent``. percent : float, optional The percentage of the image values used to determine the pixel values of the minimum and maximum cut levels. The lower cut level will set at the ``(100 - percent) / 2`` percentile, while the upper cut level will be set at the ``(100 + percent) / 2`` percentile. The default is 100.0. ``percent`` is ignored if either ``min_percent`` or ``max_percent`` is input. cmap : str The matplotlib color map name. The default is 'Greys_r'. """ hdulist = fits.open(filename) image = hdulist[exten].data hdulist.close() if out_fn is None: out_fn = filename.replace('.fits', '.png') if cmap not in cm.datad.keys(): log.critical('{0} is not a valid matplotlib colormap ' 'name'.format(cmap)) raise SystemExit() image_scaled = scale_image(image, scale=scale, power=power, asinh_a=asinh_a, min_cut=min_cut, max_cut=max_cut, min_percent=min_percent, max_percent=max_percent, percent=percent) mimg.imsave(out_fn, image_scaled, cmap=cmap) log.info('Saved file to {0}'.format(out_fn)) return