예제 #1
0
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
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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
예제 #5
0
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)
예제 #6
0
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)
예제 #7
0
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)
예제 #8
0
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)
예제 #9
0
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
예제 #10
0
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
예제 #11
0
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
예제 #12
0
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),
        ))
예제 #13
0
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
예제 #14
0
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)
예제 #15
0
    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")