Source code for webbpsf.jupyter_gui

import logging
import matplotlib
import astropy.io.fits as fits

import poppy
from . import webbpsf_core
from . import roman
from . import utils


_log = logging.getLogger('webbpsf')



[docs] def show_notebook_interface(instrumentname): """ Show Jupyter notebook widget interface Parameters ----------- instrumentname : string one of 'NIRCam','NIRSpec','NIRISS','FGS','MIRI' or 'WFI' """ if instrumentname.upper()=='WFI': instrument = roman.WFI() show_notebook_interface_wfi(instrument) else: instrument = webbpsf_core.instrument(instrumentname) show_notebook_interface_jwst(instrument)
def show_notebook_interface_wfi(instrument): # Widget related imports. # (Currently not a hard dependency for the full webbpsf package, so we import # within the function.) import ipywidgets as widgets from IPython.display import display, clear_output from matplotlib import pyplot as plt try: import synphot except ImportError: raise ImportError(f"For now, synphot must be installed to use the notebook interface") # Clean up some warnings we know about so as not to scare the users import warnings from matplotlib.cbook import MatplotlibDeprecationWarning warnings.simplefilter('ignore', MatplotlibDeprecationWarning) warnings.simplefilter('ignore', fits.verify.VerifyWarning) def make_binding_for_attribute(attribute): def callback(trait_name, new_value): setattr(instrument, attribute, new_value) return callback filter_selection = widgets.ToggleButtons( options=instrument.filter_list, value=instrument.filter, description='Filter:' ) filter_selection.on_trait_change( make_binding_for_attribute('filter'), name='selected_label' ) display(filter_selection) monochromatic_wavelength = widgets.BoundedFloatText( value=0.76, min=0.6, max=2.0, ) monochromatic_wavelength.disabled = True monochromatic_toggle = widgets.Checkbox(description='Monochromatic calculation?') def update_monochromatic(trait_name, new_value): filter_selection.disabled = new_value monochromatic_wavelength.disabled = not new_value monochromatic_toggle.on_trait_change(update_monochromatic, name='value') display(widgets.HTML(value='''<p style="padding: 1em 0;"> <span style="font-style:italic; font-size:1.0em"> Monochromatic calculations can be performed for any wavelength in the 0.6 to 2.0 &micro;m range. </span></p>''')) # kludge monochromatic_controls = widgets.HBox(children=( monochromatic_toggle, widgets.HTML(value='<span style="display: inline-block; width: 0.6em;"></span>'), monochromatic_wavelength, widgets.HTML(value='<span style="display: inline-block; width: 0.25em;"></span> &micro;m '), )) display(monochromatic_controls) display(widgets.HTML(value="<hr>")) source_selection = widgets.Select( options=poppy.specFromSpectralType('', return_list=True), value='G0V', description="Source spectrum" ) display(source_selection) display(widgets.HTML(value="<hr>")) sca_selection = widgets.Dropdown( options=instrument.detector_list, value=instrument.detector, description='Detector:' ) sca_selection.on_trait_change( make_binding_for_attribute('detector'), name='selected_label' ) display(sca_selection) detector_field_points = [ ('Top left', (4.0, 4092.0)), ('Bottom left', (4.0, 4.0)), ('Center', (2048.0, 2048.0)), ('Top right', (4092.0, 4092.0)), ('Bottom right', (4092.0, 4.0)), ] # enforce ordering of buttons detector_field_point_labels = [a[0] for a in detector_field_points] detector_field_points = dict(detector_field_points) def set_field_position(trait_name, new_value): instrument.detector_position = detector_field_points[new_value] field_position = widgets.ToggleButtons(options=detector_field_point_labels, value='Center', description='Detector field point:') field_position.on_trait_change(set_field_position, name='selected_label') display(field_position) calculate_button = widgets.Button( description="Calculate PSF", width='10em', color='white', background_color='#00c403', border_color='#318732' ) display_osys_button = widgets.Button( description="Display Optical System", width='13em', color='white', background_color='#005fc4', border_color='#224A75' ) clear_button = widgets.Button( description="Clear Output", width='10em', color='white', background_color='#ed4747', border_color='#911C1C' ) progress = widgets.HTML(value='<progress>') OUTPUT_FILENAME = 'psf.fits' DOWNLOAD_BUTTON_HTML = """ <a class="btn btn-info" href="files/{}" target="_blank"> Download FITS image from last calculation </a> """ download_link = widgets.HTML(value=DOWNLOAD_BUTTON_HTML.format(OUTPUT_FILENAME)) def disp(*args): progress.visible = True plt.figure(figsize=(12, 8)) instrument.display() progress.visible = None def calc(*args): progress.visible = True if monochromatic_toggle.value is True: psf = instrument.calc_psf( monochromatic=monochromatic_wavelength.value * 1e-6, display=True, outfile=OUTPUT_FILENAME, overwrite=True ) else: source = poppy.specFromSpectralType(source_selection.value) _log.debug("Got source type {}: {}".format(source_selection.value, source)) psf = instrument.calc_psf( source=source, display=True, outfile=OUTPUT_FILENAME, overwrite=True ) fig, (ax_oversamp, ax_detsamp) = plt.subplots(1, 2) poppy.display_psf(psf, ax=ax_oversamp) poppy.display_psf(psf, ax=ax_detsamp, ext='DET_SAMP') progress.visible = None download_link.visible = True def clear(*args): clear_output() progress.visible = None download_link.visible = None calculate_button.on_click(calc) display_osys_button.on_click(disp) clear_button.on_click(clear) display(widgets.HTML(value="<br/>")) # kludge buttons = widgets.HBox(children=[calculate_button, display_osys_button, clear_button]) display(buttons) # Insert the progress bar, hidden by default display(progress) progress.visible = None # and the download link display(download_link) download_link.visible = None def show_notebook_interface_jwst(instrument): """ Show Jupyter Notebook interface, for a JWST instrument Parameters ------------- instrument : string or object either a webbpsf instrument object, e.g. `NIRCam()` or the string name of an instrument. Example -------- nc = webbpsf.NIRCam() webbpsf.show_notebook_interface(nc) """ # Widget related imports. # (Currently not a hard dependency for the full webbpsf package, so we import # within the function.) import ipywidgets as widgets from IPython.display import display, clear_output from matplotlib import pyplot as plt if isinstance(instrument, str): instrument = instrument(instrument) try: import synphot except ImportError: raise ImportError(f"For now, synphot must be installed to use the notebook interface") # Clean up some warnings we know about so as not to scare the users import warnings from matplotlib.cbook import MatplotlibDeprecationWarning warnings.simplefilter('ignore', MatplotlibDeprecationWarning) warnings.simplefilter('ignore', fits.verify.VerifyWarning) def make_binding_for_attribute(attribute): def callback(trait_name, new_value): if new_value == 'None': setattr(instrument, attribute, None) else: setattr(instrument, attribute, new_value) return callback display(widgets.HTML(value='''<p style="padding: 1em 0;"> <span style="font-weight:bold; font-size:1.0em"> Notebook Interface for {} PSF sims </span></p>'''.format(instrument.name))) filter_selection = widgets.Dropdown( options=instrument.filter_list, value=instrument.filter, description='Filter:') filter_selection.on_trait_change( make_binding_for_attribute('filter'), name='selected_label' ) display(filter_selection) wl_bounds = (5., 30., 10.0) if instrument.name=='MIRI' else (0.6, 5.3, 2.0) monochromatic_wavelength = widgets.BoundedFloatText( value=wl_bounds[2], min=wl_bounds[0], max=wl_bounds[1], ) monochromatic_wavelength.disabled = True monochromatic_toggle = widgets.Checkbox(description='Monochromatic calculation?') def update_monochromatic(trait_name, new_value): filter_selection.disabled = new_value monochromatic_wavelength.disabled = not new_value monochromatic_toggle.on_trait_change(update_monochromatic, name='value') display(widgets.HTML(value='''<p style="padding: 1em 0;"> <span style="font-style:italic; font-size:1.0em"> Monochromatic calculations can be performed for any wavelength in the {} to {} &micro;m range. </span></p>'''.format(*wl_bounds))) # kludge monochromatic_controls = widgets.HBox(children=( monochromatic_toggle, widgets.HTML(value='<span style="display: inline-block; width: 0.6em;"></span>'), monochromatic_wavelength, widgets.HTML(value='<span style="display: inline-block; width: 0.25em;"></span> &micro;m '), )) display(monochromatic_controls) display(widgets.HTML(value="<hr>")) if instrument.name != 'FGS': image_selection = widgets.Dropdown( options=['None'] + instrument.image_mask_list, value=str(instrument.image_mask), description='Image Mask:') image_selection.on_trait_change( make_binding_for_attribute('image_mask'), name='selected_label' ) display(image_selection) pupil_selection = widgets.Dropdown( options=['None'] + instrument.pupil_mask_list, value=str(instrument.pupil_mask), description='Pupil Mask: ') pupil_selection.on_trait_change( make_binding_for_attribute('pupil_mask'), name='selected_label' ) display(pupil_selection) display(widgets.HTML(value="<hr>")) source_selection = widgets.Dropdown( options=poppy.specFromSpectralType('', return_list=True), value='G0V', description="Source spectrum" ) display(source_selection) display(widgets.HTML(value="<hr>")) calculate_button = widgets.Button( description="Calculate PSF", width='10em', color='white', background_color='#00c403', border_color='#318732' ) display_osys_button = widgets.Button( description="Display Optical System", width='13em', color='white', background_color='#005fc4', border_color='#224A75' ) clear_button = widgets.Button( description="Clear Output", width='10em', color='white', background_color='#ed4747', border_color='#911C1C' ) progress = widgets.HTML(value='<progress>') OUTPUT_FILENAME = 'psf.fits' DOWNLOAD_BUTTON_HTML = """ <a class="btn btn-info" href="files/{}" target="_blank"> Download FITS image from last calculation </a> """ download_link = widgets.HTML(value=DOWNLOAD_BUTTON_HTML.format(OUTPUT_FILENAME)) def disp(*args): progress.visible = True plt.figure(figsize=(12, 8)) instrument.display() progress.visible = None def calc(*args): progress.visible = True if monochromatic_toggle.value is True: psf = instrument.calc_psf( monochromatic=monochromatic_wavelength.value * 1e-6, display=True, outfile=OUTPUT_FILENAME, overwrite=True ) else: source = poppy.specFromSpectralType(source_selection.value) _log.debug("Got source type {}: {}".format(source_selection.value, source)) psf = instrument.calc_psf( source=source, display=True, outfile=OUTPUT_FILENAME, overwrite=True ) fig, (ax_oversamp, ax_detsamp) = plt.subplots(1, 2,figsize=(12, 4)) title1 = "PSF sim for {}, {}\n".format(instrument.name, instrument.filter) poppy.display_psf(psf, ax=ax_oversamp, title=title1+"Oversampled PSF") poppy.display_psf(psf, ax=ax_detsamp, ext='DET_SAMP', title=title1+'Detector pixel sampled PSF') progress.visible = None download_link.visible = True def clear(*args): clear_output() progress.visible = None download_link.visible = None calculate_button.on_click(calc) display_osys_button.on_click(disp) clear_button.on_click(clear) display(widgets.HTML(value="<br/>")) # kludge buttons = widgets.HBox(children=[calculate_button, display_osys_button, clear_button]) display(buttons) # Insert the progress bar, hidden by default display(progress) progress.visible = None # and the download link display(download_link) download_link.visible = None