def plot_sources(self, data, centroids, vmin=0, vmax=1000, radius=3, color='red', ax=None): """Draw apertures at each position (x_pos[i], y_pos[i]) Parameters ---------- data centroid radius color ax Returns ------- """ m_interval = ManualInterval(vmin=vmin, vmax=vmax) norm = ImageNormalize(data, stretch=LogStretch(), interval=m_interval) if ax is None: fig, ax = plt.subplots(nrows=1, ncols=1) ax.grid(False) ax.imshow(data, norm=norm, cmap='gray', origin='lower') for xy in centroids: aperture = self.mk_aperture(xy, radius, color) ax.add_patch(aperture) return ax
def convert_to_valid_color( image_color: np.ndarray, clip: bool = False, lower_clip: float = 0.0, upper_clip: float = 1.0, normalize: bool = False, scaling: Optional[str] = None, simple_norm: bool = False, ) -> np.ndarray: """ Convert the channel to a valid 0-1 range for RGB images """ if simple_norm: interval = MinMaxInterval() norm = ImageNormalize() return norm(interval(image_color)) if clip: image_color = np.clip(image_color, lower_clip, upper_clip) if normalize: interval = ManualInterval(lower_clip, upper_clip) else: interval = MinMaxInterval() if scaling == "sqrt": stretch = SqrtStretch() image_color = stretch(interval(image_color)) else: norm = ImageNormalize() image_color = norm(interval(image_color)) return image_color
def _plotbutton_inverted_individual_fired(self): try: self.data except: self.status_string_right = "No fits file loaded yet!" return self.data_scaled = ( scaling_fns[self.image_scale]() + ManualInterval(vmin=self.datamin, vmax=self.datamax))(self.data) self.image_greyRGB = ski_color.gray2rgb( adjust_gamma(self.data_scaled, self.gamma)) self.image_colorRGB = colorize_image(self.image_greyRGB, hexinv(self.imagecolor), colorintype='hex', gammacorr_color=self.gamma) #self.image_axesimage.set_data(1.-self.image_colorRGB**(1./self.gamma)) self.image_axesimage.set_data( combine_multicolor([ self.image_colorRGB, ], gamma=self.gamma, inverse=True)) self.percent_min = np.round( percentileofscore(self.data.ravel(), self.datamin, kind='strict'), 2) self.percent_max = np.round( percentileofscore(self.data.ravel(), self.datamax, kind='strict'), 2) self.in_use = True self.image_figure.canvas.draw() self.status_string_right = "Plot updated"
def plot_segmap(self, img_data, segmap, centroids=None, ax1=None, ax2=None, vmin=None, vmax=None, units=None, fs=10): """ Plot segmentation map returned by SExtractor Parameters ---------- img_data segmap centroids ax1 ax2 vmin vmax units fs Returns ------- """ if vmin is not None and vmax is not None: interval = ManualInterval(vmin=vmin, vmax=vmax) else: interval = ZScaleInterval() norm = ImageNormalize(img_data, stretch=LinearStretch(), interval=interval) segm_cmap = self.rand_cmap(np.max(segmap)) self._segm_cmap = segm_cmap if ax1 is None or ax2 is None: fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, sharex=True, sharey=True) else: fig = ax1.get_figure() im1 = ax1.imshow(img_data, norm=norm, cmap='gray', origin='lower') divider = make_axes_locatable(ax1) cax = divider.append_axes('right', size='5%', pad=0.05) cbar = fig.colorbar(im1, cax=cax, orientation='vertical') cbar.set_label(units, fontsize=fs) im2 = ax2.imshow(segmap, cmap=self.segm_cmap, origin='lower') if centroids is not None: for xy in centroids: aperture = self.mk_aperture(xy, r=3, c='red') ax1.add_patch(aperture) return fig, ax1, ax2
def manual_int(self): self.interval = ManualInterval(self.v_min, self.v_max) self.rbtn5.setChecked(True) self.rbtn6.setChecked(False) self.rbtn7.setChecked(False) self.rbtn8.setChecked(False) self.rbtn9.setChecked(False) main.refresh_norm() print('v_min, v_max = ' + str(self.v_min) + ', ' + str(self.v_max))
def _percent_max_changed(self): self.datamax = np.nanpercentile(self.data, self.percent_max) self.data_scaled = ( scaling_fns[self.image_scale]() + ManualInterval(vmin=self.datamin, vmax=self.datamax))(self.data) self.image_greyRGB = ski_color.gray2rgb( adjust_gamma(self.data_scaled, self.gamma)) self.image_colorRGB = colorize_image(self.image_greyRGB, self.imagecolor, colorintype='hex', gammacorr_color=self.gamma) self.image_axesimage.set_data(self.image_colorRGB**(1. / self.gamma)) self.image_figure.canvas.draw() self.status_string_right = "Updated scale using percentiles"
def _scale_dropdown_changed(self): self.image_scale = self.scale_dropdown #self.norm=ImageNormalize(self.sregion,stretch=scaling_fns[self.image_scale]() ) self.data_scaled = ( scaling_fns[self.image_scale]() + ManualInterval(vmin=self.datamin, vmax=self.datamax))(self.data) #*** Instead, should I just integrate my imscale class here instead of astropy? ... self.image_greyRGB = ski_color.gray2rgb( adjust_gamma(self.data_scaled, self.gamma)) self.image_colorRGB = colorize_image(self.image_greyRGB, self.imagecolor, colorintype='hex', gammacorr_color=self.gamma) self.image_axesimage.set_data(self.image_colorRGB**(1. / self.gamma)) self.in_use = True self.image_figure.canvas.draw() self.status_string_right = 'Image scale function changed to ' + self.image_scale
def _plotbutton_individual_fired(self): try: self.data except: self.status_string_right = "No fits file loaded yet!" return #self.image=self.data ###Using this command is preferable, as long as the projection doesn't need to be updated... # The home zoom button will work, but no WCS labels because projection wasn't set during init. #Scale the data to [0,1] range self.data_scaled = ( scaling_fns[self.image_scale]() + ManualInterval(vmin=self.datamin, vmax=self.datamax))(self.data) #Convert scale[0,1] image to greyscale RGB image self.image_greyRGB = ski_color.gray2rgb( adjust_gamma(self.data_scaled, self.gamma)) self.image_colorRGB = colorize_image(self.image_greyRGB, self.imagecolor, colorintype='hex', gammacorr_color=self.gamma) self.image_axesimage.set_data(self.image_colorRGB**(1. / self.gamma)) ###Using this set instead properly updates the axes labels to WCS, but the home zoom button won't work #self.image_figure.clf() #self.image_axes = self.image_figure.add_subplot(111,aspect=1)#,projection=self.wcs) #self.image_axesimage = self.image_axes.imshow(self.image, cmap=self.image_cmap,origin='lower',interpolation='nearest', norm=self.norm) self.percent_min = np.round( percentileofscore(self.data.ravel(), self.datamin, kind='strict'), 2) self.percent_max = np.round( percentileofscore(self.data.ravel(), self.datamax, kind='strict'), 2) self.in_use = True #self.update_radecpars() self.image_figure.canvas.draw() self.status_string_right = "Plot updated"
print("Input has {0} out of {1} matches to the observed leaves within 1 arcsec" .format((orig_to_obs['sep'] < 1*u.arcsec).sum(), len(pruned_orig_ppcat))) pruned_ppcat.add_column(Column(data=orig_to_obs['inds'], name='match_inds')) pruned_ppcat.add_column(Column(data=orig_to_obs['sep'], name='match_separation')) temporary = pruned_orig_ppcat[pruned_ppcat['match_inds']] merged_orig_onto_obs = table.hstack([pruned_ppcat, temporary]) # ds9 -multiframe ../analysis/*perseus*.fits ../perseus_synth/perseus_250_2_model_tclean_clean_noise.fits -lock frames image -frame 2 -scale minmax -cmap sls -frame 3 -frame delete -frame 7 -frame delete -frame 6 -cmap sls -frame 8 -cmap sls -frame 4 -cmap sls -frame 5 -cmap value 8.5 0.05 -frame 9 -cmap value 12 0.03 -frame 1 -cmap value 8.5 0.05 -lock crosshairs image & import pylab as pl from astropy.visualization import (MinMaxInterval, ManualInterval, AsinhStretch, ImageNormalize) norm = ImageNormalize(data_original, interval=ManualInterval(-0.002,0.03), stretch=AsinhStretch()) fig = pl.figure(1) fig.clf() ax = fig.add_axes([0.15, 0.1, 0.8, 0.8], projection=mywcs) ax.imshow(data_original, cmap='gray_r', origin='lower', interpolation='none', norm=norm) ax.plot(orig_ppcat['x_cen'], orig_ppcat['y_cen'], 'o', markeredgecolor='r', markerfacecolor='none', transform=ax.get_transform('world')) ra = ax.coords['ra'] ra.set_major_formatter('hh:mm:ss.s') dec = ax.coords['dec'] ra.set_axislabel("RA (J2000)", fontsize=pl.rcParams['axes.labelsize']) dec.set_axislabel("Dec (J2000)", fontsize=pl.rcParams['axes.labelsize'], minpad=0.0) ra.set_ticks(exclude_overlapping=True) dec.set_ticks(exclude_overlapping=True)
def kde2D_plot(self, parameter1, parameter2, normtype='log', interval=None, xlim=None, ylim=None, gridsize=100): """Generate a 2D KDE for the given parameters. Parameters ---------- parameter1 : `numpy.array` X-axis variable parameter2 : `numpy.array` Y-axis variable normtype : {'log', 'linear', 'sqrt'} Normalization type to apply to the data interval : tuple Limits of the interval to use when computing the image scaling xlim : tuple X-limits to use for the plot and the KDE grid ylim : tuple Y-limits to use for the plot and the KDE grid gridsize : int Step-size for the grid Returns ------- fig : :py:class:`matplotlib.figure.Figure` ax : :py:class:`matplotlib.axes.Axes` surface : numpy.array The KDE surface plot """ data = np.vstack([parameter1, parameter2]) if xlim is None: xlim = (np.min(parameter1), np.max(parameter1)) if ylim is None: ylim = (np.min(parameter2), np.max(parameter2)) # Generate a grid to compute the KDE over xgrid = np.linspace(xlim[0], xlim[1], gridsize) ygrid = np.linspace(ylim[0], ylim[1], gridsize) kde = gaussian_kde(data) Xgrid, Ygrid = np.meshgrid(xgrid, ygrid) surface = kde.evaluate(np.vstack([Xgrid.ravel(), Ygrid.ravel()])) if isinstance(interval, tuple): Interval = ManualInterval(vmin=interval[0], vmax=interval[1]) else: Interval = ZScaleInterval() norm = ImageNormalize(surface, stretch=self.image_norms[normtype], interval=Interval) fig, ax = self.mk_fig(nrows=1, ncols=1) ax.imshow(surface.reshape(Xgrid.shape), norm=norm, cmap='gray', origin='lower', aspect='auto', extent=[xgrid.min(), xgrid.max(), ygrid.min(), ygrid.max()]) return fig, ax, surface
def _plot_fits(self): """Plot all the fits. """ # Make axis box stand out as viridis can be dark. matplotlib.rc('axes', edgecolor='r') # Hand-tuning suggests a linear scale between the # min max of these stars is the best. Global limits or # percentile limits tend to saturate out the stars. ##pct_interval = AsymmetricPercentileInterval(0.10, 99.9) valmin = self._init_bglvl valmax = np.amax(self._fit_table['peak_adu']) minmax_interval = ManualInterval(vmin=valmin, vmax=valmax) norm_func = ImageNormalize(self._img_data, interval=minmax_interval, stretch=AsinhStretch()) ##norm_func = ImageNormalize(self._img_data, ## interval=pct_interval, ## stretch=SqrtStretch()) # May be overly agressive for subplots ##norm_func = ImageNormalize(self._img_data, ## interval=pct_interval, ## stretch=AsinhStretch()) # Location of text label added internal to subplots, in # normalized 0:1 coordinate. This is where the bottom left # the text box will appear. text_x = 0.2 text_y = 0.8 region_list = ['TL', 'TR', 'CN', 'BR', 'BL'] region_row_dict = {'TL': 0, 'TR': 1, 'CN': 2, 'BR': 3, 'BL': 4} # Create a dictionary that has keys of the row index within # _fit_table (also the first index of the _pixel_array) # and the column index within the 2-D plotting array. # # This is necessary because there may be less that _num_per_reg # stars per region. # # This is inelegant but should work. num_stars = len(self._fit_table) star_col_dict = {} # To fill col_idx_dict = { 'CN': 0, # working memory 'TL': 0, 'TR': 0, 'BL': 0, 'BR': 0 } for idx in range(num_stars): this_reg = self._fit_table['region'][idx] this_col_idx = col_idx_dict[this_reg] star_col_dict[idx] = this_col_idx new_col_idx = this_col_idx + 1 col_idx_dict[this_reg] = new_col_idx # Create figure for plot fig_rows = len(region_list) fig_cols = self._num_per_reg # List of handles to the images plt_imgs = [] fig, ax_arr = plt.subplots(nrows=fig_rows, ncols=fig_cols, sharex=True, sharey=True) (median_fwhm, madstd_fwhm, npts) = self.median_fwhm('both') title = 'Star PSF measurements using 2-D Gaussian fits' if self._plot_title is not None: title = self._plot_title title += f'\nMedian FWHM={median_fwhm:.2f} +/- {madstd_fwhm:.2f} (MAD stddev) pixels' fig.suptitle(title, fontsize=7) for idx in range(num_stars): this_reg = self._fit_table['region'][idx] row_idx = region_row_dict[this_reg] col_idx = star_col_dict[idx] # Plot the cutout image. cut_out = self._pixel_array[idx] plt_imgs.append(ax_arr[row_idx, col_idx].imshow(cut_out, origin='lower', norm=norm_func)) # Titles, fit info etc title_str = self._get_subplot_title(idx) fitinfo_str = self._get_subplot_fitinfo(idx) ax_arr[row_idx, col_idx].set_title(title_str, fontsize=4, pad=3) ax_arr[row_idx, col_idx].text(text_x, text_y, fitinfo_str, fontsize=3, color='w') #ax_arr[row_idx, col_idx].set_xlabel('X-axis (pixels)', fontsize=6) ax_arr[row_idx, col_idx].set_ylabel(this_reg, fontsize=6) # Get artists related to best-fit parameters artist_list = self._get_fit_artists(idx) if len(artist_list) > 0: for art in artist_list: ax_arr[row_idx, col_idx].add_artist(art) # Only show tick values on outer edge of grid. for ax in ax_arr.flat: ax.tick_params(axis='both', labelsize=4, direction='in', color='r', length=3) ax.label_outer() plt.savefig(self._fwhm_plot, dpi=200, quality=95, optimize=True, bbox_inches='tight') self._logger.info( f'Plotted star FWHM fit cut-outs to {self._fwhm_plot}') return
beam_pix = hdr['BMAJ']/hdr['CDELT2'] # crop the plotted PSF region in offset from center if args.crop_offset: crop_arcsec = args.crop_offset crop_pix = crop_arcsec/3600/hdr['CDELT2'] else: crop_arcsec= np.max([x_off_arcsec,y_off_arcsec]) crop_pix = np.max([x_off,y_off]) crop_suff = '_'+str(np.round(crop_arcsec,1))+'arcsec' # plot the PSF image plt.figure(1) plt.clf() norm=ImageNormalize(psf,stretch=LogStretch(),interval=ManualInterval(vmin=0,vmax=1)) plt.imshow(psf,origin='lower',norm=norm,cmap='gray_r') plt.colorbar() plt.xlim(left=xcen-crop_pix,right=xcen+crop_pix) plt.ylim(bottom=ycen-crop_pix,top=ycen+crop_pix) plt.savefig(save_path+crop_suff+'_image.pdf',bbox_inches='tight',metadata={'Creator':this_script}) plt.plot([xcen-crop_pix,xcen+crop_pix],[ycen,ycen],linestyle='-',lw=1.0) plt.plot([xcen,xcen],[ycen-crop_pix,ycen+crop_pix],linestyle='--',lw=1.0) plt.plot([xcen-crop_pix,xcen+crop_pix],[ycen-crop_pix,ycen+crop_pix],linestyle='-.',lw=1.0) plt.plot([xcen-crop_pix,xcen+crop_pix],[ycen+crop_pix,ycen-crop_pix],linestyle=':',lw=1.0) plt.savefig(save_path+crop_suff+'_image_slices.pdf',bbox_inches='tight',metadata={'Creator':this_script}) plt.close() #make a second x-axis on the top in pix def arcsec2pix(x): return x/3600/hdr['CDELT2']
def __call__(self, bounds=None): img = None visible_layers = 0 for uuid in sorted(self.layers, key=lambda x: self.layers[x]['zorder']): layer = self.layers[uuid] if not layer['visible']: continue interval = ManualInterval(*layer['clim']) contrast_bias = ContrastBiasStretch(layer['contrast'], layer['bias']) if callable(layer['array']): array = layer['array'](bounds=bounds) else: array = layer['array'] if array is None: continue if np.isscalar(array): scalar = True array = np.atleast_2d(array) else: scalar = False data = STRETCHES[layer['stretch']]()(contrast_bias( interval(array))) if isinstance(layer['color'], Colormap): if img is None: img = np.ones(data.shape + (4, )) # Compute colormapped image plane = layer['color'](data) alpha_plane = layer['alpha'] * plane[:, :, 3] # Use traditional alpha compositing plane[:, :, 0] = plane[:, :, 0] * alpha_plane plane[:, :, 1] = plane[:, :, 1] * alpha_plane plane[:, :, 2] = plane[:, :, 2] * alpha_plane img[:, :, 0] *= (1 - alpha_plane) img[:, :, 1] *= (1 - alpha_plane) img[:, :, 2] *= (1 - alpha_plane) img[:, :, 3] = 1 else: if img is None: img = np.zeros(data.shape + (4, )) # Get color and pre-multiply by alpha values color = COLOR_CONVERTER.to_rgba_array(layer['color'])[0] color *= layer['alpha'] # We should treat NaN values as zero (post-stretch), which means # that those pixels don't contribute towards the final image. reset = np.isnan(data) if np.any(reset): data[reset] = 0. plane = data[:, :, np.newaxis] * color plane[:, :, 3] = 1 visible_layers += 1 if scalar: plane = plane[0, 0] img += plane if img is None: return None else: img = np.clip(img, 0, 1) return img
# if not os.path.isfile('{}/images/image_filtered_low_clean.fits'.format(odf_dir)): # fits_image = '{}/images/image_filtered_low.fits'.format(odf_dir) # else: # fits_image = '{}/images/image_filtered_low_clean.fits'.format(odf_dir) hdu = fits.open(fits_image) wcs = WCS(hdu[0].header) g2_kernel = Gaussian2DKernel(2) smoothed_data_g2 = convolve(hdu[0].data, g2_kernel, mask=np.logical_not(detmask.data)) * detmask.data fig = plt.figure(figsize=(10, 10), dpi=100) pp = 99.9 # colour cut percentage ax = fig.add_subplot(111, projection=wcs) #ax.set_title("Gaussian smoothed image") norm_xmm = ImageNormalize(smoothed_data_g2, interval=ManualInterval(vmin=0.01, vmax=100.0), stretch=LogStretch()) # norm_xmm = ImageNormalize(smoothed_data_g2,interval=PercentileInterval(pp), stretch=AsinhStretch()) ax.imshow(smoothed_data_g2, cmap=plt.cm.hot, norm=norm_xmm, origin='lower', interpolation='nearest') ax.xlabel = 'RA' ax.ylabel = 'Dec' ax.set_xlabel('RA') ax.set_ylabel('DEC') # # only show the last aperture # circle_sky = CircleSkyRegion(center=center, radius=r_end) pix_reg = circle_sky.to_pixel(wcs) pix_reg.plot(ax=ax, edgecolor='yellow') plt.savefig('/home/aaranda/tfm/results_v2/{}/{}/smoothed_g2_image_low.png'.format(target, obsid)) plt.close(fig)
wcs_det = WCS(detmask.header) fits_image = '{}/images/image_filtered_high.fits'.format(odf_dir) hdu = fits.open(fits_image) wcs = WCS(hdu[0].header) g2_kernel = Gaussian2DKernel(2) smoothed_data_g2 = convolve( hdu[0].data, g2_kernel, mask=np.logical_not( detmask.data)) * detmask.data fig = plt.figure(figsize=(10, 10), dpi=100) pp = 99.9 # colour cut percentage ax = fig.add_subplot(111, projection=wcs) #ax.set_title("Gaussian smoothed image") norm_xmm = ImageNormalize(smoothed_data_g2, interval=ManualInterval(vmin=0.01, vmax=100.0), stretch=LogStretch()) # norm_xmm = ImageNormalize(smoothed_data_g2,interval=PercentileInterval(pp), stretch=AsinhStretch()) ax.imshow(smoothed_data_g2, cmap=plt.cm.hot, norm=norm_xmm, origin='lower', interpolation='nearest') ax.xlabel = 'RA' ax.ylabel = 'Dec' ax.set_xlabel('RA') ax.set_ylabel('DEC') # # only show the last aperture # circle_sky = CircleSkyRegion(center=center, radius=r_end)
def as_array(self, interval_r=AsymmetricPercentileInterval(2.5, 99.0), interval_g=AsymmetricPercentileInterval(5., 99.2), interval_b=AsymmetricPercentileInterval(10., 99.2)): """Returns the colour image as a MxNx3 (RGB) array.""" # First we determine the shifts cx, cy = 2050, 1024 # central coordinates of the image maxshiftx, maxshifty = 0, 0 aligned_imgs = {} for idx, band in enumerate(self.filenames.keys()): fn = self.filenames[band] hdu = fits.open(os.path.join(VPHAS_DATA_PATH, fn))[self.ccd] wcs = WCS(hdu.header) img = hdu.data if idx == 0: # The first image acts as reference cra, cdec = wcs.wcs_pix2world(cx, cy, 1) else: # For all subsequent images, compute the shift using the WCS refx, refy = wcs.wcs_world2pix(cra, cdec, 1) shiftx = int(refx - cx) shifty = int(refy - cy) # Now apply the required shift to the image if shiftx > 0: img = np.pad(img, ((0, 0), (0, shiftx)), mode=str('constant'))[:, shiftx:] elif shiftx < 0: img = np.pad(img, ((0, 0), (-shiftx, 0)), mode=str('constant'))[:, :shiftx] if shifty > 0: img = np.pad(img, ((0, shifty), (0, 0)), mode=str('constant'))[shifty:, :] elif shifty < 0: img = np.pad(img, ((-shifty, 0), (0, 0)), mode=str('constant'))[:shifty, :] # The maximum shift applied will determine the final img shape maxshiftx = max(abs(shiftx), maxshiftx) maxshifty = max(abs(shifty), maxshifty) aligned_imgs[band] = img if maxshiftx > cx or maxshifty > cy: raise VphasDataException('{0}-{1}: bands do not overlap'.format( self.offset, self.ccd)) # New stretch, scale, and stack the data into an MxNx3 array r = aligned_imgs['i'] + aligned_imgs['ha'] g = aligned_imgs['g'] + aligned_imgs['r'] + aligned_imgs['r2'] b = aligned_imgs['u'] + 2 * aligned_imgs['g'] r, g, b = 1.5 * r, 0.8 * g, 2.2 * b vmin_r, vmax_r = np.percentile(r, [1., 99.5]) vmin_g, vmax_g = np.percentile(g, [5., 99.5]) vmin_b, vmax_b = np.percentile(b, [10., 99.5]) #log.info((vmin_r, vmin_g, vmin_b)) #log.info((vmax_r, vmax_g, vmax_b)) #if vmin_b < 100: # vmin_b = 100 minrange = np.max( (1250., vmax_g - vmin_g, vmax_g - vmin_g, vmax_b - vmin_b)) if (vmax_r - vmin_r) < minrange: vmax_r = vmin_r + minrange if (vmax_g - vmin_g) < minrange: vmax_g = vmin_g + minrange if (vmax_b - vmin_b) < minrange: vmax_b = vmin_b + minrange interval_r = ManualInterval(vmin_r, vmax_r) interval_g = ManualInterval(vmin_g, vmax_g) interval_b = ManualInterval(vmin_b, vmax_b) r = interval_r(r) g = interval_g(g) b = interval_b(b) stacked = np.dstack((r[maxshifty:-maxshifty, maxshiftx:-maxshiftx], g[maxshifty:-maxshifty, maxshiftx:-maxshiftx], b[maxshifty:-maxshifty, maxshiftx:-maxshiftx])) return LuptonColorStretch()(stacked)
def __getitem__(self, view): img = None visible_layers = 0 for uuid in sorted(self.layers, key=lambda x: self.layers[x]['zorder']): layer = self.layers[uuid] if not layer['visible']: continue interval = ManualInterval(*layer['clim']) contrast_bias = ContrastBiasStretch(layer['contrast'], layer['bias']) if callable(layer['array']): array = layer['array'](view=view) else: array = layer['array'] if array is None: continue if not callable(layer['array']): array = array[view] if np.isscalar(array): scalar = True array = np.atleast_2d(array) else: scalar = False data = STRETCHES[layer['stretch']]()(contrast_bias(interval(array))) if isinstance(layer['color'], Colormap): if img is None: img = np.ones(data.shape + (4,)) # Compute colormapped image plane = layer['color'](data) alpha_plane = layer['alpha'] * plane[:, :, 3] # Use traditional alpha compositing plane[:, :, 0] = plane[:, :, 0] * alpha_plane plane[:, :, 1] = plane[:, :, 1] * alpha_plane plane[:, :, 2] = plane[:, :, 2] * alpha_plane img[:, :, 0] *= (1 - alpha_plane) img[:, :, 1] *= (1 - alpha_plane) img[:, :, 2] *= (1 - alpha_plane) img[:, :, 3] = 1 else: if img is None: img = np.zeros(data.shape + (4,)) # Get color and pre-multiply by alpha values color = COLOR_CONVERTER.to_rgba_array(layer['color'])[0] color *= layer['alpha'] plane = data[:, :, np.newaxis] * color plane[:, :, 3] = 1 visible_layers += 1 if scalar: plane = plane[0, 0] img += plane if img is None: if self.shape is None: return None else: img = np.zeros(self.shape + (4,)) img = np.clip(img, 0, 1) return img
def data_to_pitch(data_array, pitch_range=[100, 10000], center_pitch=440, zero_point="median", stretch='linear', minmax_percent=None, minmax_value=None, invert=False): """ Map data array to audible pitches in the given range, and apply stretch and scaling as required. Parameters ---------- data_array : array-like Data to map to pitch values. Individual data values should be floats. pitch_range : array Optional, default [100,10000]. Range of acceptable pitches in Hz. center_pitch : float Optional, default 440. The pitch in Hz where that the the zero point of the data will be mapped to. zero_point : str or float Optional, default "median". The data value that will be mapped to the center pitch. Options are mean, median, or a specified data value (float). stretch : str Optional, default 'linear'. The stretch to apply to the data array. Valid values are: asinh, sinh, sqrt, log, linear minmax_percent : array Optional. Interval based on a keeping a specified fraction of data values (can be asymmetric) when scaling the data. The format is [lower percentile, upper percentile], where data values below the lower percentile and above the upper percentile are clipped. Only one of minmax_percent and minmax_value should be specified. minmax_value : array Optional. Interval based on user-specified data values when scaling the data array. The format is [min value, max value], where data values below the min value and above the max value are clipped. Only one of minmax_percent and minmax_value should be specified. invert : bool Optional, default False. If True the pitch array is inverted (low pitches become high and vice versa). Returns ------- response : array The normalized data array, with values in given pitch range. """ # Parsing the zero point if zero_point in ("med", "median"): zero_point = np.median(data_array) if zero_point in ("ave", "mean", "average"): zero_point = np.mean(data_array) # The center pitch cannot be >= max() pitch range, or <= min() of pitch range. # If it is, fall back to using the mean of the pitch range provided. if center_pitch <= pitch_range[0] or center_pitch >= pitch_range[1]: warnings.warn("Given center pitch is outside the pitch range, defaulting to the mean.", InputWarning) center_pitch = np.mean(pitch_range) if (data_array == zero_point).all(): # All values are the same, no more calculation needed return np.full(len(data_array), center_pitch) # Normalizing the data_array and adding the zero point (so it can go through the same transform) data_array = np.append(np.array(data_array), zero_point) # Setting up the transform with the stretch if stretch == 'asinh': transform = AsinhStretch() elif stretch == 'sinh': transform = SinhStretch() elif stretch == 'sqrt': transform = SqrtStretch() elif stretch == 'log': transform = LogStretch() elif stretch == 'linear': transform = LinearStretch() else: raise InvalidInputError("Stretch {} is not supported!".format(stretch)) # Adding the scaling to the transform if minmax_percent is not None: transform += AsymmetricPercentileInterval(*minmax_percent) if minmax_value is not None: warnings.warn("Both minmax_percent and minmax_value are set, minmax_value will be ignored.", InputWarning) elif minmax_value is not None: transform += ManualInterval(*minmax_value) else: # Default, scale the entire image range to [0,1] transform += MinMaxInterval() # Performing the transform and then putting it into the pich range pitch_array = transform(data_array) if invert: pitch_array = 1 - pitch_array zero_point = pitch_array[-1] pitch_array = pitch_array[:-1] # In rare cases, the zero-point at this stage might be 0.0. # One example is an input array of two values where the median() is the same as the # lowest of the two values. In this case, the zero-point is 0.0 and will lead to error # (divide by zero). Change to small value to avoid dividing by zero (in reality the choice # of zero-point calculation by the user was probably poor, but not in purview to mandate or # change user's choice here. May want to consider providing info back to the user about the # distribution of pitches actually used based on their sonification options in some way. if zero_point == 0.0: zero_point = 1E-6 if ((1/zero_point)*(center_pitch - pitch_range[0]) + pitch_range[0]) <= pitch_range[1]: pitch_array = (pitch_array/zero_point)*(center_pitch - pitch_range[0]) + pitch_range[0] else: pitch_array = (((pitch_array-zero_point)/(1-zero_point))*(pitch_range[1] - center_pitch) + center_pitch) return pitch_array
hdu = fits.open(filename)[0] wcs = WCS(hdu.header) TICK_FONTSIZE = 8 AXIS_FONTSIZE = 10 AXIS_WEIGHT = 'bold' import matplotlib.pyplot as plt plt.rc('font', family='serif') plt.rc('text', usetex=True) ax = plt.axes([0.1, 0.1, 0.8, 0.8], projection=wcs, adjustable='datalim') norm = ImageNormalize(hdu.data, interval=ManualInterval(22, 140), stretch=SqrtStretch()) image = ax.imshow(hdu.data, origin='lower', cmap=plt.cm.plasma, norm=norm, aspect='equal') ax.set_xlim(1700, 8200) ax.set_ylim(3300, 8500) ax.coords['ra'].set_ticks(color='black') ax.coords['dec'].set_ticks(color='black') ax.coords['ra'].set_ticklabel(size=TICK_FONTSIZE)
def data_to_pitch(data_array, pitch_range=[100, 10000], center_pitch=440, zero_point="median", stretch='linear', minmax_percent=None, minmax_value=None, invert=False): """ Map data array to audible pitches in the given range, and apply stretch and scaling as required. Parameters ---------- data_array : array-like Data to map to pitch values. Individual data values should be floats. pitch_range : array Optional, default [100,10000]. Range of acceptable pitches in Hz. center_pitch : float Optional, default 440. The pitch in Hz where that the the zero point of the data will be mapped to. zero_point : str or float Optional, default "median". The data value that will be mapped to the center pitch. Options are mean, median, or a specified data value (float). stretch : str Optional, default 'linear'. The stretch to apply to the data array. Valid values are: asinh, sinh, sqrt, log, linear minmax_percent : array Optional. Interval based on a keeping a specified fraction of data values (can be asymmetric) when scaling the data. The format is [lower percentile, upper percentile], where data values below the lower percentile and above the upper percentile are clipped. Only one of minmax_percent and minmax_value should be specified. minmax_value : array Optional. Interval based on user-specified data values when scaling the data array. The format is [min value, max value], where data values below the min value and above the max value are clipped. Only one of minmax_percent and minmax_value should be specified. invert : bool Optional, default False. If True the pitch array is inverted (low pitches become high and vice versa). Returns ------- response : array The normalized data array, with values in given pitch range. """ # Parsing the zero point if zero_point in ("med", "median"): zero_point = np.median(data_array) if zero_point in ("ave", "mean", "average"): zero_point = np.mean(data_array) if (data_array == zero_point ).all(): # All values are the same, no more calculation needed return np.full(len(data_array), zero_point) # Normalizing the data_array and adding the zero point (so it can go through the same transform) data_array = np.append(np.array(data_array), zero_point) # Setting up the transform with the stretch if stretch == 'asinh': transform = AsinhStretch() elif stretch == 'sinh': transform = SinhStretch() elif stretch == 'sqrt': transform = SqrtStretch() elif stretch == 'log': transform = LogStretch() elif stretch == 'linear': transform = LinearStretch() else: raise InvalidInputError("Stretch {} is not supported!".format(stretch)) # Adding the scaling to the transform if minmax_percent is not None: transform += AsymmetricPercentileInterval(*minmax_percent) if minmax_value is not None: warnings.warn( "Both minmax_percent and minmax_value are set, minmax_value will be ignored.", InputWarning) elif minmax_value is not None: transform += ManualInterval(*minmax_value) else: # Default, scale the entire image range to [0,1] transform += MinMaxInterval() # Performing the transform and then putting it into the pich range pitch_array = transform(data_array) if invert: pitch_array = 1 - pitch_array zero_point = pitch_array[-1] pitch_array = pitch_array[:-1] if ((1 / zero_point) * (center_pitch - pitch_range[0]) + pitch_range[0]) <= pitch_range[1]: pitch_array = (pitch_array / zero_point) * ( center_pitch - pitch_range[0]) + pitch_range[0] else: pitch_array = ( (pitch_array - zero_point) / (1 - zero_point)) * (pitch_range[1] - center_pitch) + center_pitch return pitch_array
def normalize_img(img_arr, stretch='asinh', minmax_percent=None, minmax_value=None, invert=False): """ Apply given stretch and scaling to an image array. Parameters ---------- img_arr : array The input image array. stretch : str Optional, default 'asinh'. The stretch to apply to the image array. Valid values are: asinh, sinh, sqrt, log, linear minmax_percent : array Optional. Interval based on a keeping a specified fraction of pixels (can be asymmetric) when scaling the image. The format is [lower percentile, upper percentile], where pixel values below the lower percentile and above the upper percentile are clipped. Only one of minmax_percent and minmax_value shoul be specified. minmax_value : array Optional. Interval based on user-specified pixel values when scaling the image. The format is [min value, max value], where pixel values below the min value and above the max value are clipped. Only one of minmax_percent and minmax_value should be specified. invert : bool Optional, default False. If True the image is inverted (light pixels become dark and vice versa). Returns ------- response : array The normalized image array, in the form in an integer arrays with values in the range 0-255. """ # Setting up the transform with the stretch if stretch == 'asinh': transform = AsinhStretch() elif stretch == 'sinh': transform = SinhStretch() elif stretch == 'sqrt': transform = SqrtStretch() elif stretch == 'log': transform = LogStretch() elif stretch == 'linear': transform = LinearStretch() else: raise InvalidInputError("Stretch {} is not supported!".format(stretch)) # Adding the scaling to the transform if minmax_percent is not None: transform += AsymmetricPercentileInterval(*minmax_percent) if minmax_value is not None: warnings.warn("Both minmax_percent and minmax_value are set, minmax_value will be ignored.", InputWarning) elif minmax_value is not None: transform += ManualInterval(*minmax_value) else: # Default, scale the entire image range to [0,1] transform += MinMaxInterval() # Performing the transform and then putting it into the integer range 0-255 norm_img = transform(img_arr) norm_img = np.multiply(255, norm_img, out=norm_img) norm_img = norm_img.astype(np.uint8) # Applying invert if requested if invert: norm_img = 255 - norm_img return norm_img
def greyRGBize_image(datin, rescalefn='linear', scaletype='abs', min_max=[None, None], gamma=2.2, checkscale=False): """ ### Takes an image and returns 3-frame [R,G,B] (vals from 0...1) Parameters ---------- datin : array Input 2D image data array rescalefn : func Function to use for rescaling intensity. imscale.linear/sqrt/squared/log/power/sinh/asinh scaletype : str 'abs' for absolute values, 'perc' for percentiles min_max : list [min,max] vals to use in rescale. if scaletype='perc', list the percentiles to use, e.g. [1.,95.] gamma : float Value for gamma correction. For combining colorized frames, use default gamma=2.2. For inverse, use gamma=(1./2.2) checkscale : bool True to bring up plot to check the new image scale. Returns ------- array Greyscale RGB image, shape=[ypixels,xpixels,3] """ if 'per' in scaletype.lower(): if min_max == [None, None]: min_max = [0., 100.] minval, maxval = np.percentile( np.ma.masked_invalid(datin).compressed(), min_max) else: minval = [np.nanmin(datin) if min_max[0] is None else min_max[0]][0] maxval = [np.nanmax(datin) if min_max[1] is None else min_max[1]][0] # Used specified rescaling function datscaled = (scaling_fns[rescalefn]() + ManualInterval(vmin=minval, vmax=maxval))(datin) # datscaled=rescalefn(datin,vmin=minval,vmax=maxval) if gamma != 1: datscaled = adjust_gamma(datscaled, gamma) # Need to scale image between -1 and 1 if data type is float... datlinear = LinearStretch()(datscaled) # datlinear=imscale.linear(np.nan_to_num(datscaled)) # Convert to RGB dat_greyRGB = ski_color.gray2rgb(datlinear) if checkscale is not False: plt.clf() plt.close('all') fig0 = plt.figure(0) ax1 = fig0.add_subplot(121) plt.imshow(datin, interpolation='nearest', origin='lower', cmap='gist_gray') plt.title('Input Image') ax2 = fig0.add_subplot(122) plt.imshow(dat_greyRGB**(1. / gamma), interpolation='nearest', origin='lower') plt.title('Scaled Image') plt.show() # plt.clf(); plt.close('all') return dat_greyRGB
# yaxis.set_minor_frequency(ymi_num) """ scaling and imaging """ interp = 'none' # interpolation of the datacube, e.g., 'none'/'nearest'/'bilinear'/'bicubic', defaut is 'none' scaling = 'linear' # scaling of the datacube, e.g., 'linear'/'log'/'power'/'sqrt'/'squared', defaut is 'linear' index = 1e3 # index of log and power scaling, default is 1e3 if scaling == 'linear': stretch = LinearStretch() elif scaling == 'log': stretch = LogStretch(index) elif scaling == 'power': stretch = PowerStretch(index) elif scaling == 'sqrt': stretch = SqrtStretch() elif scaling == 'squared': stretch = SquaredStretch() if scale is None: interval = ManualInterval(vmin=np.nanmin(dat), vmax=np.nanmax(dat)) else: interval = ManualInterval(vmin=scale[0], vmax=scale[1]) # norm=ImageNormalize(dat, interval=interval, stretch=stretch) if scale is None: norm = colors.Normalize(vmin=np.nanmin(dat), vmax=np.nanmax(dat)) else: norm = colors.Normalize(vmin=scale[0], vmax=scale[1]) # ax.set_xlim(-0.5, dat.shape[1]-0.5) # ax.set_ylim(-0.5, dat.shape[0]-0.5) if colormap is not None: plt.set_cmap(colormap) cmap = mpl.cm.get_cmap() cmap.set_bad(color='white') im = ax.imshow(dat, norm=norm, interpolation=interp, cmap=cmap, origin='lower')
# yaxis.set_minor_frequency(ymi_num) """ scaling and imaging """ interp='none' # interpolation of the datacube, e.g., 'none'/'nearest'/'bilinear'/'bicubic', defaut is 'none' scaling='linear' # scaling of the datacube, e.g., 'linear'/'log'/'power'/'sqrt'/'squared', defaut is 'linear' index=1e3 # index of log and power scaling, default is 1e3 if scaling=='linear': stretch=LinearStretch() elif scaling=='log': stretch=LogStretch(index) elif scaling=='power': stretch=PowerStretch(index) elif scaling=='sqrt': stretch=SqrtStretch() elif scaling=='squared': stretch=SquaredStretch() if scale is None: interval=ManualInterval(vmin=np.nanmin(dat), vmax=np.nanmax(dat)) else: interval=ManualInterval(vmin=scale[0], vmax=scale[1]) # norm=ImageNormalize(dat, interval=interval, stretch=stretch) if scale is None: norm=colors.Normalize(vmin=np.nanmin(dat), vmax=np.nanmax(dat)) else: norm=colors.Normalize(vmin=scale[0], vmax=scale[1]) # ax.set_xlim(-0.5, dat.shape[1]-0.5) # ax.set_ylim(-0.5, dat.shape[0]-0.5) if colormap is not None: plt.set_cmap(colormap) cmap=mpl.cm.get_cmap() cmap.set_bad(color='white') im=ax.imshow(dat, norm=norm, interpolation=interp, cmap=cmap, origin='lower') """ The following arguments need to be set in the command.
def plot_inset(data, ax, centroids=None, cmap=None, vmin=None, vmax=None, w=100, h=100): """Plot an inset in the image plot Parameters ---------- data norm ax w h Returns ------- """ ax_inset = inset_axes(ax, width="30%", height="30%") ax_inset.grid(False) mark_inset(ax, ax_inset, loc1=2, loc2=4, fc="none", ec='r', lw=1.25) for label in ['bottom', 'top', 'left', 'right']: ax_inset.spines[label].set_color('r') ax_inset.tick_params(axis='both', which='major', bottom=False, top=False, right=False, left=False, labelleft=False, labelbottom=False) ymax, xmax = data.shape xlim = (xmax // 5 - w, xmax // 5 + w) ylim = (ymax // 3 - h, ymax // 3 + h) if cmap is not None: ax_inset.imshow( data, cmap=cmap, origin='lower', ) else: if vmin is not None and vmax is not None: interval = ManualInterval(vmin=vmin, vmax=vmax) else: interval = ZScaleInterval() norm = ImageNormalize(data, stretch=LinearStretch(), interval=interval) ax_inset.imshow(data, norm=norm, origin='lower', cmap='gray') if centroids is not None: for xy in centroids: aperture = Circle(xy=xy, radius=3, color='red', fill=False, lw=0.75) ax_inset.add_patch(aperture) ax_inset.set_xlim(xlim) ax_inset.set_ylim(ylim) return ax_inset