<jupyter_start><jupyter_text>InspectorInspector is a prototype DESI spectral viewer for use with jupyter notebooks at NERSC.  It is currently in a standalone package for exploratory development, but could be moved into desispec after it matures.<jupyter_code>import os
import inspector<jupyter_output><empty_output><jupyter_text>Loading SpectraUse `inspector.load_spectra(specfile)` to load a `spectra*.fits` file.  A matching `zbest*.fits` file should be in the same directory; otherwise use the optional `zbestfile` argument to specify the location of a corresponding redrock zbest output file.<jupyter_code>reduxdir = os.getenv('DESI_ROOT') + '/datachallenge/reference_runs/18.6/spectro/redux/mini'
specfile = reduxdir + '/spectra-64/53/5354/spectra-64-5354.fits'

sp = inspector.load_spectra(specfile)<jupyter_output><empty_output><jupyter_text>At this point you could sub-select the targets before plotting them,e.g. select just QSOs or just targetids that had previously been identified for expert followup.We'll show how to do that later, but for now we'll just proceed with plotting.  PlottingStart the interactive viewer with the `.plot()` command.* The large window displays a downsampled spectrum with best fit model overlaid.* Scanning the mouse over that plot shows a full-resolution zoom of that portion of the spectrum, which is particularly useful for scanning narrow emission lines.* Try the various tools at the top for panning, zooming, selecting.  When the wheel zoom tool is selected (default), using the scroll wheel will zoom in and out.  Point the mouse over the x or y axis before scrolling to zoom on just that axis.* Click on one of the legend entries to turn that item on/off.* The buttons at the bottom can be used to navigate between targets:  * **prev** / **next**: go to the previous or next target without recording visual inspection results  * the other buttons record visual inspection results and advance to the next target:    * **flag**: flag this target as having bad data    * **bad**: bad data (e.g. low-S/N) such that no redshift fitter could get a confident redshift    * **no**: the fitted redshift is incorrect    * **maybe**: the fitted redshift might be correct, but not confidently    * **yes**: the fitted redshift is definitely correct<jupyter_code>sp.plot()<jupyter_output><empty_output><jupyter_text>Toggle spectral linesThe display of emission and absorption lines can be toggled with the commands below.  ``True`` turns them on and ``False`` turns them off.  You can also call these functions with no arguments to simply flip the existing state.<jupyter_code>sp.emission(True)
sp.absorption(True)
sp.emission(False)
sp.absorption(False)
sp.emission()
sp.absorption()<jupyter_output><empty_output><jupyter_text>Visual inpsection resultsThe visual inspection results are stored in a `visual_scan` table which can be inspected and saved.  This table includes the scanner's username so that results from different scanners can be cross checked.  Tables for different spectra files can also be stacked to create truth tables.  Try navigating through a few spectra marking them as flag/bad/no/maybe/yes, then view the scan results table and save it.<jupyter_code>sp.visual_scan
sp.visual_scan.write('scan_results.fits', overwrite=True)<jupyter_output><empty_output><jupyter_text>Navigating through targetsYou can use the buttons to go the previous/next targets, or use the `.prev()` and `.next()` functions.  e.g. to watch a loop over all the targets, you could do the following (scroll back up to watch the display update)<jupyter_code>import time
sp.ispec = 0
for i in range(sp.nspec):
    sp.next()
    time.sleep(0.5)<jupyter_output><empty_output><jupyter_text>Sub-selecting targetsYou can use the `.select(targetids)` function to sub-select which targets to display.  This discards the othertargets, so if you want to get them back you have to reload the spectra from the beginning.  e.g. to select just targets identified as QSOs by redrock:<jupyter_code>qso_targetids = sp.zbest['TARGETID'][sp.zbest['SPECTYPE'] == 'QSO']
sp.select(qso_targetids)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07601065117404987, 'fraction_numerical': 0.004841442749939482, 'mean_word_length': 5.356923076923077, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '547024', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1189, 'n_tokens_neox': 1123, 'n_words': 508, 'path': 'inspector.ipynb', 'repo_name': 'sbailey/inspector', 'size': '4131'}