Exemplo n.º 1
0
def plot_rmswfe_rrmswfe_scatter(db, ylim=(None, None), fig=None, ax=None):
    """Make a scatter plot of residual RMS WFE vs RMS WFE from a database.

    This plot can be used as a simplified means of understanding the capture
    range of MTF-based wavefront sensing.

    Parameters
    ----------
    db : `iris.data.Database`
        database of simulation results
    ylim : `iterable`, optional
        lower, upper y axis limits
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    """
    fig, ax = share_fig_ax(fig, ax)
    ax.scatter(db.df.truth_rmswfe, db.df.rrmswfe_final)
    ax.set(xlabel=r'RMS WFE [$\lambda$]',
           ylim=ylim,
           ylabel=r'Residual RMS WFE [$\lambda$]',
           yscale='log')
    return fig, ax
Exemplo n.º 2
0
    def plot2d(self, fig=None, ax=None):
        ''' Creates a 2D plot of the phase error of the pupil

        Args:
            fig (pyplot.figure): Figure to draw plot in
            ax (pyplot.axis): Axis to draw plot in

        Returns:
            (pyplot.figure, pyplot.axis): Figure and axis containing the plot

        '''
        epd = self.epd

        fig, ax = share_fig_ax(fig, ax)
        im = ax.imshow(convert_phase(self.phase, self),
                       extent=[-epd / 2, epd / 2, -epd / 2, epd / 2],
                       cmap='RdYlBu',
                       interpolation='lanczos',
                       origin='lower')
        cb = fig.colorbar(im,
                          label=f'OPD [{self._opd_str}]',
                          ax=ax,
                          fraction=0.046)
        cb.outline.set_edgecolor('k')
        cb.outline.set_linewidth(0.5)
        ax.set(xlabel=r'Pupil $\xi$ [mm]', ylabel=r'Pupil $\eta$ [mm]')
        return fig, ax
Exemplo n.º 3
0
def plot_final_cost_rrmswfe_scatter(db, ylim=(None, None), fig=None, ax=None):
    """Plot final cost residual RMS WFE vs final cost function value.

    This plot can be used as a simplified means of understanding a uniqueness
    problem in MTF-based wavefront sensing.

    Parameters
    ----------
    db : `iris.data.Database`
        database of simulation results
    ylim : iterable, optional
        Description
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    """
    fig, ax = share_fig_ax(fig, ax)
    ax.scatter(db.df.cost_final, db.df.rrmswfe_final)
    ax.set(xlabel='Cost Function Value',
           ylim=ylim,
           ylabel=r'Residual RMS WFE [$\lambda$]',
           yscale='log')
    return fig, ax
Exemplo n.º 4
0
def _render_rrmswfe_vs_angle_plot(db,
                                  sph_amount,
                                  other='coma',
                                  fig=None,
                                  ax=None):
    other_amounts = [0.05, 0.10, 0.20]
    if other.lower() == 'coma':
        lbl = '|Z7,Z8| '
    else:
        lbl = '|Z5,Z6| '

    fig, ax = share_fig_ax(fig, ax)
    for ca in other_amounts:
        ids = _filter_db_for_sph_and_coma_or_ast_mags(db, other, sph_amount,
                                                      ca)
        cost, rmswfe, rrmswfe, coma_angle = _get_cost_rmswfe_rrmswfe_coma_or_ast_angle(
            db, ids, other)
        ax.plot(coma_angle, rrmswfe, label=f'{ca}')

    ax.set(ylim=(1e-4, 1e-0),
           yscale='log',
           ylabel=r'Residual RMS WFE [$\lambda$]',
           xlabel=r'$\Theta(Z)$ [deg]')
    ax.legend(title=lbl + r'$\lambda{}$ RMS',
              loc='lower left',
              fancybox=True,
              framealpha=1)

    return fig, ax
Exemplo n.º 5
0
def plot_image_from_cfg_codex_params_focus(config,
                                           codex,
                                           params,
                                           focuses,
                                           gamma=1.5,
                                           titles=('Tangential', 'Sagittal'),
                                           fig=None,
                                           axs=None):
    """Make a 2D image of (frequency, focus) from data used to do a simulation.

    Parameters
    ----------
    config : `prysm.macros.SimulationConfig`
        a simulationconfig
    codex : `dict`
        dictionary with keys of integers and values of 'Zxx' strings, see `iris.rings`
    params : iterable
        set of wavefront parameters
    focuses : iterable
        set of focus values, in um
    gamma : `float`, optional
        gamma value to stretch plot by
    titles : iterable, optional
        titles to use to label plots
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    axs : iterable of `matplotlib.axes.Axis`
        Axes containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    axs : iterable of `matplotlib.axes.Axis`
        Axes containing the plot

    """
    imgt, imgs = config_codex_params_to_imgs(config, codex, params, focuses)
    extx = [config.freqs[0], config.freqs[-1]]
    exty = [focuses[0], focuses[-1]]

    fig, axs = share_fig_ax(fig, axs, numax=2)
    for data, ax, title in zip([imgt, imgs], axs, titles):
        im = ax.imshow(data,
                       extent=[*extx, *exty],
                       origin='lower',
                       aspect='auto',
                       cmap='inferno',
                       norm=mpl.colors.PowerNorm(1 / gamma),
                       clim=(0, 1),
                       interpolation='lanczos')
        ax.set(xlim=extx,
               xlabel='Spatial Frequency [cy/mm]',
               ylim=exty,
               ylabel=r'Focus [$\mu m$]',
               title=title)

    fig.tight_layout()
    fig.colorbar(im, ax=axs, label='MTF [Rel. 1.0]')
    return fig, axs
Exemplo n.º 6
0
    def show(self, interp_method=None, fig=None, ax=None):
        ''' Displays the image.

        Args:
            interp_method (`string`): interpolation technique used in display.

            fig (`matplotlib.figure`): figure to display in.

            ax (`matplotlib.axis`): axis to display in.

        Returns:
            `tuple` containing:

                `matplotlib.figure`: figure containing the plot.

                `matplotlib.axis`: axis containing the plot.

        '''
        lims = (0, 1)
        fig, ax = share_fig_ax(fig, ax)

        ax.imshow(self.data,
                  cmap='Greys_r',
                  interpolation=interp_method,
                  clim=lims,
                  origin='lower')
        ax.set_axis_off()
        return fig, ax
Exemplo n.º 7
0
    def plot_mtf_thrufocus(self,
                           field_index,
                           focus_range,
                           numpts,
                           freqs,
                           fig=None,
                           ax=None):
        focus, mtfs = self._make_mtf_thrufocus(field_index, focus_range,
                                               numpts)
        t = []
        s = []
        for mtf in mtfs:
            t.append(mtf.exact_polar(freqs, 0))
            s.append(mtf.exact_polar(freqs, 90))

        t, s = np.asarray(t), np.asarray(s)
        fig, ax = share_fig_ax(fig, ax)
        for idx, freq in enumerate(freqs):
            l, = ax.plot(focus, t[:, idx], lw=2, label=freq)
            ax.plot(focus, s[:, idx], lw=2, ls='--', c=l.get_color())
        ax.legend(title=r'$\nu$ [cy/mm]')
        ax.set(xlim=(focus[0], focus[-1]),
               xlabel=r'Defocus [$\mu m$]',
               ylim=(0, 1),
               ylabel='MTF [Rel. 1.0]',
               title='Through Focus MTF')

        return fig, ax
Exemplo n.º 8
0
    def interferogram(self, visibility=1, passes=2, fig=None, ax=None):
        ''' Creates an interferogram of the :class:`Pupil~.

        Args:
            visibility (`float`): Visibility of the interferogram

            passes (`float`): number of passes (double-pass, quadra-pass, etc.)

            fig (pyplot.figure): Figure to draw plot in

            ax (pyplot.axis): Axis to draw plot in

        Returns:
            `tuple` containing:
                :class:`~matplotlib.pyplot.figure`: Figure containing the plot

                :class:`~matplotlib.pyplot.axis`: Axis containing the plot

        '''
        epd = self.epd

        fig, ax = share_fig_ax(fig, ax)
        plotdata = (visibility * sin(2 * pi * passes * self.phase))
        im = ax.imshow(plotdata,
                       extent=[-epd / 2, epd / 2, -epd / 2, epd / 2],
                       cmap='Greys_r',
                       interpolation='lanczos',
                       clim=(-1, 1),
                       origin='lower')
        fig.colorbar(im,
                     label=r'Wrapped Phase [$\lambda$]',
                     ax=ax,
                     fraction=0.046)
        ax.set(xlabel=r'Pupil $\xi$ [mm]', ylabel=r'Pupil $\eta$ [mm]')
        return fig, ax
Exemplo n.º 9
0
def log_kde(data,
            xlim,
            num_pts=100,
            shade=True,
            bw_method=None,
            gridlines_below=True,
            fig=None,
            ax=None):
    """Create a Kernel Density Estimation based 'histogram' on a logarithmic x axis.

    Parameters
    ----------
    data: `numpy.ndarray`
        data to plot
    xlim: iterable of length 2
        lower and upper x limits to plot
    num_pts: `int`, optional
        number of points to sample along x axis
    shade: `bool`, optional
        whether to shade the area under the curve
    bw_method: `str` or `float`, optional
        passed to `scipy.stats.gaussian_kde` to set the bandwidth during estimation
    gridlines_below: `bool`
        whether to set axis gridlines to be below the graphics
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    """
    d = np.log10(data)
    kde = gaussian_kde(d, bw_method)
    xpts = np.linspace(np.log10(xlim[0]), np.log10(xlim[1]),
                       num_pts)  # in transformed space
    data = kde(xpts)
    real_xpts = 10**xpts
    data = data / data.sum() * 100

    fig, ax = share_fig_ax(fig, ax)
    if shade is True:
        z = np.zeros(real_xpts.shape)
        ax.fill_between(real_xpts, data, z)
    ax.plot(real_xpts, data)
    ax.set(xlim=xlim,
           xlabel=r'Residual RMS WFE [$\lambda$]',
           xscale='log',
           ylim=(0, None),
           ylabel='Probability Density [%]',
           axisbelow=gridlines_below)
    return fig, ax
Exemplo n.º 10
0
def zernike_barplot(zerndict,
                    barwidth=0.8,
                    alpha=1.0,
                    shift=0,
                    label=None,
                    fig=None,
                    ax=None):
    """Summary

    Parameters
    ----------
    zerndict : TYPE
        dictionary with keys 'Zxxx' and numeric values
    barwidth : float, optional
        width of bars; values greater than 1 may cause poor appearance
    alpha : `float`, optional
        transparency of the bars
    shift : `float`,
        amount to shift the x values by, used for combining multiple barplots
    label : `str`
        label for the set of bars
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    """
    nums = [int(x[1:]) + shift for x in zerndict.keys()]
    base_adj = barwidth / 2
    base_y = [0, 0]
    base_x = [min(nums) - base_adj, max(nums) + base_adj]

    fig, ax = share_fig_ax(fig, ax)
    ax.plot(base_x, base_y, lw=0.5, c='k')
    ax.bar(nums,
           zerndict.values(),
           width=barwidth,
           alpha=alpha,
           zorder=4,
           label=label)
    ax.set(xticks=nums,
           xticklabels=zerndict.keys(),
           ylabel=r'Amplitude RMS [$\lambda$]')
    for tick in ax.get_xticklabels():
        tick.set_rotation(45)

    return fig, ax
Exemplo n.º 11
0
    def plot_mtf_vs_field(self,
                          num_pts,
                          freqs=[10, 20, 30, 40, 50],
                          title='MTF vs Field',
                          minorgrid=True,
                          fig=None,
                          ax=None):
        ''' Generates a plot of the MTF vs Field for the lens.

        Args:
            num_pts (`int`): number of field points to evaluate.

            freqs (`iterable`): frequencies to evaluate the MTF at.

            fig (`matplotlib.pyplot.figure`): figure to plot inside.

            ax (`matplotlib.pyplot.axis`): axis to plot ini.

        Return:
            `tuple` containing:

                `matplotlib.pyplot.figure`: figure containing the plot.

                `matplotlib.pyplot.axis`: axis containing the plot.

        '''
        data_s, data_t = self.mtf_vs_field(num_pts, freqs)
        flds_abs = np.linspace(0, self.fov_y, num_pts)
        fig, ax = share_fig_ax(fig, ax)
        for i in range(len(freqs)):
            ln, = ax.plot(flds_abs, data_s[:, i], lw=3, ls='--')
            ax.plot(flds_abs,
                    data_t[:, i],
                    lw=3,
                    color=ln.get_color(),
                    label=f'{freqs[i]}lp/mm')

        ax.plot(0, 0, color='k', ls='--', label='Sag')
        ax.plot(0, 0, color='k', label='Tan')
        # todo: respect units of `self`

        if minorgrid is True:
            ax.set_yticks([0.1, 0.3, 0.5, 0.7, 0.9], minor=True)
            ax.grid(True, which='minor')

        ax.set(xlim=(0, self.fov_y),
               xlabel='Image Height [mm]',
               ylim=(0, 1),
               ylabel='MTF [Rel. 1.0]',
               title=title)
        ax.legend()

        return fig, ax
Exemplo n.º 12
0
def plot_axial_df_2d(df,
                     gamma=1.5,
                     titles=('Tangential', 'Sagittal'),
                     fig=None,
                     axs=None):
    """Make a 2D plot of (frequency, focus) from a dataframe containing axial data.

    Parameters
    ----------
    df : `pandas.DataFrame`
        a pandas df with columns Focus, Field, Freq, Azimuth, and MTF
    gamma : `float`, optional
        gamma value to stretch plot by
    titles : iterable, optional
        titles for the left and right panes
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    axs : iterable of `matplotlib.axes.Axis`
        Axes containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    axs : iterable of `matplotlib.axes.Axis`
        Axes containing the plot

    """
    focuspos, ax_t, ax_s = _axial_df_to_image_focus(df)
    extx, exty = [df.Freq.min(), df.Freq.max()], [focuspos[0], focuspos[-1]]
    fig, axs = share_fig_ax(fig, axs, numax=2)
    for data, ax, title in zip([ax_t, ax_s], axs, titles):
        im = ax.imshow(data,
                       extent=[*extx, *exty],
                       origin='lower',
                       aspect='auto',
                       cmap='inferno',
                       norm=mpl.colors.PowerNorm(1 / gamma),
                       clim=(0, 1),
                       interpolation='lanczos')
        ax.set(xlim=extx,
               xlabel='Spatial Frequency [cy/mm]',
               ylim=exty,
               ylabel=r'Focus [$\mu m$]',
               title=title)

    fig.tight_layout()
    fig.colorbar(im, ax=axs, label='MTF [Rel. 1.0]')
    return fig, axs
Exemplo n.º 13
0
def cie_1976_wavelength_annotations(wavelengths, fig=None, ax=None):
    ''' Draws lines normal to the spectral locust on a CIE 1976 diagram and
        writes the text for each wavelength.

    Args:
        wavelengths (`iterable`): set of wavelengths to annotate.

        fig (`matplotlib.figure.Figure`): figure to draw on.

        ax (`matplotlib.axes.Axis`): axis to draw in.

    Returns:

        `tuple` containing:

            `matplotlib.figure.Figure`: figure containing the annotations.

            `matplotlib.axes.Axis`: axis containing the annotations.

    Notes:
        see SE:
        https://stackoverflow.com/questions/26768934/annotation-along-a-curve-in-matplotlib

    '''
    # some tick parameters
    tick_length = 0.025
    text_offset = 0.06

    # convert wavelength to u' v' coordinates
    wavelengths = np.asarray(wavelengths)
    idx = np.arange(1, len(wavelengths) - 1, dtype=int)
    wvl_lbl = wavelengths[idx]
    uv = XYZ_to_uvprime(wavelength_to_XYZ(wavelengths))
    u, v = uv[..., 0][idx], uv[..., 1][idx]
    u_last, v_last = uv[..., 0][idx - 1], uv[..., 1][idx - 1]
    u_next, v_next = uv[..., 0][idx + 1], uv[..., 1][idx + 1]

    angle = atan2(v_next - v_last, u_next - u_last) + pi / 2
    cos_ang, sin_ang = cos(angle), sin(angle)
    u1, v1 = u + tick_length * cos_ang, v + tick_length * sin_ang
    u2, v2 = u + text_offset * cos_ang, v + text_offset * sin_ang

    fig, ax = share_fig_ax(fig, ax)
    tick_lines = LineCollection(np.c_[u, v, u1, v1].reshape(-1, 2, 2), color='0.25', lw=1.25)
    ax.add_collection(tick_lines)
    for i in range(len(idx)):
        ax.text(u2[i], v2[i], str(wvl_lbl[i]), va="center", ha="center", clip_on=True)

    return fig, ax
Exemplo n.º 14
0
def cct_duv_diagram(samples=100, fig=None, ax=None):
    ''' Creates a CCT-Duv diagram, for more information see Calculation of
        CCT and Duv and Practical Conversion Formulae, Yoshi Ohno, 2011.

    Args:
        samples (`int`): number of samples on the background.

        fig (`matplotlib.figure.Figure`): figure to plot in.

        ax (`matplotlib.axes.Axis`): axis to plot in.

    Returns:
        `tuple` containing:

            `matplotlib.figure.Figure`: figure containing the plot.

            `matplotlib.axes.Axis`: Axis containing the plot.

    '''
    # raise UserWarning('this type of plot is not yet properly implemented')
    xlim = (2000, 10000)
    ylim = (-0.03, 0.03)

    cct = np.linspace(xlim[0], xlim[1], samples)  # todo: even sampling along log, not linear
    duv = np.linspace(ylim[0], ylim[1], samples)

    upvp = multi_cct_duv_to_upvp(cct, duv)
    cct, duv = np.meshgrid(cct, duv)

    xy = uvprime_to_xy(upvp)
    xyz = xy_to_XYZ(xy)
    dat = XYZ_to_sRGB(xyz)

    maximum = np.max(dat, axis=-1)
    dat /= maximum[..., np.newaxis]
    dat = np.clip(dat, 0, 1)

    fig, ax = share_fig_ax(fig, ax)

    ax.imshow(dat,
              extent=[*xlim, *ylim],
              interpolation='bilinear',
              origin='lower',
              aspect='auto')

    ax.set(xlim=xlim, xlabel='CCT [K]',
           ylim=ylim, ylabel='Duv [a.u.]')

    return fig, ax
Exemplo n.º 15
0
def plot_2d_optframe(data,
                     max_freq=None,
                     focus_range=None,
                     focus_unit=r'$\mu m$',
                     fig=None,
                     ax=None):
    """Plot an image view of the data.

    Parameters
    ----------
    data : `numpy.ndarray`
        2D data with first dimension spatial frequency, second dimension focus
    max_freq : `float`, optional
        maximum spatial frequency to plot, x axis range will be [0,max_freq]
    focus_range : `float`, optional
        maximum defocus value to plot, y axis range will be [-focus_range,focus_range]
    focus_unit : str, optional
        unit of focus, e.g. um or waves
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    """
    fig, ax = share_fig_ax(fig, ax)

    im = ax.imshow(data,
                   extent=[0, max_freq, -focus_range, focus_range],
                   aspect='auto',
                   origin='lower',
                   interpolation=None)

    fig.colorbar(im)

    if max_freq is not None and focus_range is not None:
        ax.set(xlim=(0, max_freq),
               xlabel='Spatial Frequency [cy/mm]',
               ylim=(-focus_range, focus_range),
               ylabel=f'Focus [{focus_unit}]')

    return fig, ax
Exemplo n.º 16
0
    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
Exemplo n.º 17
0
def plot_costfunction_history_global(document,
                                     sqrt=False,
                                     log=True,
                                     ylim=(None, None),
                                     ls=None,
                                     fig=None,
                                     ax=None):
    """Plot the cost function history of a global optimization run.

    Parameters
    ----------
    document : `dict`
        document produced by utilities.prepare_document_global
    sqrt : `bool`
        whether to take the sqrt of the cost function
    log : `bool`
        whether to plot with logarithmic y axis
    ylim : iterable of length 2
        lower, upper y axis limits
    ls : `str`
        line style
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    """
    if log is True:
        yscale = 'log'
    else:
        yscale = None
    fig, ax = share_fig_ax(fig, ax)
    if sqrt:
        data = [[_sqrt(x) for x in y] for y in document['cost_iter']]
        label = r'$\sqrt{Cost\, Function\,}$ [a.u.]'
    else:
        data = document['cost_iter']
        label = 'Cost Function [a.u.]'
    _plot_attribute_global(data, ax=ax, ls=ls)
    ax.set(ylabel=label, yscale=yscale, ylim=ylim, xlabel='Iteration')
    return fig, ax
Exemplo n.º 18
0
def plot_fourier_chain(pupil, psf, mtf, fig=None, axs=None, sizex=12, sizey=6):
    '''Plots a :class:`Pupil`, :class:`PSF`, and :class:`MTF`
        demonstrating the process of fourier optics simulation

    Args:
        pupil (prysm.Pupil): The pupil of an optical system

        psf (prysm.PSF): The psf of an optical system

        mtf (prysm.MTF): The MTF of an optical system

        fig (pyplot.figure): A figure object

        axs (list of pyplot.axes): axes to place the plots in

        sizex (number): size of the figure in x

        sizey (number): size of the figure in y

    Returns:
        fig, axs.  A figure and axes containing the plot.

    '''

    fig, axs = share_fig_ax(fig, axs, numax=3)

    pupil.interferogram(fig=fig, ax=axs[0])
    psf.plot2d(fig=fig, ax=axs[1])
    mtf.plot2d(fig=fig, ax=axs[2])

    axs[0].set(title='Pupil')
    axs[1].set(title='PSF')
    axs[2].set(title='MTF')

    bbox_props = dict(boxstyle="rarrow", fill=None, lw=1)
    axs[0].text(1.385, 1.07, r'|Fourier Transform|$^2$',
                ha='center', va='center', bbox=bbox_props,
                transform=axs[0].transAxes)
    axs[0].text(3.15, 1.07, r'|Fourier Transform|',
                ha='center', va='center', bbox=bbox_props,
                transform=axs[0].transAxes)
    fig.set_size_inches(sizex, sizey)
    fig.tight_layout()
    return fig, axs
Exemplo n.º 19
0
def plot_rrmswfe_history_global(document,
                                log=True,
                                ylim=(None, None),
                                ls=None,
                                fig=None,
                                ax=None):
    """Plot the residual RMS WFE history of a global optimization run.

    Parameters
    ----------
    document : `dict`
        document produced by utilities.prepare_document_global
    log : `bool`
        whether to plot with logarithmic y axis
    ylim : iterable of length 2
        lower, upper y axis limits
    ls : `str`
        line style
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    """
    if log is True:
        yscale = 'log'
    else:
        yscale = None
    fig, ax = share_fig_ax(fig, ax)
    _plot_attribute_global(document['rrmswfe_iter'], ax=ax, ls=ls)
    ax.set(ylabel=r'Residual RMS WFE [$\lambda$]',
           yscale=yscale,
           ylim=ylim,
           xlabel='Iteration')
    return fig, ax
Exemplo n.º 20
0
    def plot_slice_xy(self, log=False, axlim=20, fig=None, ax=None):
        ''' Makes a 1D plot of X and Y slices through the PSF.

        Args:
            log (`bool`): if true, plot in log scale.  if false, plot in linear
                scale.

            axlim (`float`): limits of axis, will plot [-axlim, axlim].

            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.

        '''
        ux, x = self.slice_x
        uy, y = self.slice_y
        if log:
            fcn_x = 20 * np.log10(1e-100 + x)
            fcn_y = 20 * np.log10(1e-100 + y)
            label_str = 'Normalized Intensity [dB]'
            lims = (-120, 0)
        else:
            fcn_x = x
            fcn_y = y
            label_str = 'Normalized Intensity [a.u.]'
            lims = (0, 1)

        fig, ax = share_fig_ax(fig, ax)

        ax.plot(ux, fcn_x, label='Slice X', lw=3)
        ax.plot(uy, fcn_y, label='Slice Y', lw=3)
        ax.set(xlabel=r'Image Plane X [$\mu m$]',
               ylabel=label_str,
               xlim=(-axlim, axlim),
               ylim=lims)
        plt.legend(loc='upper right')
        return fig, ax
Exemplo n.º 21
0
    def plot_psf_vs_field(self, num_pts, fig=None, axes=None, axlim=25):
        ''' Creates a figure showing the evolution of the PSF over the field
            of view.

        Args:
            num_pts (`int`): Number of points between (0,1) to create a PSF for

        Returns:
            `tuple` containing:

                `matplotlib.pyplot.figure`: figure containing the plots.

                `list`: the axes the plots are placed in.

        '''
        psfs = self.psf_vs_field(num_pts)
        fig, axes = share_fig_ax(fig,
                                 axes,
                                 numax=num_pts,
                                 sharex=True,
                                 sharey=True)

        for idx, (psf, axis) in enumerate(zip(psfs, axes)):
            show_labels = False
            show_colorbar = False
            if idx == 0:
                show_labels = True
            elif idx == num_pts - 1:
                show_colorbar = True
            psf.plot2d(fig=fig,
                       ax=axis,
                       axlim=axlim,
                       show_axlabels=show_labels,
                       show_colorbar=show_colorbar)

        fig_width = 15
        fig.set_size_inches(fig_width, fig_width / num_pts)
        fig.tight_layout()
        return fig, axes
Exemplo n.º 22
0
    def plot_reference_spots(self, fig=None, ax=None):
        ''' Create a plot of the reference positions of lenslets.

        Args:
            fig (`matplotlib.figure.Figure`): figure object to draw in.

            ax (`matplotlib.axes.Axis`): axis object to draw in.

        Returns:
            `tuple` containing:

                `matplotlib.figure.Figure`: figure containing the plot.

                `matplotlib.axes.Axis`: axis containing the plot.
        '''

        fig, ax = share_fig_ax(fig, ax)
        ax.scatter(self.refx / 1e3, self.refy / 1e3, c='k', s=8)
        ax.set(xlim=(0, self.sensor_size[0]), xlabel='Detector Position X [mm]',
               ylim=(0, self.sensor_size[1]), ylabel='Detector Position Y [mm]',
               aspect='equal')
        return fig, ax
Exemplo n.º 23
0
def plot_mtf_focus_grid(data, frequencies, focus, fig=None, ax=None):
    """Plot a 2D view of MTF through frequency and focus.

    Parameters
    ----------
    data : `numpy.ndarray`
        2D ndarray with dimensions of frequency,focus
    frequencies : iterable
        fequencies the data is given at; x axes, cy/mm
    focus : iterable
        focus points the data is given at; y axes, microns
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    Returns
    -------
    fig : `matplotlib.figure.Figure`
        Figure containing the plot
    ax : `matplotlib.axes.Axis`
        Axis containing the plot

    """
    xlims = (frequencies[0], frequencies[-1])
    ylims = (focus[0], focus[-1])
    fig, ax = share_fig_ax(fig, ax)
    ax.imshow(data,
              extent=[*xlims, *ylims],
              origin='lower',
              aspect='auto',
              interpolation='lanczos')
    ax.set(xlim=xlims,
           xlabel='Spatial Frequency $\nu$ [cy/mm]',
           ylim=ylims,
           ylabel='Focus [$\mu$ m]')

    return fig, ax
Exemplo n.º 24
0
    def show_fourier(self, interp_method='lanczos', fig=None, ax=None):
        ''' Displays the fourier transform of the image.

        Args:
            interp_method (`string`): method used to interpolate the data
                for display.

            fig (`matplotlib.figure`): figure to plot in.

            ax (`matplotlib.axis`): axis to plot in.

        Returns:
            `tuple` containing:

                `matplotlib.figure`: figure containing the plot.

                `matplotlib.axis`: axis containing the plot.

        '''
        dat = abs(fftshift(fft2(pad2d(self.data))))
        dat /= dat.max()
        unit_x = forward_ft_unit(self.sample_spacing, self.samples_x)
        unit_y = forward_ft_unit(self.sample_spacing, self.samples_y)
        xmin, xmax = unit_x[0], unit_x[-1]
        ymin, ymax = unit_y[0], unit_y[-1]

        fig, ax = share_fig_ax(fig, ax)
        im = ax.imshow(dat**0.1,
                       extent=[xmin, xmax, ymin, ymax],
                       cmap='Greys_r',
                       interpolation=interp_method,
                       origin='lower')
        fig.colorbar(im)
        ax.set(xlabel='Spatial Frequency X [cy/mm]',
               ylabel='Spatial Frequency Y [cy/mm]',
               title='Normalized FT of image, to 0.1 power')
        return fig, ax
Exemplo n.º 25
0
    def plot_encircled_energy(self, azimuth=None, axlim=20, fig=None, ax=None):
        ''' Makes a 1D plot of the encircled energy at the given azimuth.

        Args:
            azimuth (`float`): azimuth to plot at, in degrees.

            axlim (`float`): limits of axis, will plot [0, axlim].

            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

        '''
        unit, data = self.encircled_energy(azimuth)

        fig, ax = share_fig_ax(fig, ax)
        ax.plot(unit, data, lw=3)
        ax.set(xlabel=r'Image Plane Distance [$\mu m$]',
               ylabel=r'Encircled Energy [Rel 1.0]',
               xlim=(0, axlim))
        return fig, ax
Exemplo n.º 26
0
    def plot_slice_xy(self, fig=None, ax=None):
        ''' Creates a plot of slices through the X and Y axes of the pupil

        Args:
            fig (pyplot.figure): Figure to draw plot in
            ax (pyplot.axis): Axis to draw plot in

        Returns:
            (pyplot.figure, pyplot.axis): Figure and axis containing the plot

        '''
        u, x = self.slice_x
        _, y = self.slice_y

        fig, ax = share_fig_ax(fig, ax)

        x = convert_phase(x, self)
        y = convert_phase(y, self)

        ax.plot(u, x, lw=3, label='Slice X')
        ax.plot(u, y, lw=3, label='Slice Y')
        ax.set(xlabel=r'Pupil $\rho$ [mm]', ylabel=f'OPD [{self._opd_str}]')
        plt.legend()
        return fig, ax
Exemplo n.º 27
0
    def plot_simple_result(self, result_index=-1, type='quiver', fig=None, ax=None):
        ''' Plots the simple version of the most recent result.

        Args:
            result_index (`int`): which capture to plot, defaults to most recent.

            type (`str`): what type of plot to make.  Either "quiver" or "dots".

            fig (`matplotlib.figure.Figure`): figure to plot in.

            ax (`matplotlib.axes.Axis`): axis to plot in.

        Returns:
            `tuple` containing:

                `matplotlib.figure.Figure`: figure containing the plot.

                `matplotlib.axes.Axis`: axis containing the plot.

        '''
        idx = result_index

        fig, ax = share_fig_ax(fig, ax)

        mx, my = self.captures_simple[idx]['x'], self.captures_simple[idx]['y']
        if type.lower() in ('q', 'quiver'):
            dx, dy = mx - self.refx, my - self.refy
            ax.quiver(self.refx, self.refy, dx, dy, scale=1, units='xy', scale_units='xy')
        elif type.lower() in ('d', 'dots'):
            ax.scatter(self.refx, self.refy, c='k', s=8)
            ax.scatter(mx, my, c='r', s=8)

        ax.set(xlim=(0, self.sensor_size[0] * 1e3), xlabel=r'Detector X [$\mu m$]',
               ylim=(0, self.sensor_size[1] * 1e3), ylabel=r'Detector Y [$\mu m$]',
               aspect='equal')
        return fig, ax
Exemplo n.º 28
0
def plot_spectrum(spectrum_dict, xrange=(370, 730), yrange=(0, 100), smoothing=None, fig=None, ax=None):
    ''' Plots the spectrum.

    Args:
        xrange (`iterable`): pair of lower and upper x bounds.

        yrange (`iterable`): pair of lower and upper y bounds.

        smoothing (`float`): number of nanometers to smooth data by.  If None,
            do no smoothing.

        fig (`matplotlib.figure.Figure`): figure to plot in.

        ax (`matplotlib.axes.Axis`): axis to plot in.

    Returns:
        `tuple` containing:

            `matplotlib.figure.Figure`: figure containign the plot.

            `matplotlib.axes.Axis`: axis containing the plot.

    '''
    wvl, values = spectrum_dict['wvl'], spectrum_dict['values']
    if smoothing is not None:
        dx = wvl[1] - wvl[0]
        window_width = int(smoothing / dx)
        values = smooth(values, window_width, window='flat')

    lc = colorline(wvl, values, wvl, cmin=400, cmax=700, lw=5)
    fig, ax = share_fig_ax(fig, ax)
    ax.add_collection(lc)
    ax.set(xlim=xrange, xlabel=r'Wavelength $\lambda$ [nm]',
           ylim=yrange, ylabel='Transmission [%]')

    return fig, ax
Exemplo n.º 29
0
    def plot_tan_sag(self,
                     max_freq=200,
                     fig=None,
                     ax=None,
                     labels=('Tangential', 'Sagittal')):
        ''' Creates a plot of the tangential and sagittal MTF.

        Args:
            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.

            labels (`iterable`): set of labels for the two lines that will be plotted.

        Returns:
            `tuple` containing:
                fig (:class:`~matplotlib.pyplot.figure`): Figure containing the plot.

                ax (:class:`~matplotlib.pyplot.axis`): Axis containing the plot.

        '''
        ut, tan = self.tan
        us, sag = self.sag

        fig, ax = share_fig_ax(fig, ax)
        ax.plot(ut, tan, label=labels[0], linestyle='-', lw=3)
        ax.plot(us, sag, label=labels[1], linestyle='--', lw=3)
        ax.set(xlabel='Spatial Frequency [cy/mm]',
               ylabel='MTF [Rel 1.0]',
               xlim=(0, max_freq),
               ylim=(0, 1))
        plt.legend(loc='lower left')
        return fig, ax
Exemplo n.º 30
0
def cie_1976_plankian_locust(trange=(2000, 10000), num_points=100,
                             isotemperature_lines_at=None, isotemperature_du=0.025,
                             fig=None, ax=None):
    ''' draws the plankian locust on the CIE 1976 color diagram.

    Args:
        trange (`iterable`): (min,max) color temperatures.

        num_points (`int`): number of points to compute.

        isotemperature_lines_at (`iterable`): CCTs to plot isotemperature lines at,
            defaults to [2000, 3000, 4000, 5000, 6500, 10000] if None.
            set to False to not plot lines.

        isotemperature_du (`float`): delta-u, parameter, length in x of the isotemperature lines.

        fig (`matplotlib.figure.Figure`): figure to plot in.

        ax (`matplotlib.axes.Axis`): axis to plot in.

    Returns:
        `tuple` containing:

            `matplotlib.figure.Figure`. figure containing the plot.

            `matplotlib.axes.Axis`: axis containing the plot.

    '''
    cct = prepare_robertson_cct_data()
    cct_K, cct_u, cct_v, cct_dvdu = cct['K'], cct['u'], cct['v'], cct['dvdu']
    # compute the u', v' coordinates of the temperatures
    temps = np.linspace(trange[0], trange[1], num_points)
    interpf_u = interp1d(cct_K, cct_u)
    interpf_v = interp1d(cct_K, cct_v)
    u = interpf_u(temps)
    v = interpf_v(temps) * 1.5  # x1.5 converts 1960 uv to 1976 u' v'

    # if plotting isotemperature lines, compute the upper and lower points of
    # each line and connect them.
    plot_isotemp = True
    if isotemperature_lines_at is None:
        isotemperature_lines_at = np.asarray([2000, 3000, 4000, 5000, 6500, 10000])
        u_iso = interpf_u(isotemperature_lines_at)
        v_iso = interpf_v(isotemperature_lines_at)
        interpf_dvdu = interp1d(cct_u, cct_dvdu)

        dvdu = interpf_dvdu(u_iso)
        du = isotemperature_du / dvdu

        u_high = u_iso + du / 2
        u_low = u_iso - du / 2
        v_high = (v_iso + du / 2 * dvdu) * 1.5  # factors of 1.5 convert from uv to u'v'
        v_low = (v_iso - du / 2 * dvdu) * 1.5
    elif isotemperature_lines_at is False:
        plot_isotemp = False

    fig, ax = share_fig_ax(fig, ax)
    ax.plot(u, v, c='0.15')
    if plot_isotemp is True:
        for ul, uh, vl, vh in zip(u_low, u_high, v_low, v_high):
            ax.plot([ul, uh], [vl, vh], c='0.15')

    return fig, ax