def match_redrock_zfit_to_spectra(redrockfile, spectra, Nfit=None) : ''' Read Redrock file, and return astropy Table of best fits matched to the targetids of input spectra - for each target, store arrays chi2[Nfit], coeff[Nfit], z[Nfit], spectype[Nfit], subtype[Nfit] - if Nfit is None: take all available fits ''' dummy, rr_table = redrock.results.read_zscan(redrockfile) rr_targets = rr_table['targetid'] if Nfit is None : ww, = np.where( (rr_targets == rr_targets[0]) ) Nfit = len(ww) matched_redrock_cat = Table(dtype=[('TARGETID', '<i8'), ('CHI2', '<f8', (Nfit,)), ('DELTACHI2', '<f8', (Nfit,)), ('COEFF', '<f8', (Nfit,10,)), ('Z', '<f8', (Nfit,)), ('ZERR', '<f8', (Nfit,)), ('ZWARN', '<i8', (Nfit,)), ('SPECTYPE', '<U6', (Nfit,)), ('SUBTYPE', '<U2', (Nfit,))]) for i_spec in range(spectra.num_spectra()) : ww, = np.where((rr_targets == spectra.fibermap['TARGETID'][i_spec])) if len(ww)<Nfit : raise RuntimeError("redrock table cannot match spectra with "+str(Nfit)+" best fits") ind = np.argsort(rr_table[ww]['chi2'])[0:Nfit] sub_table = rr_table[ww][ind] the_entry = [ spectra.fibermap['TARGETID'][i_spec] ] the_entry.append(sub_table['chi2']) the_entry.append(sub_table['deltachi2']) the_entry.append(sub_table['coeff']) the_entry.append(sub_table['z']) the_entry.append(sub_table['zerr']) the_entry.append(sub_table['zwarn']) the_entry.append(sub_table['spectype']) the_entry.append(sub_table['subtype']) matched_redrock_cat.add_row(the_entry) return matched_redrock_cat
def match_redrock_zfit_to_spectra(redrockfile, spectra, num_best_fit=3): ''' Read Redrock file, and return astropy Table of best fits matched to the targetids of input spectra - for each target, returns arrays chi2[N], coeff[N], z[N], spectype[N], subtype[N] - where N = num_best_fit ''' matched_redrock_cat = Table(dtype=[( 'TARGETID', '<i8'), ('chi2', '<f8', (num_best_fit, )), ('coeff', '<f8', ( num_best_fit, 10, )), ('z', '<f8', (num_best_fit, )), ('spectype', '<U6', ( num_best_fit, )), ('subtype', '<U2', (num_best_fit, ))]) dummy, rr_table = redrock.results.read_zscan(redrockfile) for i_spec in range(spectra.num_spectra()): ww, = np.where( (rr_table['targetid'] == spectra.fibermap['TARGETID'][i_spec])) if len(ww) < num_best_fit: raise RuntimeError("redrock table cannot match spectra with " + str(num_best_fit) + " best fits") ind = np.argsort(rr_table[ww]['chi2'])[0:num_best_fit] sub_table = rr_table[ww][ind][0:num_best_fit] the_entry = [spectra.fibermap['TARGETID'][i_spec]] the_entry.append(sub_table['chi2']) the_entry.append(sub_table['coeff']) the_entry.append(sub_table['z']) the_entry.append(sub_table['spectype']) the_entry.append(sub_table['subtype']) matched_redrock_cat.add_row(the_entry) return matched_redrock_cat
def main(): args = _parse() log = get_logger() specprod_dir = args.specprod_dir if specprod_dir is None: specprod_dir = desispec.io.specprod_root() webdir = args.webdir if webdir is None: webdir = os.environ[ "DESI_WWW"] + "/users/armengau/svdc2019c" # TMP, for test nights = desispec.io.get_nights(specprod_dir=specprod_dir) # TODO - Select night (eg. only last night) nights = nights[8:11] # TMP, for test for thenight in nights: # Get spectra from tiles dir - To consolidate specfiles = glob.glob( os.path.join(specprod_dir, "tiles/*/tilespectra-*-" + thenight + ".fits")) for f in specfiles: log.info("Working on file " + f) file_label = f[ f.find("tilespectra-") + 12:f.find(thenight) - 1] # From tile-based file description - To consolidate spectra = desispec.io.read_spectra(f) zbfile = f.replace("tilespectra", "zbest") zbest = Table.read(zbfile, 'ZBEST') # Handle several html pages per pixel : sort by TARGETID # NOTE : this way, individual spectra from the same target are together # Does it make sense ? (they have the same fit) nbpages = int(np.ceil((spectra.num_spectra() / args.nspecperfile))) sort_indices = np.argsort( spectra.fibermap["TARGETID"], kind='mergesort') # keep order of equal elts for i_page in range(1, 1 + nbpages): log.info(" * Page " + str(i_page) + " / " + str(nbpages)) the_indices = sort_indices[(i_page - 1) * args.nspecperfile:i_page * args.nspecperfile] thespec = myspecselect(spectra, indices=the_indices) thezb, kk = match_zcat_to_spectra(zbest, thespec) #model = plotframes.create_model(thespec, thezb) ### No VI results to display by default # vifile = os.environ['HOME']+"/prospect/vilist_prototype.fits" # vidata = match_vi_targets(vifile, thespec.fibermap["TARGETID"]) titlepage = "specviewer_night" + thenight + "_" + file_label + "_" + str( i_page) html_dir = webdir + "/nights/night" + thenight if not os.path.exists(html_dir): os.makedirs(html_dir) os.mkdir(html_dir + "/vignettes") plotspectra(thespec, zcatalog=thezb, title=titlepage, html_dir=html_dir)
def page_subset_expo(fdir, exposure, frametype, petals, html_dir, titlepage_prefix, mask, log, nspecperfile, snr_cut): ''' Running prospect from frames : loop over petals for a given exposure ''' nspec_done = 0 for petal_num in petals: frames = [ desispec.io.read_frame( os.path.join( fdir, frametype + "-" + band + petal_num + "-" + exposure + ".fits")) for band in ['b', 'r', 'z'] ] spectra = utils_specviewer.frames2spectra(frames, with_scores=True) if 'FIBERSTATUS' in spectra.fibermap.keys(): spectra = myspecselect.myspecselect(spectra, clean_fiberstatus=True) if spectra is None: return 0 # Selection if (mask != None) or (snr_cut != None): spectra = utils_specviewer.specviewer_selection( spectra, log=log, mask=mask, mask_type='CMX_TARGET', snr_cut=snr_cut, with_dirty_mask_merge=True) if spectra == 0: continue # Handle several html pages per exposure - sort by fiberid nspec_expo = spectra.num_spectra() log.info("Petal number " + petal_num + " : " + str(nspec_expo) + " spectra") sort_indices = np.argsort(spectra.fibermap["FIBER"]) nbpages = int(np.ceil((nspec_expo / nspecperfile))) for i_page in range(1, 1 + nbpages): log.info(" * Page " + str(i_page) + " / " + str(nbpages)) the_indices = sort_indices[(i_page - 1) * nspecperfile:i_page * nspecperfile] thespec = myspecselect.myspecselect(spectra, indices=the_indices) titlepage = titlepage_prefix + "_petal" + petal_num + "_" + str( i_page) plotframes.plotspectra(thespec, with_noise=True, with_coaddcam=True, is_coadded=False, title=titlepage, html_dir=html_dir, mask_type='CMX_TARGET', with_thumb_only_page=True) nspec_done += nspec_expo return nspec_done
def match_zcat_to_spectra(zcat_in, spectra): ''' zcat_in : astropy Table from redshift fitter creates a new astropy Table whose rows match the targetids of input spectra also returns the corresponding list of indices ''' zcat_out = Table(dtype=zcat_in.dtype) index_list = list() for i_spec in range(spectra.num_spectra()): ww, = np.where( (zcat_in['TARGETID'] == spectra.fibermap['TARGETID'][i_spec])) if len(ww) < 1: raise RuntimeError("zcat table cannot match spectra.") zcat_out.add_row(zcat_in[ww[0]]) index_list.append(ww[0]) return (zcat_out, index_list)
def match_zcat_to_spectra(zcat_in, spectra): ''' zcat_in : astropy Table from redshift fitter - creates a new astropy Table whose rows match the targetids of input spectra - also returns the corresponding list of indices - for each targetid, a unique row in zcat_in must exist. ''' zcat_out = Table(dtype=zcat_in.dtype) index_list = list() for i_spec in range(spectra.num_spectra()): ww, = np.where( (zcat_in['TARGETID'] == spectra.fibermap['TARGETID'][i_spec])) if len(ww) < 1: raise RuntimeError("No zcat entry for target " + str(spectra.fibermap['TARGETID'][i_spec])) if len(ww) > 1: raise RuntimeError("Several zcat entries for target " + str(spectra.fibermap['TARGETID'][i_spec])) zcat_out.add_row(zcat_in[ww[0]]) index_list.append(ww[0]) return (zcat_out, index_list)
def match_zcat_to_spectra(zcat_in, spectra) : ''' zcat_in : astropy Table from redshift fitter - creates a new astropy Table whose rows match the targetids of input spectra - also returns the corresponding list of indices - for each targetid, a unique row in zcat_in must exist. TODO : maybe rename this fct ? match_table_to_spectra ? => it also works whatever kind of input zcat : just has to be a table with 'TARGETID' key => in particular it's useful for "redrock_cat" tables ''' if zcat_in is None : return None zcat_out = Table(dtype=zcat_in.dtype) index_list = list() for i_spec in range(spectra.num_spectra()) : ww, = np.where((zcat_in['TARGETID'] == spectra.fibermap['TARGETID'][i_spec])) if len(ww)<1 : raise RuntimeError("No zcat entry for target "+str(spectra.fibermap['TARGETID'][i_spec])) if len(ww)>1 : raise RuntimeError("Several zcat entries for target "+str(spectra.fibermap['TARGETID'][i_spec])) zcat_out.add_row(zcat_in[ww[0]]) index_list.append(ww[0]) return (zcat_out, index_list)
def plotspectra(spectra, zcatalog=None, redrock_cat=None, notebook=False, html_dir=None, title=None, with_imaging=True, with_noise=True, with_thumb_tab=True, with_vi_widgets=True, top_metadata=None, vi_countdown=-1, with_thumb_only_page=False, with_coaddcam=True, mask_type='DESI_TARGET', model_from_zcat=True, model=None, num_approx_fits=None, with_full_2ndfit=True, template_dir=None, archetype_fit=False, archetypes_dir=None): '''Main prospect routine. From a set of spectra, creates a bokeh document used for VI, to be displayed as an HTML page or within a Jupyter notebook. Parameters ---------- spectra : :class:`~desispec.spectra.Spectra` or :class:`~specutils.Spectrum1D` or :class:`~specutils.SpectrumList` or list of :class:`~desispec.frame.Frame` Input spectra. :class:`~specutils.Spectrum1D` are assumed to be SDSS/BOSS/eBOSS. Otherwise DESI spectra or frames is assumed. zcatalog : :class:`~astropy.table.Table`, optional Redshift values, matched one-to-one with the input spectra. redrock_cat : :class:`~astropy.table.Table`, optional Redrock output (as defined in :func:`~prospect.utilities.match_redrock_zfit_to_spectra`). Entries must be matched one-by-one (in order) to spectra. notebook : :class:`bool`, optional If ``True``, bokeh outputs the viewer to a Jupyter notebook. html_dir : :class:`str`, optional Directory to store the HTML page if `notebook` is ``False``. title : :class:`str`, optional Title used to name the HTML page / the bokeh figure / the VI file. with_imaging : :class:`bool`, optional If ``False``, don't include thumb image from https://www.legacysurvey.org/viewer. with_noise : :class:`bool`, optional If ``False``, don't include uncertainty for each spectrum. with_thumb_tab : :class:`bool`, optional If ``False``, don't include a tab with spectra thumbnails. with_vi_widgets : :class:`bool`, optional Include widgets used to enter VI information. Set it to ``False`` if you do not intend to record VI files. top_metadata : :class:`list`, optional List of metadata to be highlighted in the top (most visible) table. Default values ['TARGETID', 'EXPID'] vi_countdown : :class:`int`, optional If ``>0``, add a countdown widget in the VI panel, with a value in minutes given by `vi_countdown``. with_thumb_only_page : :class:`bool`, optional When creating a static HTML (`notebook` is ``False``), a light HTML page including only the thumb gallery will also be produced. with_coaddcam : :class:`bool`, optional Include camera-coaddition, only relevant for DESI. mask_type : :class:`str`, optional (default: DESI_TARGET) Bitmask type to identify target categories in the spectra. For DESI these could be: DESI_TARGET, SV1_DESI_TARGET, SV1_BGS_TARGET, CMX_TARGET. model_from_zcat : :class:`bool`, optional If ``True``, model spectra will be computed from the input `zcatalog`. model : :func:`tuple`, optional If set, use this input set of model spectra instead of computing it from `zcatalog`. model consists of (mwave, mflux); model must be entry-matched to `zcatalog`. num_approx_fits : :class:`int`, optional Number of best-fit models to display, if `redrock_cat` is provided. By default, all best-fit models available in `redrock_cat` are diplayed. with_full_2ndfit : :class:`bool`, optional If ``True``, the second best-fit model from `redrock_cat` will be displayed without approximation (no undersampling, full resolution). template_dir : :class:`str`, optional Redrock template directory. archetype_fit : :class:`bool`, optional If ``True``, assume `zcatalog` derived from :command:`redrock --archetypes` and plot model accordingly. archetypes_dir : :class:`str`, optional Directory path for archetypes if not :envvar:`RR_ARCHETYPE_DIR`. ''' #- Check input spectra. #- Set masked bins to NaN for compatibility with bokeh. if _specutils_imported and isinstance(spectra, Spectrum1D): # We will assume this is from an SDSS/BOSS/eBOSS spPlate file. survey = 'SDSS' nspec = spectra.flux.shape[0] bad = (spectra.uncertainty.array == 0.0) | spectra.mask spectra.flux[bad] = np.nan elif _specutils_imported and isinstance(spectra, SpectrumList): # We will assume this is from a DESI spectra-64 file. survey = 'DESI' nspec = spectra[0].flux.shape[0] for s in spectra: bad = (s.uncertainty.array == 0.0) | s.mask s.flux[bad] = np.nan else: # DESI object (Spectra or list of Frame) survey = 'DESI' if _desispec_imported and isinstance(spectra, desispec.spectra.Spectra): nspec = spectra.num_spectra() elif _desispec_imported and isinstance(spectra, list) and isinstance( spectra[0], desispec.frame.Frame): # If inputs are frames, convert to a spectra object spectra = frames2spectra(spectra) nspec = spectra.num_spectra() if title is None: title = 'Night {} ExpID {} Spectrograph {}'.format( spectra.meta['NIGHT'], spectra.meta['EXPID'], spectra.meta['CAMERA'][1], ) else: raise ValueError("Unsupported type for input spectra. \n" + " _specutils_imported = " + str(_specutils_imported) + "\n" + " _desispec_imported = " + str(_desispec_imported)) for band in spectra.bands: bad = (spectra.ivar[band] == 0.0) | (spectra.mask[band] != 0) spectra.flux[band][bad] = np.nan #- No coaddition if spectra is already single-band if len(spectra.bands) == 1: with_coaddcam = False if title is None: title = "specviewer" #- Input zcatalog / model if zcatalog is not None: if survey == 'SDSS': if len(zcatalog) != spectra.flux.shape[0]: raise ValueError( 'zcatalog and spectra do not match (different lengths)') else: if np.any(zcatalog['TARGETID'] != spectra.fibermap['TARGETID']): raise ValueError( 'zcatalog and spectra do not match (different targetids)') if model is not None: # SDSS spectra will supply the model. assert not model_from_zcat mwave, mflux = model if len(mflux) != nspec: raise ValueError( "model fluxes do not match spectra (different nb of entries)" ) if model_from_zcat: # DESI spectra will obtain the model from templates. model = create_model(spectra, zcatalog, archetype_fit=archetype_fit, archetypes_dir=archetypes_dir, template_dir=template_dir) #----- #- Gather information into ColumnDataSource objects for Bokeh viewer_cds = ViewerCDS() viewer_cds.load_spectra(spectra, with_noise) if with_coaddcam: viewer_cds.init_coaddcam_spec(spectra, with_noise) if model is not None: viewer_cds.init_model(model) if redrock_cat is not None: # TODO unhardcode delta_lambd_templates=3 if np.any(redrock_cat['TARGETID'] != spectra.fibermap['TARGETID']): raise RuntimeError( 'redrock_cat and spectra do not match (different targetids)') if zcatalog is None: raise ValueError('Redrock_cat was provided but not zcatalog.') with_fit_templates = False if num_approx_fits == 0 else True template_dicts = make_template_dicts( redrock_cat, delta_lambd_templates=3, with_fit_templates=with_fit_templates, template_dir=template_dir) nfits_redrock_cat = template_dicts[1]['Nfit'] if num_approx_fits is None: num_approx_fits = nfits_redrock_cat if (num_approx_fits > nfits_redrock_cat): raise ValueError("num_approx_fits too large wrt redrock_cat") if with_full_2ndfit: zcat_2ndfit = create_zcat_from_redrock_cat(redrock_cat, fit_num=1) model_2ndfit = create_model(spectra, zcat_2ndfit, archetype_fit=archetype_fit, archetypes_dir=archetypes_dir, template_dir=template_dir) viewer_cds.init_model(model_2ndfit, second_fit=True) viewer_cds.init_othermodel(zcatalog) else: template_dicts = None viewer_cds.load_metadata(spectra, mask_type=mask_type, zcatalog=zcatalog, survey=survey) #------------------------- #-- Graphical objects -- #------------------------- viewer_plots = ViewerPlots() viewer_plots.create_mainfig(spectra, title, viewer_cds, survey, with_noise=with_noise, with_coaddcam=with_coaddcam) viewer_plots.create_zoomfig(viewer_cds, with_noise=with_noise, with_coaddcam=with_coaddcam) if with_imaging: viewer_plots.create_imfig(spectra) #----- #- Emission and absorption lines z = zcatalog['Z'][0] if (zcatalog is not None) else 0.0 viewer_cds.load_spectral_lines(z) viewer_plots.add_spectral_lines(viewer_cds, figure='main') viewer_plots.add_spectral_lines(viewer_cds, figure='zoom', label_offsets=[50, 5]) #------------------------- #-- Widgets and callbacks -- #------------------------- viewer_widgets = ViewerWidgets(viewer_plots, nspec) viewer_widgets.add_navigation(nspec) viewer_widgets.add_resetrange(viewer_cds, viewer_plots) viewer_widgets.add_redshift_widgets(z, viewer_cds, viewer_plots) viewer_widgets.add_oii_widgets(viewer_plots) viewer_plots.add_imfig_callback(viewer_widgets) if viewer_cds.cds_coaddcam_spec is not None: viewer_widgets.add_coaddcam(viewer_plots) if zcatalog is not None: show_zcat = True else: show_zcat = False if top_metadata is None: top_metadata = ['TARGETID', 'EXPID'] viewer_widgets.add_metadata_tables(viewer_cds, top_metadata=top_metadata, show_zcat=show_zcat, template_dicts=template_dicts) viewer_widgets.add_specline_toggles(viewer_cds, viewer_plots) if template_dicts is not None: viewer_cds.compute_median_spectra(spectra) viewer_widgets.add_model_select(viewer_cds, template_dicts, num_approx_fits, with_full_2ndfit=with_full_2ndfit) #----- #- VI-related widgets ## TODO if with_vi_widgets (need to adapt update_plot.js..) viewer_vi_widgets = ViewerVIWidgets(title, viewer_cds) viewer_vi_widgets.add_filename() viewer_vi_widgets.add_vi_issues(viewer_cds, viewer_widgets) viewer_vi_widgets.add_vi_z(viewer_cds, viewer_widgets) viewer_vi_widgets.add_vi_spectype(viewer_cds, viewer_widgets) viewer_vi_widgets.add_vi_comment(viewer_cds, viewer_widgets) viewer_vi_widgets.add_vi_quality(viewer_cds, viewer_widgets) viewer_vi_widgets.add_vi_scanner(viewer_cds) viewer_vi_widgets.add_guidelines() viewer_vi_widgets.add_vi_storage(viewer_cds, viewer_widgets) viewer_vi_widgets.add_vi_table(viewer_cds) if (vi_countdown > 0): viewer_vi_widgets.add_countdown(vi_countdown) viewer_widgets.add_update_plot_callback(viewer_cds, viewer_plots, viewer_vi_widgets, template_dicts) #----- #- Bokeh layout and output bokeh_layout = ViewerLayout(viewer_plots, viewer_widgets, viewer_vi_widgets, with_vi_widgets=with_vi_widgets) if with_thumb_tab: bokeh_layout.add_thumb_tab(spectra, viewer_plots, viewer_widgets, nspec) if notebook: bk.output_notebook() bk.show(bokeh_layout.full_viewer) else: if html_dir is None: raise RuntimeError("Need html_dir") html_page = os.path.join(html_dir, "specviewer_" + title + ".html") bk.output_file(html_page, title='DESI spectral viewer') bk.save(bokeh_layout.full_viewer) #----- #- "Light" Bokeh layout including only the thumbnail gallery if with_thumb_only_page: assert not notebook thumb_page = os.path.join(html_dir, "thumbs_specviewer_" + title + ".html") bk.output_file(thumb_page, title='DESI spectral viewer - thumbnail gallery') thumb_grid = StandaloneThumbLayout(spectra, viewer_plots, title) bk.save(thumb_grid.thumb_viewer)
def main(): args = _parse() log = get_logger() specprod_dir = args.specprod_dir if specprod_dir is None : specprod_dir = desispec.io.specprod_root() webdir = args.webdir if webdir is None : webdir = os.environ["DESI_WWW"]+"/users/armengau/svdc2019c" # TMP, for test # TODO - Selection on pixels based on existing specviewer pages if args.pixel_list is None : pixels = glob.glob( os.path.join(specprod_dir,"spectra-64/*/*") ) pixels = [x[x.rfind("/")+1:] for x in pixels] else : pixels = np.loadtxt(args.pixel_list, dtype=str) if args.random_pixels : random.shuffle(pixels) # Loop on pixels nspec_done = 0 for pixel in pixels : log.info("Working on pixel "+pixel) thefile = desispec.io.findfile('spectra', groupname=int(pixel), specprod_dir=specprod_dir) individual_spectra = desispec.io.read_spectra(thefile) spectra = coadd_targets(individual_spectra) zbfile = thefile.replace('spectra-64-', 'zbest-64-') if os.path.isfile(zbfile) : zbest = Table.read(zbfile, 'ZBEST') else : log.info("No associated zbest file found : skipping pixel") continue spectra = specviewer_selection(spectra, log=log, mask=args.mask, mask_type=args.mask_type, gmag_cut=args.gcut, rmag_cut=args.rcut, chi2cut=args.chi2cut, zbest=zbest) if spectra == 0 : continue # Handle several html pages per pixel : sort by TARGETID # TODO - Find a more useful sort ? nbpages = int(np.ceil((spectra.num_spectra()/args.nspecperfile))) sort_indices = np.argsort(spectra.fibermap["TARGETID"]) for i_page in range(1,1+nbpages) : log.info(" * Page "+str(i_page)+" / "+str(nbpages)) the_indices = sort_indices[(i_page-1)*args.nspecperfile:i_page*args.nspecperfile] thespec = myspecselect(spectra, indices=the_indices) thezb, kk = match_zcat_to_spectra(zbest,thespec) ### No VI results to display by default # VI "catalog" - location to define later .. # vifile = os.environ['HOME']+"/prospect/vilist_prototype.fits" # vidata = match_vi_targets(vifile, thespec.fibermap["TARGETID"]) titlepage = "pix"+pixel+"_"+str(i_page) if args.gcut is not None : titlepage = "gcut-"+str(args.gcut[0])+"-"+str(args.gcut[1])+"_"+titlepage if args.rcut is not None : titlepage = "rcut-"+str(args.rcut[0])+"-"+str(args.rcut[1])+"_"+titlepage if args.chi2cut is not None : titlepage = "chi2cut-"+str(args.chi2cut[0])+"-"+str(args.chi2cut[1])+"_"+titlepage if args.mask is not None : titlepage = args.mask+"_"+titlepage #model = create_model(thespec, thezb) html_dir = os.path.join(webdir,"pix"+pixel) if not os.path.exists(html_dir) : os.makedirs(html_dir) os.mkdir(html_dir+"/vignettes") plotspectra(thespec, zcatalog=zbest, model_from_zcat=True, model=None, title=titlepage, html_dir=html_dir, mask_type=args.mask_type) # for i_spec in range(thespec.num_spectra()) : # saveplot = html_dir+"/vignettes/pix"+pixel+"_"+str(i_page)+"_"+str(i_spec)+".png" # miniplot_spectrum(thespec, i_spec, model=model, saveplot=saveplot, smoothing = args.vignette_smoothing) nspec_done += thespec.num_spectra() # Stop running if needed, only once a full pixel is completed if args.nmax_spectra is not None : if nspec_done >= args.nmax_spectra : log.info(str(nspec_done)+" spectra done : no other pixel will be processed") break
def specviewer_selection(spectra, log=None, mask=None, mask_type=None, gmag_cut=None, rmag_cut=None, chi2cut=None, zbest=None, snr_cut=None, with_dirty_mask_merge=False, remove_scores=False): ''' Simple sub-selection on spectra based on meta-data. Implemented cuts based on : target mask ; photo mag (g, r) ; chi2 from fit ; SNR (in spectra.scores, BRZ) - if chi2cut : a catalog zbest must be provided, with entries matching exactly those of spectra ''' # SNR selection if snr_cut is not None: assert ((len(snr_cut) == 2) and (spectra.scores is not None)) for band in ['B', 'R', 'Z']: w, = np.where( (spectra.scores['MEDIAN_CALIB_SNR_' + band] > snr_cut[0]) & (spectra.scores['MEDIAN_CALIB_SNR_' + band] < snr_cut[1])) if len(w) == 0: if log is not None: log.info(" * No spectra with MEDIAN_CALIB_SNR_" + band + " in requested range") return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect( spectra, targets=targetids, remove_scores=remove_scores) # Target mask selection if mask is not None: assert mask_type in ['SV1_DESI_TARGET', 'DESI_TARGET', 'CMX_TARGET'] if mask_type == 'SV1_DESI_TARGET': assert (mask in sv1_desi_mask.names()) w, = np.where( (spectra.fibermap['SV1_DESI_TARGET'] & sv1_desi_mask[mask])) elif mask_type == 'DESI_TARGET': assert (mask in desi_mask.names()) w, = np.where((spectra.fibermap['DESI_TARGET'] & desi_mask[mask])) elif mask_type == 'CMX_TARGET': assert (mask in cmx_mask.names()) mask2 = None if with_dirty_mask_merge: # Self-explanatory... only for fast VI of minisv if mask in ['SV0_QSO', 'SV0_ELG', 'SV0_LRG']: mask2 = mask.replace('SV0', 'MINI_SV') if mask == 'SV0_BGS': mask2 = 'MINI_SV_BGS_BRIGHT' if mask in ['SV0_STD_FAINT', 'SV0_STD_BRIGHT']: mask2 = mask.replace('SV0_', '') if mask2 is None: w, = np.where( (spectra.fibermap['CMX_TARGET'] & cmx_mask[mask])) else: w, = np.where((spectra.fibermap['CMX_TARGET'] & cmx_mask[mask]) | (spectra.fibermap['CMX_TARGET'] & cmx_mask[mask2])) if len(w) == 0: if log is not None: log.info(" * No spectra with mask " + mask) return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect(spectra, targets=targetids, remove_scores=remove_scores) # Photometry selection if gmag_cut is not None: assert len(gmag_cut) == 2 # Require range [gmin, gmax] gmag = np.zeros(spectra.num_spectra()) w, = np.where((spectra.fibermap['FLUX_G'] > 0) & (spectra.fibermap['MW_TRANSMISSION_G'] > 0)) gmag[w] = -2.5 * np.log10( spectra.fibermap['FLUX_G'][w] / spectra.fibermap['MW_TRANSMISSION_G'][w]) + 22.5 w, = np.where((gmag > gmag_cut[0]) & (gmag < gmag_cut[1])) if len(w) == 0: if log is not None: log.info(" * No spectra with g_mag in requested range") return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect(spectra, targets=targetids) if rmag_cut is not None: assert len(rmag_cut) == 2 # Require range [rmin, rmax] rmag = np.zeros(spectra.num_spectra()) w, = np.where((spectra.fibermap['FLUX_R'] > 0) & (spectra.fibermap['MW_TRANSMISSION_R'] > 0)) rmag[w] = -2.5 * np.log10( spectra.fibermap['FLUX_R'][w] / spectra.fibermap['MW_TRANSMISSION_R'][w]) + 22.5 w, = np.where((rmag > rmag_cut[0]) & (rmag < rmag_cut[1])) if len(w) == 0: if log is not None: log.info(" * No spectra with r_mag in requested range") return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect(spectra, targets=targetids, remove_scores=remove_scores) # Chi2 selection if chi2cut is not None: assert len(chi2cut) == 2 # Require range [chi2min, chi2max] if np.any(zbest['TARGETID'] != spectra.fibermap['TARGETID']): raise RunTimeError( 'specviewer_selection : zbest and spectra do not match (different targetids)' ) w, = np.where((zbest['DELTACHI2'] > chi2cut[0]) & (zbest['DELTACHI2'] < chi2cut[1])) if len(w) == 0: if log is not None: log.info( " * No target in this pixel with DeltaChi2 in requested range" ) return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect(spectra, targets=targetids, remove_scores=remove_scores) return spectra
def create_model(spectra, zbest): ''' Returns model_wave[nwave], model_flux[nspec, nwave], row matched to zbest, which can be in a different order than spectra. ''' import redrock.templates from desispec.interpolation import resample_flux nspec = spectra.num_spectra() assert len(zbest) == nspec #- Load redrock templates; redirect stdout because redrock is chatty saved_stdout = sys.stdout sys.stdout = open('/dev/null', 'w') try: templates = dict() for filename in redrock.templates.find_templates(): tx = redrock.templates.Template(filename) templates[(tx.template_type, tx.sub_type)] = tx except Exception as err: sys.stdout = saved_stdout raise (err) sys.stdout = saved_stdout #- Empty model flux arrays per band to fill model_flux = dict() for band in spectra.bands: model_flux[band] = np.zeros(spectra.flux[band].shape) targetids = spectra.target_ids() for i in range(len(zbest)): zb = zbest[i] j = np.where(targetids == zb['TARGETID'])[0][0] tx = templates[(zb['SPECTYPE'], zb['SUBTYPE'])] coeff = zb['COEFF'][0:tx.nbasis] model = tx.flux.T.dot(coeff).T for band in spectra.bands: mx = resample_flux(spectra.wave[band], tx.wave * (1 + zb['Z']), model) model_flux[band][i] = spectra.R[band][j].dot(mx) #- Now combine to a single wavelength grid across all cameras #- TODO: assumes b,r,z all exist br_split = 0.5 * (spectra.wave['b'][-1] + spectra.wave['r'][0]) rz_split = 0.5 * (spectra.wave['r'][-1] + spectra.wave['z'][0]) keep = dict() keep['b'] = (spectra.wave['b'] < br_split) keep['r'] = (br_split <= spectra.wave['r']) & (spectra.wave['r'] < rz_split) keep['z'] = (rz_split <= spectra.wave['z']) model_wave = np.concatenate([ spectra.wave['b'][keep['b']], spectra.wave['r'][keep['r']], spectra.wave['z'][keep['z']], ]) mflux = np.concatenate([ model_flux['b'][:, keep['b']], model_flux['r'][:, keep['r']], model_flux['z'][:, keep['z']], ], axis=1) return model_wave, mflux
def plotspectra(spectra, zcatalog=None, model=None, notebook=False, title=None): ''' TODO: document ''' if notebook: bk.output_notebook() #- If inputs are frames, convert to a spectra object if isinstance(spectra, list) and isinstance(spectra[0], desispec.frame.Frame): spectra = frames2spectra(spectra) frame_input = True else: frame_input = False if frame_input and title is None: meta = spectra.meta title = 'Night {} ExpID {} Spectrograph {}'.format( meta['NIGHT'], meta['EXPID'], meta['CAMERA'][1], ) #- Gather spectra into ColumnDataSource objects for Bokeh nspec = spectra.num_spectra() cds_spectra = list() for band in spectra.bands: #- Set masked bins to NaN so that Bokeh won't plot them bad = (spectra.ivar[band] == 0.0) | (spectra.mask[band] != 0) spectra.flux[band][bad] = np.nan cdsdata = dict( origwave=spectra.wave[band].copy(), plotwave=spectra.wave[band].copy(), ) for i in range(nspec): key = 'origflux' + str(i) cdsdata[key] = spectra.flux[band][i] cdsdata['plotflux'] = cdsdata['origflux0'] cds_spectra.append(bk.ColumnDataSource(cdsdata, name=band)) #- Reorder zcatalog to match input targets #- TODO: allow more than one zcatalog entry with different ZNUM per targetid targetids = spectra.target_ids() if zcatalog is not None: ii = np.argsort(np.argsort(targetids)) jj = np.argsort(zcatalog['TARGETID']) kk = jj[ii] zcatalog = zcatalog[kk] #- That sequence of argsorts may feel like magic, #- so make sure we got it right assert np.all(zcatalog['TARGETID'] == targetids) assert np.all(zcatalog['TARGETID'] == spectra.fibermap['TARGETID']) #- Also need to re-order input model fluxes if model is not None: mwave, mflux = model model = mwave, mflux[kk] #- Gather models into ColumnDataSource objects, row matched to spectra if model is not None: mwave, mflux = model model_obswave = mwave.copy() model_restwave = mwave.copy() cds_model_data = dict( origwave=mwave.copy(), plotwave=mwave.copy(), plotflux=np.zeros(len(mwave)), ) for i in range(nspec): key = 'origflux' + str(i) cds_model_data[key] = mflux[i] cds_model_data['plotflux'] = cds_model_data['origflux0'] cds_model = bk.ColumnDataSource(cds_model_data) else: cds_model = None #- Subset of zcatalog and fibermap columns into ColumnDataSource target_info = list() for i, row in enumerate(spectra.fibermap): target_bit_names = ' '.join(desi_mask.names(row['DESI_TARGET'])) txt = 'Target {}: {}'.format(row['TARGETID'], target_bit_names) if zcatalog is not None: txt += '<BR/>{} z={:.4f} ± {:.4f} ZWARN={}'.format( zcatalog['SPECTYPE'][i], zcatalog['Z'][i], zcatalog['ZERR'][i], zcatalog['ZWARN'][i], ) target_info.append(txt) cds_targetinfo = bk.ColumnDataSource(dict(target_info=target_info), name='targetinfo') if zcatalog is not None: cds_targetinfo.add(zcatalog['Z'], name='z') plot_width = 800 plot_height = 400 # tools = 'pan,box_zoom,wheel_zoom,undo,redo,reset,save' tools = 'pan,box_zoom,wheel_zoom,reset,save' fig = bk.figure(height=plot_height, width=plot_width, title=title, tools=tools, toolbar_location='above', y_range=(-10, 20)) fig.toolbar.active_drag = fig.tools[1] #- box zoom fig.toolbar.active_scroll = fig.tools[2] #- wheel zoom fig.xaxis.axis_label = 'Wavelength [Å]' fig.yaxis.axis_label = 'Flux' fig.xaxis.axis_label_text_font_style = 'normal' fig.yaxis.axis_label_text_font_style = 'normal' colors = dict(b='#1f77b4', r='#d62728', z='maroon') data_lines = list() for spec in cds_spectra: lx = fig.line('plotwave', 'plotflux', source=spec, line_color=colors[spec.name]) data_lines.append(lx) if cds_model is not None: model_lines = list() lx = fig.line('plotwave', 'plotflux', source=cds_model, line_color='black') model_lines.append(lx) legend = Legend(items=[ ("data", data_lines[-1::-1]), #- reversed to get blue as lengend entry ("model", model_lines), ]) else: legend = Legend(items=[ ("data", data_lines[-1::-1]), #- reversed to get blue as lengend entry ]) fig.add_layout(legend, 'center') fig.legend.click_policy = 'hide' #- or 'mute' #- Zoom figure around mouse hover of main plot zoomfig = bk.figure( height=plot_height // 2, width=plot_height // 2, y_range=fig.y_range, x_range=(5000, 5100), # output_backend="webgl", toolbar_location=None, tools=[]) for spec in cds_spectra: zoomfig.line('plotwave', 'plotflux', source=spec, line_color=colors[spec.name], line_width=1, line_alpha=1.0) if cds_model is not None: zoomfig.line('plotwave', 'plotflux', source=cds_model, line_color='black') #- Callback to update zoom window x-range zoom_callback = CustomJS(args=dict(zoomfig=zoomfig), code=""" zoomfig.x_range.start = cb_obj.x - 100; zoomfig.x_range.end = cb_obj.x + 100; """) fig.js_on_event(bokeh.events.MouseMove, zoom_callback) #----- #- Emission and absorption lines z = zcatalog['Z'][0] if (zcatalog is not None) else 0.0 line_data, lines, line_labels = add_lines(fig, z=z) #----- #- Add widgets for controling plots z1 = np.floor(z * 100) / 100 dz = z - z1 zslider = Slider(start=0.0, end=4.0, value=z1, step=0.01, title='Redshift') dzslider = Slider(start=0.0, end=0.01, value=dz, step=0.0001, title='+ Delta redshift') dzslider.format = "0[.]0000" #- Observer vs. Rest frame wavelengths waveframe_buttons = RadioButtonGroup(labels=["Obs", "Rest"], active=0) ifiberslider = Slider(start=0, end=nspec - 1, value=0, step=1) if frame_input: ifiberslider.title = 'Fiber' else: ifiberslider.title = 'Target' zslider_callback = CustomJS( args=dict( spectra=cds_spectra, model=cds_model, targetinfo=cds_targetinfo, ifiberslider=ifiberslider, zslider=zslider, dzslider=dzslider, waveframe_buttons=waveframe_buttons, line_data=line_data, lines=lines, line_labels=line_labels, fig=fig, ), #- TODO: reorder to reduce duplicated code code=""" var z = zslider.value + dzslider.value var line_restwave = line_data.data['restwave'] var ifiber = ifiberslider.value var zfit = 0.0 if(targetinfo.data['z'] != undefined) { zfit = targetinfo.data['z'][ifiber] } // Observer Frame if(waveframe_buttons.active == 0) { var x = 0.0 for(var i=0; i<line_restwave.length; i++) { x = line_restwave[i] * (1+z) lines[i].location = x line_labels[i].x = x } for(var i=0; i<spectra.length; i++) { var data = spectra[i].data var origwave = data['origwave'] var plotwave = data['plotwave'] for (var j=0; j<plotwave.length; j++) { plotwave[j] = origwave[j] } spectra[i].change.emit() } // Update model wavelength array if(model) { var origwave = model.data['origwave'] var plotwave = model.data['plotwave'] for(var i=0; i<plotwave.length; i++) { plotwave[i] = origwave[i] * (1+z) / (1+zfit) } model.change.emit() } // Rest Frame } else { for(i=0; i<line_restwave.length; i++) { lines[i].location = line_restwave[i] line_labels[i].x = line_restwave[i] } for (var i=0; i<spectra.length; i++) { var data = spectra[i].data var origwave = data['origwave'] var plotwave = data['plotwave'] for (var j=0; j<plotwave.length; j++) { plotwave[j] = origwave[j] / (1+z) } spectra[i].change.emit() } // Update model wavelength array if(model) { var origwave = model.data['origwave'] var plotwave = model.data['plotwave'] for(var i=0; i<plotwave.length; i++) { plotwave[i] = origwave[i] / (1+zfit) } model.change.emit() } } """) zslider.js_on_change('value', zslider_callback) dzslider.js_on_change('value', zslider_callback) waveframe_buttons.js_on_click(zslider_callback) plotrange_callback = CustomJS(args=dict( zslider=zslider, dzslider=dzslider, waveframe_buttons=waveframe_buttons, fig=fig, ), code=""" var z = zslider.value + dzslider.value // Observer Frame if(waveframe_buttons.active == 0) { fig.x_range.start = fig.x_range.start * (1+z) fig.x_range.end = fig.x_range.end * (1+z) } else { fig.x_range.start = fig.x_range.start / (1+z) fig.x_range.end = fig.x_range.end / (1+z) } """) waveframe_buttons.js_on_click(plotrange_callback) smootherslider = Slider(start=0, end=31, value=0, step=1.0, title='Gaussian Sigma Smooth') target_info_div = Div(text=target_info[0]) #----- #- Toggle lines lines_button_group = CheckboxButtonGroup(labels=["Emission", "Absorption"], active=[]) lines_callback = CustomJS(args=dict(line_data=line_data, lines=lines, line_labels=line_labels), code=""" var show_emission = false var show_absorption = false if (cb_obj.active.indexOf(0) >= 0) { // index 0=Emission in active list show_emission = true } if (cb_obj.active.indexOf(1) >= 0) { // index 1=Absorption in active list show_absorption = true } for(var i=0; i<lines.length; i++) { if(line_data.data['emission'][i]) { lines[i].visible = show_emission line_labels[i].visible = show_emission } else { lines[i].visible = show_absorption line_labels[i].visible = show_absorption } } """) lines_button_group.js_on_click(lines_callback) # lines_button_group.js_on_change('value', lines_callback) #----- update_plot = CustomJS(args=dict( spectra=cds_spectra, model=cds_model, targetinfo=cds_targetinfo, target_info_div=target_info_div, ifiberslider=ifiberslider, smootherslider=smootherslider, zslider=zslider, dzslider=dzslider, lines_button_group=lines_button_group, fig=fig, ), code=""" var ifiber = ifiberslider.value var nsmooth = smootherslider.value target_info_div.text = targetinfo.data['target_info'][ifiber] if(targetinfo.data['z'] != undefined) { var z = targetinfo.data['z'][ifiber] var z1 = Math.floor(z*100) / 100 zslider.value = z1 dzslider.value = (z - z1) } function get_y_minmax(pmin, pmax, data) { // copy before sorting to not impact original, and filter out NaN var dx = data.slice().filter(Boolean) dx.sort() var imin = Math.floor(pmin * dx.length) var imax = Math.floor(pmax * dx.length) return [dx[imin], dx[imax]] } // Smoothing kernel var kernel = []; for(var i=-2*nsmooth; i<=2*nsmooth; i++) { kernel.push(Math.exp(-(i**2)/(2*nsmooth))) } var kernel_offset = Math.floor(kernel.length/2) // Smooth plot and recalculate ymin/ymax // TODO: add smoother function to reduce duplicated code var ymin = 0.0 var ymax = 0.0 for (var i=0; i<spectra.length; i++) { var data = spectra[i].data var plotflux = data['plotflux'] var origflux = data['origflux'+ifiber] for (var j=0; j<plotflux.length; j++) { if(nsmooth == 0) { plotflux[j] = origflux[j] } else { plotflux[j] = 0.0 var weight = 0.0 // TODO: speed could be improved by moving `if` out of loop for (var k=0; k<kernel.length; k++) { var m = j+k-kernel_offset if((m >= 0) && (m < plotflux.length)) { var fx = origflux[m] if(fx == fx) { plotflux[j] = plotflux[j] + fx * kernel[k] weight += kernel[k] } } } plotflux[j] = plotflux[j] / weight } } spectra[i].change.emit() tmp = get_y_minmax(0.01, 0.99, plotflux) ymin = Math.min(ymin, tmp[0]) ymax = Math.max(ymax, tmp[1]) } // update model if(model) { var plotflux = model.data['plotflux'] var origflux = model.data['origflux'+ifiber] for (var j=0; j<plotflux.length; j++) { if(nsmooth == 0) { plotflux[j] = origflux[j] } else { plotflux[j] = 0.0 var weight = 0.0 // TODO: speed could be improved by moving `if` out of loop for (var k=0; k<kernel.length; k++) { var m = j+k-kernel_offset if((m >= 0) && (m < plotflux.length)) { var fx = origflux[m] if(fx == fx) { plotflux[j] = plotflux[j] + fx * kernel[k] weight += kernel[k] } } } plotflux[j] = plotflux[j] / weight } } model.change.emit() } // update y_range if(ymin<0) { fig.y_range.start = ymin * 1.4 } else { fig.y_range.start = ymin * 0.6 } fig.y_range.end = ymax * 1.4 """) smootherslider.js_on_change('value', update_plot) ifiberslider.js_on_change('value', update_plot) #----- #- Add navigation buttons navigation_button_width = 30 prev_button = Button(label="<", width=navigation_button_width) next_button = Button(label=">", width=navigation_button_width) prev_callback = CustomJS(args=dict(ifiberslider=ifiberslider), code=""" if(ifiberslider.value>0) { ifiberslider.value-- } """) next_callback = CustomJS(args=dict(ifiberslider=ifiberslider, nspec=nspec), code=""" if(ifiberslider.value<nspec+1) { ifiberslider.value++ } """) prev_button.js_on_event('button_click', prev_callback) next_button.js_on_event('button_click', next_callback) #----- slider_width = plot_width - 2 * navigation_button_width navigator = bk.Row( widgetbox(prev_button, width=navigation_button_width), widgetbox(next_button, width=navigation_button_width + 20), widgetbox(ifiberslider, width=slider_width - 20)) bk.show( bk.Column( bk.Row(fig, zoomfig), widgetbox(target_info_div, width=plot_width), navigator, widgetbox(smootherslider, width=plot_width // 2), bk.Row( widgetbox(waveframe_buttons, width=120), widgetbox(zslider, width=plot_width // 2 - 60), widgetbox(dzslider, width=plot_width // 2 - 60), ), widgetbox(lines_button_group), ))
def specviewer_selection(spectra, log=None, mask=None, mask_type=None, gmag_cut=None, rmag_cut=None, chi2cut=None, zbest=None, snr_cut=None): ''' Simple sub-selection on spectra based on meta-data. Implemented cuts based on : target mask ; photo mag (g, r) ; chi2 from fit ; SNR (in spectra.scores, BRZ) ''' # Target mask selection if mask is not None: assert mask_type in ['SV1_DESI_TARGET', 'DESI_TARGET', 'CMX_TARGET'] if mask_type == 'SV1_DESI_TARGET': assert (mask in sv1_desi_mask.names()) w, = np.where( (spectra.fibermap['SV1_DESI_TARGET'] & sv1_desi_mask[mask])) elif mask_type == 'DESI_TARGET': assert (mask in desi_mask.names()) w, = np.where((spectra.fibermap['DESI_TARGET'] & desi_mask[mask])) elif mask_type == 'CMX_TARGET': assert (mask in cmx_mask.names()) w, = np.where((spectra.fibermap['CMX_TARGET'] & cmx_mask[mask])) if len(w) == 0: if log is not None: log.info(" * No spectra with mask " + mask) return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect(spectra, targets=targetids) # Photometry selection if gmag_cut is not None: assert len(gmag_cut) == 2 # Require range [gmin, gmax] gmag = np.zeros(spectra.num_spectra()) w, = np.where((spectra.fibermap['FLUX_G'] > 0) & (spectra.fibermap['MW_TRANSMISSION_G'] > 0)) gmag[w] = -2.5 * np.log10( spectra.fibermap['FLUX_G'][w] / spectra.fibermap['MW_TRANSMISSION_G'][w]) + 22.5 w, = np.where((gmag > gmag_cut[0]) & (gmag < gmag_cut[1])) if len(w) == 0: if log is not None: log.info(" * No spectra with g_mag in requested range") return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect(spectra, targets=targetids) if rmag_cut is not None: assert len(rmag_cut) == 2 # Require range [rmin, rmax] rmag = np.zeros(spectra.num_spectra()) w, = np.where((spectra.fibermap['FLUX_R'] > 0) & (spectra.fibermap['MW_TRANSMISSION_R'] > 0)) rmag[w] = -2.5 * np.log10( spectra.fibermap['FLUX_R'][w] / spectra.fibermap['MW_TRANSMISSION_R'][w]) + 22.5 w, = np.where((rmag > rmag_cut[0]) & (rmag < rmag_cut[1])) if len(w) == 0: if log is not None: log.info(" * No spectra with r_mag in requested range") return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect(spectra, targets=targetids) # SNR selection ## TODO check it !! May not work ... if snr_cut is not None: assert ((len(snr_cut) == 2) and (spectra.scores is not None)) for band in ['B', 'R', 'Z']: w, = np.where( (spectra.scores['MEDIAN_CALIB_SNR_' + band] > snr_cut[0]) & (spectra.scores['MEDIAN_CALIB_SNR_' + band] < snr_cut[1])) if len(w) == 0: if log is not None: log.info(" * No spectra with MEDIAN_CALIB_SNR_" + band + " in requested range") return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect(spectra, targets=targetids) # Chi2 selection if chi2cut is not None: assert len(chi2cut) == 2 # Require range [chi2min, chi2max] assert (zbest is not None) thezb, kk = match_zcat_to_spectra(zbest, spectra) w, = np.where((thezb['DELTACHI2'] > chi2cut[0]) & (thezb['DELTACHI2'] < chi2cut[1])) if len(w) == 0: if log is not None: log.info( " * No target in this pixel with DeltaChi2 in requested range" ) return 0 else: targetids = spectra.fibermap['TARGETID'][w] spectra = myspecselect.myspecselect(spectra, targets=targetids) return spectra
def main(): args = _parse() datadir = os.environ['DESI_ROOT'] + "/" + args.datadir specfiles = glob.glob(datadir + "/*/*/spectra*") specfiles = specfiles[0:2] # TMP # Get list of exposures with associated files # Todo : select exposures not yet processed dict_exposures = {} for thespecfile in specfiles: spectra = desispec.io.read_spectra(thespecfile) pp = np.unique(spectra.fibermap['EXPID']) for the_expo in pp: if the_expo not in dict_exposures.keys(): dict_exposures[the_expo] = [thespecfile] else: dict_exposures[the_expo].append(thespecfile) # Loop on exposures for exposure, thespecfiles in dict_exposures.items(): print("* Working on exposure " + str(exposure)) print("* ( Nb of files : " + str(len(thespecfiles)) + " )") for ii, thefile in enumerate(thespecfiles): thespec = desispec.io.read_spectra(thefile) zbfile = thefile.replace('spectra-64-', 'zbest-64-') thezb = Table.read(zbfile, 'ZBEST') # First creation of spectra with metadata + zbest if ii == 0: spectra = desispec.spectra.Spectra(meta=thespec.meta, extra=thespec.extra) zbest = Table(dtype=thezb.dtype) thespec = myspecselect(thespec, expids=[exposure]) spectra.update(thespec) for i_zb in range(len(thezb)): zbest.add_row(thezb[i_zb]) # Handle several html pages per exposure : sort by fibers nbpages = int(np.ceil((spectra.num_spectra() / args.nspecperfile))) fiberlist = np.unique(spectra.fibermap["FIBER"]) if len(fiberlist) != spectra.num_spectra(): print("!! Several times the same fiber in exposure ??") for i_page in range(1, 1 + nbpages): print("** Page " + str(i_page) + " / " + str(nbpages)) thespec = myspecselect( spectra, fibers=fiberlist[(i_page - 1) * args.nspecperfile:i_page * args.nspecperfile]) thezb = match_zbest_to_spectra(zbest, thespec) # VI "catalog" - location to define later .. vifile = os.environ['HOME'] + "/prospect/vilist_prototype.fits" vidata = match_vi_targets(vifile, thespec.fibermap["TARGETID"]) titlepage = "specviewer_expo" + str(exposure) + "_fiberset" + str( i_page) model = create_model(thespec, thezb) savedir = args.webdir + "/exposures/expo" + str(exposure) if not os.path.exists(savedir): os.mkdir(savedir) os.mkdir(savedir + "/vignettes") plotspectra(thespec, zcatalog=thezb, vidata=vidata, model=model, title=titlepage, savedir=savedir)
print("* ( Nb of files : "+str(len(thespecfiles))+" )") for ii,thefile in enumerate(thespecfiles) : thespec = desispec.io.read_spectra(thefile) zbfile = thefile.replace('spectra-64-', 'zbest-64-') thezb = Table.read(zbfile, 'ZBEST') # First creation of spectra with metadata + zbest if ii==0 : spectra = desispec.spectra.Spectra(meta=thespec.meta, extra=thespec.extra) zbest = Table(dtype=thezb.dtype) thespec = myspecselect.myspecselect(thespec, expids=[exposure]) spectra.update(thespec) for i_zb in range(len(thezb)) : zbest.add_row(thezb[i_zb]) # Handle several html pages per exposure : sort by fibers nbpages = int(np.ceil((spectra.num_spectra()/args.nspecperfile))) fiberlist = np.unique(spectra.fibermap["FIBER"]) if len(fiberlist)!=spectra.num_spectra() : print("!! Several times the same fiber in exposure ??") for i_page in range(1,1+nbpages) : print("** Page "+str(i_page)+" / "+str(nbpages)) thespec = myspecselect.myspecselect(spectra, fibers=fiberlist[(i_page-1)*args.nspecperfile:i_page*args.nspecperfile]) thezb = utils_specviewer.match_zbest_to_spectra(zbest,thespec) # VI "catalog" - location to define later .. vifile = os.environ['HOME']+"/prospect/vilist_prototype.fits" vidata = utils_specviewer.match_vi_targets(vifile, thespec.fibermap["TARGETID"]) titlepage = "specviewer_expo"+str(exposure)+"_fiberset"+str(i_page) model = plotframes.create_model(thespec, thezb) savedir=args.webdir+"/exposures/expo"+str(exposure) if not os.path.exists(savedir) : os.mkdir(savedir) os.mkdir(savedir+"/vignettes")