Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gui cosmetics #97

Merged
merged 6 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ prospect's Change Log
1.3.1 (unreleased)
------------------

* Added a Text widget to enter a spectrum number by hand.
armengau marked this conversation as resolved.
Show resolved Hide resolved
* Added ``-colors`` option for the main plot's curves.
* Handling the case of a missing spectrograph arm (PR `#95`_).
* Don't use mask information when marking bad pixels in SDSS data (PR `#94`_).

.. _`#95`: https://github.com/desihub/prospect/pull/95
.. _`#94`: https://github.com/desihub/prospect/pull/94

1.3.0 (2023-09-06)
Expand Down
7 changes: 7 additions & 0 deletions py/prospect/js/update_plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ var nsmooth = smootherslider.value;
// update VI widgets + infos for current spectrum
//
if (cb_obj == ispectrumslider) {
//
// Update ispec_input, avoiding recursive call
//
if (i_spectrum != parseInt(ispec_input.value)) {
ispec_input.value = String(i_spectrum);
}

//
// Update metadata using "shortcds" objects.
//
Expand Down
2 changes: 2 additions & 0 deletions py/prospect/scripts/prospect_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def _parse():
parser.add_argument('--titlepage_prefix', help='Prefix for html page title', type=str, default='DESI_spectra')
parser.add_argument('--top_metadata', help="""List of fibermap's metadata to be highlighted (display in the most visible table).
Note: if fibermap contains FIRST/LAST/NUM_XX, then including XX in top_metadata will display all of FIRST/LAST/NUM_XX.""", nargs='+', type=str, default=None)
parser.add_argument('--colors', help="""Customize the curve's colors: 3 colors should be given, associated respectively to the coadded data, the model and the noise.""", nargs='+', type=str, default=None)
parser.add_argument('--no_imaging', dest='with_imaging', help='Do not include thumb images from https://www.legacysurvey.org/viewer', action='store_false')
parser.add_argument('--no_noise', dest='with_noise', help='Do not display noise vectors associated to spectra', action='store_false')
parser.add_argument('--no_thumb_tab', dest='with_thumb_tab', help='Do not include a tab with spectra thumbnails', action='store_false')
Expand Down Expand Up @@ -296,6 +297,7 @@ def main():
'with_full_2ndfit': False,
'with_thumb_only_page': args.with_thumbnail_only_pages,
'std_template_file': args.std_template_file,
'colors': args.colors,
'with_imaging': args.with_imaging,
'with_noise': args.with_noise,
'with_thumb_tab': args.with_thumb_tab,
Expand Down
7 changes: 5 additions & 2 deletions py/prospect/viewer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def create_model(spectra, zcat, archetype_fit=False, archetypes_dir=None, templa


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,
colors=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,
Expand All @@ -165,6 +165,9 @@ def plotspectra(spectra, zcatalog=None, redrock_cat=None, notebook=False, html_d
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.
colors : :class:`list`, optional
Customize the curve's colors: 3 colors should be given, associated respectively to
the coadded data, the model and the noise.
with_imaging : :class:`bool`, optional
If ``False``, don't include thumb image from https://www.legacysurvey.org/viewer.
with_noise : :class:`bool`, optional
Expand Down Expand Up @@ -320,7 +323,7 @@ def plotspectra(spectra, zcatalog=None, redrock_cat=None, notebook=False, html_d
#-- Graphical objects --
#-------------------------

viewer_plots = ViewerPlots()
viewer_plots = ViewerPlots(colors=colors)
viewer_plots.create_mainfig(spectra, title, viewer_cds, survey,
with_noise=with_noise, with_coaddcam=with_coaddcam)
viewer_plots.create_zoomfig(viewer_cds,
Expand Down
27 changes: 19 additions & 8 deletions py/prospect/viewer/layouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ def __init__(self, plots, widgets, vi_widgets, with_vi_widgets=True):
vi_widgets : :class:`ViewerVIWidgets`
'''

#- Main 'navigator'
#- Main spectrum 'navigator'
self.navigator = bl.row(
bl.column(widgets.prev_button, width=widgets.navigation_button_width+15),
bl.column(widgets.next_button, width=widgets.navigation_button_width+20),
bl.column(widgets.ispectrumslider, width=plots.plot_width+(plots.plot_height//2)-(60*len(vi_widgets.vi_quality_labels)+2*widgets.navigation_button_width+35))
bl.column(widgets.ispectrumslider, width=plots.plot_width+(plots.plot_height//2)-(60*len(vi_widgets.vi_quality_labels)+2*widgets.navigation_button_width+35+100)),
bl.column(widgets.ispec_input, width=100),
background='#ececf9'
)

#- Redshift widgets
Expand Down Expand Up @@ -70,9 +72,12 @@ def __init__(self, plots, widgets, vi_widgets, with_vi_widgets=True):

#- VI widgets
if with_vi_widgets :
self.navigator.children.insert(1, bl.column(vi_widgets.vi_quality_input, width=60*len(vi_widgets.vi_quality_labels)) )
self.navigator.children.insert(1, bl.column(
vi_widgets.vi_quality_input,
width=60*len(vi_widgets.vi_quality_labels)
) )
if vi_widgets.vi_countdown_toggle is None :
vi_header_block = bl.column( Div(text="VI optional indications :"), width=300 )
vi_header_block = bl.column( Div(text="VI optional indications:"), width=300 )
else :
vi_header_block = bl.row(
bl.column( Div(text="VI optional indications :"), width=300 ),
Expand Down Expand Up @@ -124,14 +129,14 @@ def __init__(self, plots, widgets, vi_widgets, with_vi_widgets=True):
bl.column(bl.Spacer(width=30)),
bl.column(widgets.waveframe_buttons, width=120)
)
else :
else:
waveframe_block = bl.column(widgets.waveframe_buttons, width=120)
self.plot_widget_set.children.append(waveframe_block)
if widgets.model_select is not None :
self.plot_widget_set.children.insert(4, bl.column(widgets.model_select, width=200))

#- Assemble all widgets
if with_vi_widgets :
if with_vi_widgets:
self.full_widget_set = bl.column(
bl.row(
self.vi_widget_set,
Expand All @@ -140,7 +145,12 @@ def __init__(self, plots, widgets, vi_widgets, with_vi_widgets=True):
),
bl.column(vi_widgets.vi_guideline_div, width=2*widgets.plot_widget_width)
)
else : self.full_widget_set = self.plot_widget_set
else:
N = len(self.plot_widget_set.children) // 2
self.full_widget_set = bl.row(
bl.column(self.plot_widget_set.children[0:N]),
bl.column(self.plot_widget_set.children[N:])
)

self.main_bokehlayout = bl.column(
bl.row(plots.fig, bl.column(plots.imfig, plots.zoomfig), bl.Spacer(width=20)),
Expand All @@ -153,6 +163,7 @@ def __init__(self, plots, widgets, vi_widgets, with_vi_widgets=True):
bl.column(widgets.oii_undo_button, width=50),
),
self.navigator,
bl.column(bl.Spacer(height=10)),
self.full_widget_set,
sizing_mode='stretch_width'
)
Expand Down
20 changes: 15 additions & 5 deletions py/prospect/viewer/plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class ViewerPlots(object):
Encapsulates Bokeh plot-like objects that are part of prospect's GUI.
"""

def __init__(self):
def __init__(self, colors=None):
# "Hardcoded" plotting parameters here:
self.legend_outside_plot = True
if (self.legend_outside_plot):
Expand All @@ -102,9 +102,15 @@ def __init__(self):
self.plot_height=400
self.colors = dict(b='#1f77b4', r='#d62728', z='maroon', coadd='#d62728', brz='#d62728')
self.noise_colors = dict(b='greenyellow', r='green', z='forestgreen', coadd='green', brz='green')
self.model_color = 'black'
## overlap wavelengths are hardcoded, from 1907.10688 (Table 1)
self.overlap_waves = [ [5660, 5930], [7470, 7720] ]
self.alpha_overlapband = 0.03
if colors is not None:
assert len(colors)==3
self.colors['coadd'] = self.colors['brz'] = colors[0]
self.model_color = colors[1]
self.noise_colors['coadd'] = self.noise_colors['brz'] = colors[2]

self.fig = None
self.zoomfig = None
Expand Down Expand Up @@ -193,12 +199,16 @@ def create_mainfig(self, spectra, title, viewer_cds, survey, with_noise=True, wi

self.model_lines = list()
if viewer_cds.cds_model is not None:
lx = self.fig.line('plotwave', 'plotflux', source=viewer_cds.cds_model, line_color='black')
lx = self.fig.line('plotwave', 'plotflux',
source=viewer_cds.cds_model,
line_color=self.model_color)
self.model_lines.append(lx)

self.othermodel_lines = list()
if viewer_cds.cds_othermodel is not None :
lx = self.fig.line('plotwave', 'plotflux', source=viewer_cds.cds_othermodel, line_color='black', line_dash='dashed')
lx = self.fig.line('plotwave', 'plotflux',
source=viewer_cds.cds_othermodel,
line_color=self.model_color, line_dash='dashed')
self.othermodel_lines.append(lx)

legend_items = [("data", self.data_lines[-1::-1])] #- reversed to get blue as lengend entry
Expand Down Expand Up @@ -244,9 +254,9 @@ def create_zoomfig(self, viewer_cds, with_noise=True, with_coaddcam=True):
self.zoom_noise_lines.append(lx)

if viewer_cds.cds_model is not None:
lx = self.zoomfig.line('plotwave', 'plotflux', source=viewer_cds.cds_model, line_color='black')
lx = self.zoomfig.line('plotwave', 'plotflux', source=viewer_cds.cds_model, line_color=self.model_color)
if viewer_cds.cds_othermodel is not None :
lx = self.zoomfig.line('plotwave', 'plotflux', source=viewer_cds.cds_othermodel, line_color='black', line_dash='dashed')
lx = self.zoomfig.line('plotwave', 'plotflux', source=viewer_cds.cds_othermodel, line_color=self.model_color, line_dash='dashed')

#- Callback to update zoom window x-range
self.zoom_callback = CustomJS(
Expand Down
22 changes: 19 additions & 3 deletions py/prospect/viewer/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ def __init__(self, plots, nspec):
# Ispectrumslider's value controls which spectrum is displayed
# These two widgets call update_plot(), later defined
slider_end = nspec-1 if nspec > 1 else 0.5 # Slider cannot have start=end
self.ispectrumslider = Slider(start=0, end=slider_end, value=0, step=1, title='Spectrum (0 to '+str(nspec-1)+')')
slidertitle = 'Spectrum number (0 to '+str(nspec-1)+')'
self.ispectrumslider = Slider(start=0, end=slider_end, value=0, step=1, title=slidertitle)
self.smootherslider = Slider(start=0, end=26, value=0, step=1.0, title='Gaussian Sigma Smooth')
self.coaddcam_buttons = None
self.model_select = None
Expand All @@ -102,14 +103,28 @@ def add_navigation(self, nspec):
}
""")
self.next_callback = CustomJS(
args=dict(ispectrumslider=self.ispectrumslider, nspec=nspec),
code="""
args = dict(ispectrumslider=self.ispectrumslider, nspec=nspec),
code = """
if(ispectrumslider.value<nspec-1 && ispectrumslider.end>=1) {
ispectrumslider.value++
}
""")
self.prev_button.js_on_event('button_click', self.prev_callback)
self.next_button.js_on_event('button_click', self.next_callback)
#- Input spectrum number
self.ispec_input = TextInput(value=str(self.ispectrumslider.value), width=50)
self.ispec_input_callback = CustomJS(
args = dict(ispec_input=self.ispec_input, ispectrumslider=self.ispectrumslider, nspec=nspec),
code = """
var i_spec = parseInt(ispec_input.value) ;
if (Number.isInteger(i_spec) && i_spec>=0 && i_spec<nspec) {
// Avoid recursive call
if (i_spec != ispectrumslider.value) {
ispectrumslider.value = i_spec ;
}
}
""")
self.ispec_input.js_on_change('value', self.ispec_input_callback)

def add_resetrange(self, viewer_cds, plots):
#-----
Expand Down Expand Up @@ -495,6 +510,7 @@ def add_update_plot_callback(self, viewer_cds, plots, vi_widgets):
shortcds_table_c = self.shortcds_table_c,
shortcds_table_d = self.shortcds_table_d,
ispectrumslider = self.ispectrumslider,
ispec_input = self.ispec_input,
smootherslider = self.smootherslider,
z_input = self.z_input,
widgetinfos = self.cds_widgetinfos,
Expand Down