Browse Source

Initial window done but with many issues

pull/1/head
Benito Marcote 9 months ago
parent
commit
34eba30fcf
  1. 228
      app.py
  2. 46
      vlbiplanobs/graphical_elements.py

228
app.py

@ -286,36 +286,75 @@ def update_pickband_tooltip(a_wavelength):
]
@app.callback([Output('initial-timeselection-div-guess', 'hidden'),
Output('initial-timeselection-div-epoch', 'hidden')],
[Input('initial-timeselection', 'value')])
# @app.callback([Output('initial-timeselection-div-guess', 'hidden'),
# Output('initial-timeselection-div-epoch', 'hidden')],
# [Input('initial-timeselection', 'value')])
# def type_initial_time_selection(time_selection_selected):
# """Modifies the hidden message related to the two options about how to pick the observing time.
# """
# print('checked')
# return [time_selection_selected, not time_selection_selected]
@app.callback([Output('timeselection-div-guess', 'hidden'),
Output('timeselection-div-epoch', 'hidden')],
[Input('timeselection', 'value')])
def type_time_selection(time_selection_selected):
"""Modifies the hidden message related to the two options about how to pick the observing time.
"""
print('checked2')
return [time_selection_selected, not time_selection_selected]
@app.callback([Output('band', 'value'),
Output('array', 'value'),
Output('e-EVN', 'value'),
Output('timeselection', 'value'),
Output('starttime', 'date'),
Output('starthour', 'value'),
Output('duration', 'value'),
Output('source', 'value')],
[Input('initial-band', 'value'),
Input('initial-array', 'value'),
Input('initial-e-EVN', 'value'),
Input('initial-timeselection', 'value'),
Input('initial-starttime', 'date'),
Input('initial-starthour', 'value'),
Input('initial-duration', 'value'),
Input('initial-source', 'value'),
]
)
def sync_values_from_wizard_to_main(*args):
return args
@app.callback(Output('main-window2', 'children'),
[Input('button-initial-wizard', 'n_clicks'),
Input('button-initial-expert', 'n_clicks'),
Input('button-pickband', 'n_clicks'),
[Input('button-pickband', 'n_clicks'),
Input('button-picknetwork', 'n_clicks'),
Input('button-picktimes', 'n_clicks'),
Input('button-mode-continuum', 'n_clicks'),
Input('button-mode-line', 'n_clicks')],
[State('band', 'value'),
State('array', 'value'),
State('e-EVN', 'value'),
State('initial-timeselection', 'value'), # True if date are provided, False if guessing
State('starttime', 'date'),
State('starthour', 'value'),
State('duration', 'value')
])
def intro_choices(clicks_wizard, clicks_expert, clicks_pickband, clicks_picknetwork, clicks_picktimes,
clicks_continuum, clicks_line,
[State('initial-band', 'value'),
State('initial-array', 'value'),
State('initial-e-EVN', 'value'),
State('initial-timeselection', 'value'),
State('initial-starttime', 'date'),
State('initial-starthour', 'value'),
State('initial-duration', 'value'),
State('initial-source', 'value'),
State('datarate', 'value'),
State('subbands', 'value'),
State('channels', 'value'),
State('pols', 'value'),
State('inttime', 'value'),
State('initial-timeselection', 'value')])
def intro_choices(clicks_pickband, clicks_picknetwork, clicks_picktimes, clicks_continuum, clicks_line,
a_wavelength, a_array, is_eEVN, time_selection, starttime, starthour, obs_duration):
if clicks_expert is not None:
return html.Div(id='main-window2', children=main_page(results_visible=False))
return main_page(results_visible=False, show_compute_button=True)
elif clicks_wizard is not None:
return initial_page('band')
elif clicks_pickband is not None:
@ -382,7 +421,46 @@ def intro_choices(clicks_wizard, clicks_expert, clicks_pickband, clicks_picknetw
return dash.no_update
def initial_page(choice_card):
def initial_page():
"""Initial window with the two options to select: guided or manual setup of the observation.
"""
return [
html.Div(className='row justify-content-center', id='main-window2',
children=html.Div(className='col-sm-6 justify-content-center',
children=[html.Div(className='justify-content-center',
children=[#html.H3("Welcome!"),
html.P(["The EVN Observation Planner allows you to plan observations with the ",
html.A(href="https://www.evlbi.org", children="European VLBI Network"),
" (EVN) and other Very Long Baseline Interferometry (VLBI) networks. "
"The EVN Observation Planner helps you to determine when your source "
"can be observed by the different antennas, and provides the expected "
"outcome of these observations, like the expected sensitivity or resolution."]),
html.Br(),
html.Div(ge.initial_window_start(app))
])
])
)]
@app.callback(Output('full-window', 'children'),
[Input('button-initial-wizard', 'n_clicks'),
Input('button-initial-expert', 'n_clicks')])
def choice_for_setup(do_wizard, do_expert):
if (do_expert is not None) or (do_wizard is not None):
return [
html.Div(id='main-window', hidden=do_expert is None,
children=main_page(show_compute_button=do_expert is not None)),
html.Div(id='main-window2', hidden=do_expert is not None,
children=[dbc.Checklist(id='is_line', options=[{'label': 'line obs', 'value': False}],
value=[])] if do_expert is not None else choice_page('band'))
]
else:
return dash.no_update
def choice_page(choice_card):
"""Initial window with the introduction to the EVN Observation Planner and the band selection.
"""
return [
@ -398,42 +476,22 @@ def initial_page(choice_card):
"outcome of these observations, like the expected sensitivity or resolution."]),
html.Br(),
*[
html.Div(hidden=False if choice_card == 'choice' else True,
children=ge.initial_window_start(app)),
# html.Div(hidden=False if choice_card == 'choice' else True,
# children=ge.initial_window_start(app)),
html.Div(hidden=False if choice_card == 'band' else True,
children=ge.initial_window_pick_band()),
html.Div(hidden=False if choice_card == 'network' else True,
children=ge.initial_window_pick_network(vlbi_networks_names,
sorted_networks, all_antennas)),
children=ge.initial_window_pick_network(vlbi_networks_names)),
html.Div(hidden=False if choice_card == 'time' else True,
children=ge.initial_window_pick_time()),
html.Div(hidden=False if choice_card == 'mode' else True,
children=ge.initial_window_pick_mode(app)),
html.Div(hidden=False if choice_card == 'final' else True,
children=ge.initial_window_final()),
html.Div(hidden=True) if choice_card == 'final' else html.Div(hidden=True,
children=[
dcc.Dropdown(id='datarate',
placeholder="Select the data rate...",
options=[{'label': fs.data_rates[dr], 'value': dr} \
for dr in fs.data_rates], value=256, persistence=True),
dcc.Dropdown(id='subbands', placeholder="Select no. subbands...",
options=[{'label': fs.subbands[sb], 'value': sb} \
for sb in fs.subbands], value=1, persistence=True),
dcc.Dropdown(id='channels', placeholder="Select no. channels...",
options=[{'label': fs.channels[ch], 'value': ch} \
for ch in fs.channels], value=2048, persistence=True),
dcc.Dropdown(id='pols', placeholder="Select polarizations...",
options=[{'label': fs.polarizations[p], 'value': p} \
for p in fs.polarizations], value=4, persistence=True),
dcc.Dropdown(id='inttime', placeholder="Select integration time...",
options=[{'label': fs.inttimes[it], 'value': it} \
for it in fs.inttimes], value=2, persistence=True)
])
],
], style={'text:align': 'justify !important'})
])
)] #, *main_page(None, True)]
)]
@ -441,8 +499,7 @@ def initial_page(choice_card):
def main_page(results_visible=False, summary_output=None, fig_elev_output=None,
fig_ant_output=None, fig_uv_output=None, show_compute_button=True):
return [# First row containing all buttons/options, list of telescopes, and button with text output
#TODO: to remove when implementing nebwie approachXXXXXXXXXXXXXXXXX
html.Div(id='main-window2'),
html.Div(id='main-window2', hidden=True),
dcc.ConfirmDialog(id='global-error', message=''),
# Elements in second column (checkboxes with all stations)
html.Div(className='container-fluid', children=[
@ -504,18 +561,18 @@ def main_page(results_visible=False, summary_output=None, fig_elev_output=None,
dbc.FormGroup([
dbc.RadioItems(options=[{"label": "I don't have a preferred epoch", "value": False},
{"label": "I know the observing epoch", "value": True}],
value=False, id="initial-timeselection", inline=True, persistence=True),
value=False, id="timeselection", inline=True, persistence=True),
], inline=True),
html.Div(children=[
html.Div(id='initial-timeselection-div-guess', className='row justify-content-center',
children=[
html.Div(id='timeselection-div-guess', className='row justify-content-center',
hidden=False, children=[
html.Small("Choose the first option to find out when your source "
"may be visible (by >3 telescopes).", style={'color': '#999999'}),
html.Small("Note that this option may not provide the best (expected) "
"results in case of combining different networks very far apart "
"(e.g. LBA and EVN).", style={'color': '#999999'})
]),
html.Div(id='initial-timeselection-div-epoch', children=[
html.Div(id='timeselection-div-epoch', hidden=True, children=[
html.Label('Start of observation (UTC)'),
*ge.tooltip(idname='popover-startime', message="Select the date and "
"time of the start of the observation (Universal, UTC, "
@ -785,7 +842,7 @@ def main_page(results_visible=False, summary_output=None, fig_elev_output=None,
@app.callback(Output('onsourcetime-label', 'children'),
[Input('onsourcetime', 'value'),
Input('duration', 'value'),
Input('initial-timeselection', 'value')])
Input('timeselection', 'value')])
def update_onsourcetime_label(onsourcetime, total_duration, defined_epoch):
"""Keeps the on-source time label updated with the value selected by the user.
"""
@ -819,8 +876,11 @@ def update_bandwidth_label(datarate, npols):
@app.callback([Output(f"check_{s.codename}", 'checked') for s in all_antennas] + \
[Output(f"check_{s.codename}", 'disabled') for s in all_antennas] + \
[Output('datarate', 'value')],
[Input('band', 'value'), Input('array', 'value'), Input('e-EVN', 'value')])
def select_antennas(selected_band, selected_networks, is_eEVN):
[Input('band', 'value'),
Input('array', 'value'),
Input('e-EVN', 'value'),
Input('is_line', 'value')])
def select_antennas(selected_band, selected_networks, is_eEVN, is_line):
"""Given a selected band and selected default networks, it selects the associated
antennas from the antenna list.
"""
@ -846,6 +906,31 @@ def select_antennas(selected_band, selected_networks, is_eEVN):
@app.callback([Output('initial-error_starttime', 'children'),
Output('initial-error_duration', 'children')],
[Input('initial-starttime', 'date'), Input('starthour', 'value'),
Input('initial-duration', 'value')])
def check_initial_obstime(starttime, starthour, duration):
"""Verify the introduced times/dates for correct values.
Once the user has introduced all values for the start and end of the observation,
it guarantees that they have the correct shape:
- the duration of the observation is > 0 hours.
- The total observing length is less than five days (value chosen for computational reasons).
"""
if duration is None:
return "", ""
if (not isinstance(duration, float)) and (not isinstance(duration, int)):
return "", "Must be a number"
if duration <= 0.0:
return "", "The duration must be a positive number"
elif duration > 4*24:
return "", "Please, put an observation shorter than 4 days"
return "", ""
@app.callback([Output('error_starttime', 'children'),
Output('error_duration', 'children')],
[Input('starttime', 'date'), Input('starthour', 'value'),
@ -871,6 +956,31 @@ def check_obstime(starttime, starthour, duration):
return "", ""
@app.callback([Output('initial-error_source', 'children'),
Output('initial-error_source', 'style')],
[Input('initial-source', 'value')])
def get_initial_source(source_coord):
"""Verifies that the introduced source coordinates have a right format.
If they are correct, it does nothing. If they are incorrect, it shows an error label.
"""
if source_coord != 'hh:mm:ss dd:mm:ss' and source_coord != None and source_coord != '':
if len(source_coord) > 30:
# Otherwise the source name check gets too slow
return "Name too long.", {'color': '#a01d26'}
try:
dummy_target = observation.Source(convert_colon_coord(source_coord), 'Source')
return '', dash.no_update
except ValueError as e:
try:
dummy_target = coord.get_icrs_coordinates(source_coord)
return dummy_target.to_string('hmsdms'), {'color': '#999999'}
except coord.name_resolve.NameResolveError as e:
return "Unrecognized name. Use 'hh:mm:ss dd:mm:ss' or 'XXhXXmXXs XXdXXmXXs'", {'color': '#a01d26'}
else:
return '', dash.no_update
@app.callback([Output('error_source', 'children'),
Output('error_source', 'style')],
[Input('source', 'value')])
@ -922,7 +1032,7 @@ def get_source(source_coord):
State('channels', 'value'),
State('pols', 'value'),
State('inttime', 'value'),
State('initial-timeselection', 'value'),
State('timeselection', 'value'),
State('tabs', 'value')] + \
[State(f"check_{s.codename}", 'checked') for s in all_antennas])
def compute_observation(n_clicks, band, starttime, starthour, duration, source, onsourcetime,
@ -979,14 +1089,8 @@ def compute_observation(n_clicks, band, starttime, starthour, duration, source,
return *[temp if out_center else temp[::-1]][0], dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update
if not epoch_selected:
try:
if starttime is not None:
utc_times, _ = observation.Observation.guest_times_for_source(target_source,
stations.Stations('Observation', itertools.compress(all_antennas, ants)),
Time(dt.strptime(f"{starttime} 00:00", "%Y-%m-%d %H:%M"), format='datetime',
scale='utc'))
else:
utc_times, _ = observation.Observation.guest_times_for_source(target_source,
stations.Stations('Observation', itertools.compress(all_antennas, ants)))
utc_times, _ = observation.Observation.guest_times_for_source(target_source,
stations.Stations('Observation', itertools.compress(all_antennas, ants)))
except observation.SourceNotVisible:
temp = [alert_message([
html.P(["Your source cannot be observed within the arranged observation.",
@ -1166,8 +1270,8 @@ app.layout = html.Div([
])
]),
html.Div([html.Br(), html.Br()]),
html.Div(id='main-window', children=main_page(False))])
# html.Div(id='main-window', children=initial_page('choice'))])
html.Div(id='full-window', children=html.Div(id='main-window', children=main_page(False)))])
# html.Div(id='full-window', children=initial_page())])

46
vlbiplanobs/graphical_elements.py

@ -429,7 +429,7 @@ def initial_window_pick_band():
], style={'text:align': 'justify !important'}),
html.Br(),
html.Div(className='justify-content-center', children=[html.Div(
dcc.Slider(id='band', min=0, max=len(fs.bands)-1,
dcc.Slider(id='initial-band', min=0, max=len(fs.bands)-1,
value=tuple(fs.bands).index('18cm'), step=-1,
marks={i: fq for i,fq in enumerate(fs.bands)},
persistence=True, # tooltip={'always_visible': True, 'placement': 'top'},
@ -443,7 +443,7 @@ def initial_window_pick_band():
]
def initial_window_pick_network(vlbi_networks, sorted_networks, all_antennas, selected_band):
def initial_window_pick_network(vlbi_networks):
"""Initial window to introduce the default VLBI network(s) to be used.
It will only allow the ones that can observe at the given wavelength.
"""
@ -455,7 +455,7 @@ def initial_window_pick_network(vlbi_networks, sorted_networks, all_antennas, se
]),
html.Br(),
html.Div(className='justify-content-center', children=[
dcc.Dropdown(id='array', options=[{'label': vlbi_networks[n], 'value': n} \
dcc.Dropdown(id='initial-array', options=[{'label': vlbi_networks[n], 'value': n} \
for n in vlbi_networks], value=[], persistence=True, multi=True)
]),
html.Br(),
@ -467,7 +467,7 @@ def initial_window_pick_network(vlbi_networks, sorted_networks, all_antennas, se
"not all telescopes are capable for this and the bandwidth "
"may be limited. Observations during the e-EVN epochs.")
]),
dbc.Checklist(id='e-EVN', className='checkbox', persistence=True,
dbc.Checklist(id='initial-e-EVN', className='checkbox', persistence=True,
options=[{'label': ' e-EVN mode',
'value': 'e-EVN'}], value=[]),
]),
@ -476,25 +476,6 @@ def initial_window_pick_network(vlbi_networks, sorted_networks, all_antennas, se
# html.Div(className='row', children=[
# html.Div(),
# ]),
html.Div(id='antennas-div', hidden=True, className='container', children=[
html.Div(className='antcheck', children=[html.Br(), html.Br(),
html.Label(html.H4(f"{sorted_networks[an_array]}"),
style={'width': '100%'}),
html.Br(),
html.Div(className='antcheck', children=[
dbc.FormGroup([
Checkbox(id=f"check_{s.codename}", persistence=True,
className='custom-control-input',
disabled=not s.has_band(selected_band)),
dbc.Label(s.name, html_for=f"check_{s.codename}",
id=f"_input_{s.codename}",
className='custom-control-label')
], check=True, inline=True,
className="custom-checkbox custom-control custom-control-inline")
for s in all_antennas if s.network == an_array
])
]) for an_array in sorted_networks
]),
html.Br(),
html.Div(className='row justify-content-center',
children=html.Button('Continue', id='button-picknetwork',
@ -534,7 +515,7 @@ def initial_window_pick_time():
"time). You will also see the day of the year (DOY) in "
"brackets once the date is selected."),
html.Br(),
dcc.DatePickerSingle(id='starttime', date=None, min_date_allowed=dt(1900, 1, 1),
dcc.DatePickerSingle(id='initial-starttime', date=None, min_date_allowed=dt(1900, 1, 1),
max_date_allowed=dt(2100, 1, 1),
display_format='DD-MM-YYYY (DDD)',
placeholder='Start date',
@ -542,18 +523,18 @@ def initial_window_pick_time():
initial_visible_month=dt.today(),
persistence=True,
className='form-picker'),
dcc.Dropdown(id='starthour', placeholder="Start time (UTC)", value=None,
dcc.Dropdown(id='initial-starthour', placeholder="Start time (UTC)", value=None,
options=[{'label': f"{hm//60:02n}:{hm % 60:02n}", \
'value': f"{hm//60:02n}:{hm % 60:02n}"} \
for hm in range(0, 24*60, 15)],
persistence=True, className='form-hour'),
html.Small(id='error_starttime', style={'color': 'red'},
html.Small(id='initial-error_starttime', style={'color': 'red'},
className='form-text text-muted'),
html.Label('Duration of the observation (in hours)'),
html.Div(className='form-group', children=[
dcc.Input(id='duration', value=None, type='number', className='form-control',
dcc.Input(id='initial-duration', value=None, type='number', className='form-control',
placeholder="Duration in hours", persistence=True, inputMode='numeric'),
html.Small(id='error_duration', style={'color': 'red'},
html.Small(id='initial-error_duration', style={'color': 'red'},
className='form-text text-muted')
])
])
@ -566,16 +547,13 @@ def initial_window_pick_time():
"00h00m00s 00d00m00s."]),
html.Br(),
html.Div(className='form-group', children=[
dcc.Input(id='source', value=None, type='text',
dcc.Input(id='initial-source', value=None, type='text',
className='form-control', placeholder="hh:mm:ss dd:mm:ss",
persistence=True),
html.Small(id='error_source', style={'color': '#999999'},
html.Small(id='initial-error_source', style={'color': '#999999'},
className='form-text'),
])
]),
html.Div(hidden=True, children=[dcc.Slider(id='onsourcetime', min=20, max=100, step=5, value=70,
marks={i: str(i) for i in range(20, 101, 10)},
persistence=True)]),
html.Span(style={'height': '2rem'}),
html.Div(className='row justify-content-center',
children=html.Button('Continue', id='button-picktimes',
@ -641,8 +619,6 @@ def initial_window_final():
html.Div(className='col-9 text-center justify-content-center', children=[
dcc.Loading(id="loading", children=[html.Div(id="loading-output")],
type="dot"),
dcc.Loading(id="loading2", children=[html.Div(id="loading-output2")],
type="dot")
]),
dcc.ConfirmDialog(id='global-error', message='')
])]

Loading…
Cancel
Save