def plot2d(self, log=False, max_freq=200, fig=None, ax=None): ''' Creates a 2D plot of the MTF. Args: log (`bool`): If true, plots on log scale. max_freq (`float`): Maximum frequency to plot to. Axis limits will be ((-max_freq, max_freq), (-max_freq, max_freq)). fig (:class:`~matplotlib.pyplot.figure`): Figure to plot in. ax (:class:`~matplotlib.pyplot.axis`): Axis to plot in. Returns: `tuple` containing: fig (:class:`~matplotlib.pyplot.figure`): Figure containing the plot ax (:class:`~matplotlib.pyplot.axis`): Axis containing the plot. ''' if log: fcn = 20 * np.log10(1e-24 + self.data) label_str = 'MTF [dB]' lims = (-120, 0) else: fcn = correct_gamma(self.data) label_str = 'MTF [Rel 1.0]' lims = (0, 1) left, right = self.unit_x[0], self.unit_x[-1] bottom, top = self.unit_y[0], self.unit_y[-1] fig, ax = share_fig_ax(fig, ax) im = ax.imshow(fcn.T, extent=[left, right, bottom, top], origin='lower', cmap='Greys_r', interpolation='lanczos', clim=lims) cb = fig.colorbar(im, label=label_str, ax=ax, fraction=0.046) cb.outline.set_edgecolor('k') cb.outline.set_linewidth(0.5) ax.set(xlabel=r'$\nu_x$ [cy/mm]', ylabel=r'$\nu_y$ [cy/mm]', xlim=(-max_freq, max_freq), ylim=(-max_freq, max_freq)) return fig, ax
def test_correct_gamma_general_case(): arr = np.ones((ARR_SIZE, ARR_SIZE)) * 0.5 out = util.correct_gamma(arr, encoding=0.5) assert np.allclose(arr**2, out)
def test_correct_gamma_unity_case(): arr = np.ones((ARR_SIZE, ARR_SIZE)) * 0.75 out = util.correct_gamma(arr, encoding=1) assert np.allclose(arr, out)
def plot2d(self, freq, symmetric=False, contours=True, interp_method='lanczos', fig=None, ax=None): ''' Creates a 2D plot of the cube, an "MTF vs Field vs Focus" plot. Args: freq (`float`): frequency to plot, will be rounded to the closest value present in the self.freq iterable. symmetric (`bool`): make the plot symmetric by mirroring it about the x-axis origin. contours (`bool`): plot contours, yes or no (T/F). interp_method (`string`): interpolation method used for the plot. fig (`matplotlib.figure.Figure`): Figure to plot inside. ax (`matplotlib.axes.Axis`): Axis to plot inside. Returns: `tuple` containing: `matplotlib.figure.Figure`: figure containing the plot. `matplotlib.axes.Axis`: axis containing the plot. ''' ext_x = [self.field[0], self.field[-1]] ext_y = [self.focus[0], self.focus[-1]] freq_idx = np.searchsorted(self.freq, freq) # if the plot is symmetric, mirror the data if symmetric is True: dat = correct_gamma( np.concatenate( (self.data[:, ::-1, freq_idx], self.data[:, :, freq_idx]), axis=1)) ext_x[0] = ext_x[1] * -1 else: dat = correct_gamma(self.data[:, :, freq_idx]) ext = [ext_x[0], ext_x[1], ext_y[0], ext_y[1]] fig, ax = share_fig_ax(fig, ax) im = ax.imshow(dat, extent=ext, origin='lower', cmap='inferno', clim=(0, 1), interpolation=interp_method, aspect='auto') if contours is True: contours = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] cs = ax.contour(dat, contours, colors='0.15', linewidths=0.75, extent=ext) ax.clabel(cs, fmt='%1.1f', rightside_up=True) fig.colorbar(im, label='MTF [Rel. 1.0]', ax=ax, fraction=0.046) ax.set(xlim=(ext_x[0], ext_x[1]), xlabel='Image Height [mm]', ylim=(ext_y[0], ext_y[1]), ylabel=r'Focus [$\mu$m]') return fig, ax
def plot2d_rgbgrid(self, axlim=25, interp_method='lanczos', pix_grid=None, fig=None, ax=None): '''Creates a 2D color plot of the PSF and components Args: axlim (`float`): limits of axis, symmetric. xlim=(-axlim,axlim), ylim=(-axlim, axlim). interp_method (string): method used to interpolate the image between samples of the PSF. pix_grid (float): if not None, overlays gridlines with spacing equal to pix_grid. Intended to show the collection into camera pixels while still in the oversampled domain. fig (pyplot.figure): figure to plot in. ax (pyplot.axis): axis to plot in. Returns: pyplot.fig, pyplot.axis. Figure and axis containing the plot. Notes: Need to refine internal workings at some point. ''' # make the arrays for the RGB images dat = np.empty((self.samples_y, self.samples_x, 3)) datr = np.zeros((self.samples_y, self.samples_x, 3)) datg = np.zeros((self.samples_y, self.samples_x, 3)) datb = np.zeros((self.samples_y, self.samples_x, 3)) dat[:, :, 0] = self.R dat[:, :, 1] = self.G dat[:, :, 2] = self.B datr[:, :, 0] = self.R datg[:, :, 1] = self.G datb[:, :, 2] = self.B left, right = self.unit[0], self.unit[-1] ax_width = 2 * axlim # generate a figure and axes to plot in fig, ax = share_fig_ax(fig, ax) axr, axg, axb = make_rgb_axes(ax) ax.imshow(correct_gamma(dat), extent=[left, right, left, right], interpolation=interp_method, origin='lower') axr.imshow(correct_gamma(datr), extent=[left, right, left, right], interpolation=interp_method, origin='lower') axg.imshow(correct_gamma(datg), extent=[left, right, left, right], interpolation=interp_method, origin='lower') axb.imshow(correct_gamma(datb), extent=[left, right, left, right], interpolation=interp_method, origin='lower') for axs in (ax, axr, axg, axb): ax.set(xlim=(-axlim, axlim), ylim=(-axlim, axlim)) if pix_grid is not None: # if pixel grid is desired, add it mult = np.floor(axlim / pix_grid) gmin, gmax = -mult * pix_grid, mult * pix_grid pts = np.arange(gmin, gmax, pix_grid) ax.set_yticks(pts, minor=True) ax.set_xticks(pts, minor=True) ax.yaxis.grid(True, which='minor') ax.xaxis.grid(True, which='minor') ax.set(xlabel=r'Image Plane X [$\mu m$]', ylabel=r'Image Plane Y [$\mu m$]') axr.text(-axlim + 0.1 * ax_width, axlim - 0.2 * ax_width, 'R', color='white') axg.text(-axlim + 0.1 * ax_width, axlim - 0.2 * ax_width, 'G', color='white') axb.text(-axlim + 0.1 * ax_width, axlim - 0.2 * ax_width, 'B', color='white') return fig, ax
def plot2d(self, log=False, axlim=25, interp_method='lanczos', pix_grid=None, fig=None, ax=None): ''' Creates a 2D color plot of the PSF. Args: log (`bool`): if true, plot in log scale. If false, plot in linear scale. axlim (`float`): limits of axis, symmetric. xlim=(-axlim,axlim), ylim=(-axlim, axlim). interp_method (`string`): method used to interpolate the image between samples of the PSF. pix_grid (`float`): if not None, overlays gridlines with spacing equal to pix_grid. Intended to show the collection into camera pixels while still in the oversampled domain. fig (pyplot.figure): figure to plot in. ax (pyplot.axis): axis to plot in. Returns: pyplot.fig, pyplot.axis. Figure and axis containing the plot. Notes: Largely a copy-paste of plot2d() from the PSF class. Some refactoring could be done to make the code more succinct and unified. ''' dat = np.empty((self.samples_x, self.samples_y, 3)) dat[:, :, 0] = self.R dat[:, :, 1] = self.G dat[:, :, 2] = self.B if log: fcn = 20 * np.log10(1e-100 + dat) lims = (-100, 0) # show first 100dB -- range from (1e-6, 1) in linear scale else: fcn = correct_gamma(dat) lims = (0, 1) left, right = self.unit_x[0], self.unit_x[-1] bottom, top = self.unit_y[0], self.unit_y[-1] fig, ax = share_fig_ax(fig, ax) ax.imshow(fcn, extent=[left, right, bottom, top], interpolation=interp_method, origin='lower') ax.set(xlabel=r'Image Plane X [$\mu m$]', ylabel=r'Image Plane Y [$\mu m$]', xlim=(-axlim, axlim), ylim=(-axlim, axlim)) if pix_grid is not None: # if pixel grid is desired, add it mult = floor(axlim / pix_grid) gmin, gmax = -mult * pix_grid, mult * pix_grid pts = np.arange(gmin, gmax, pix_grid) ax.set_yticks(pts, minor=True) ax.set_xticks(pts, minor=True) ax.yaxis.grid(True, which='minor') ax.xaxis.grid(True, which='minor') return fig, ax
def plot2d(self, axlim=25, power=1, interp_method='lanczos', pix_grid=None, fig=None, ax=None, show_axlabels=True, show_colorbar=True): ''' Creates a 2D plot of the PSF. Args: axlim (`float`): limits of axis, symmetric. xlim=(-axlim,axlim), ylim=(-axlim, axlim). power (`float`): power to stretch the data by for plotting. interp_method (`string`): method used to interpolate the image between samples of the PSF. pix_grid (`float`): if not None, overlays gridlines with spacing equal to pix_grid. Intended to show the collection into camera pixels while still in the oversampled domain. fig (pyplot.figure): figure to plot in. ax (pyplot.axis): axis to plot in. show_axlabels (`bool`): whether or not to show the axis labels. show_colorbar (`bool`): whether or not to show the colorbar. Returns: pyplot.fig, pyplot.axis. Figure and axis containing the plot. ''' fcn = correct_gamma(self.data ** power) label_str = 'Normalized Intensity [a.u.]' lims = (0, 1) left, right = self.unit_x[0], self.unit_x[-1] bottom, top = self.unit_y[0], self.unit_y[-1] fig, ax = share_fig_ax(fig, ax) im = ax.imshow(fcn, extent=[left, right, bottom, top], origin='lower', cmap='Greys_r', interpolation=interp_method, clim=lims) if show_colorbar: cb = fig.colorbar(im, label=label_str, ax=ax, fraction=0.046) cb.outline.set_edgecolor('k') cb.outline.set_linewidth(0.5) if show_axlabels: ax.set(xlabel=r'Image Plane $x$ [$\mu m$]', ylabel=r'Image Plane $y$ [$\mu m$]') ax.set(xlim=(-axlim, axlim), ylim=(-axlim, axlim)) if pix_grid is not None: # if pixel grid is desired, add it mult = floor(axlim / pix_grid) gmin, gmax = -mult * pix_grid, mult * pix_grid pts = np.arange(gmin, gmax, pix_grid) ax.set_yticks(pts, minor=True) ax.set_xticks(pts, minor=True) ax.yaxis.grid(True, which='minor', color='white', alpha=0.25) ax.xaxis.grid(True, which='minor', color='white', alpha=0.25) return fig, ax