Browse Source

Fully working v3.0

tags/v3.1
Benito Marcote 6 months ago
parent
commit
11139d5f15
10 changed files with 143 additions and 148 deletions
  1. +24
    -38
      app.py
  2. BIN
      assets/network-kvn.jpeg
  3. +51
    -14
      assets/style.css
  4. BIN
      assets/waves-Xcm.pxd/QuickLook/Icon.tiff
  5. BIN
      assets/waves-Xcm.pxd/QuickLook/Thumbnail.tiff
  6. +0
    -33
      assets/waves-Xcm.pxd/data/selectionForContentTransform/meta
  7. +0
    -12
      assets/waves-Xcm.pxd/data/selectionForContentTransform/shapeSelection/meta
  8. BIN
      assets/waves-Xcm.pxd/data/selectionForContentTransform/shapeSelection/path
  9. BIN
      assets/waves-Xcm.pxd/metadata.info
  10. +68
    -51
      vlbiplanobs/graphical_elements.py

+ 24
- 38
app.py View File

@@ -85,15 +85,15 @@ default_arrays = {'EVN': ['Ef', 'Hh', 'Jb2', 'Mc', 'Nt', 'Ur', 'On', 'Sr', 'T6',
'Ov', 'Pt', 'Gb'],
'EHT': ['ALMA', 'Pv', 'LMT', 'PdB', 'SMA', 'JCMT', 'APEX', 'SMT', 'SPT']}

vlbi_networks_names = {'EVN': 'EVN: European VLBI Network',
'eMERLIN': 'e-MERLIN',
'LBA': 'LBA: Australian Long Baseline Array',
'VLBA': 'VLBA: Very Long Baseline Array',
'KVN': 'KVN: Korean VLBI Network',
vlbi_networks_names = {'EVN': 'European VLBI Network',
'eMERLIN': 'eMERLIN',
'LBA': 'Australian Long Baseline Array',
'VLBA': 'Very Long Baseline Array',
'KVN': 'Korean VLBI Network',
# 'Global VLBI': 'Global VLBI (VLBA+EVN)',
'HSA': 'HSA: High Sensitivity Array',
'GMVA': 'GMVA: Global mm-VLBI Array',
'EHT': 'EHT: Event Horizon Telescope'}
'HSA': 'High Sensitivity Array',
'GMVA': 'Global mm-VLBI Array',
'EHT': 'Event Horizon Telescope'}

#TODO: this will be included per station (but maybe it needs to remain):
default_datarates = {'EVN': 2048, 'e-EVN': 2048, 'eMERLIN': 4096, 'LBA': 1024, 'VLBA': 4096, 'KVN': 4096,
@@ -146,7 +146,7 @@ def get_doc_text():
temp += [ge.create_accordion_card(a_topic, dcc.Markdown(parsed_text),
id=str(i), is_open=False)]

return html.Div(temp, className='col-12 accordion')
return html.Div(temp, className='col-12 accordion shadow-1-strong')


@app.callback([Output(f"collapse-{i}", "is_open") for i in range(len(doc_files))],
@@ -216,7 +216,8 @@ def update_sensitivity(obs):
cards += ge.summary_card_beam(app, obs)
cards += ge.summary_card_rms(app, obs)
cards += ge.summary_card_fov(app, obs)
return [html.Div(className='card-deck col-12 justify-content-center', children=cards)]
return [html.Div(className='card-deck col-12 justify-content-center',
children=cards)]


def arrays_with_band(arrays, a_band):
@@ -268,7 +269,7 @@ def update_pickband_tooltip(a_wavelength):
a_band = tuple(fs.bands)[a_wavelength]
return [dbc.Card(dbc.CardBody([
html.H5([html.Img(height='30rem',
src=app.get_asset_url(f"waves-{a_band.replace('.', '_')}.svg"),
src=app.get_asset_url(f"waves-{a_band.replace('.', '_')}.png"),
alt='Band: ', className='d-inline-block'),
html.Span(f"{fs.bands[a_band].split('(')[0].strip()}",
style={'float': 'right'})
@@ -316,16 +317,17 @@ def type_time_selection(time_selection_selected):




@app.callback(Output('band', 'value'),
Input('initial-band', 'value'), prevent_initial_call=True)
def band_from_initial(initial_value):
return tuple(fs.bands)[initial_value] if initial_value is not None else dash.no_update


@app.callback(Output('array', 'value'),
Input('initial-array', 'value'), prevent_initial_call=True)
def array_from_initial(initial_value):
return initial_value if initial_value is not None else dash.no_update
[Input(f'network-{network.lower()}', 'value') for network in vlbi_networks_names],
prevent_initial_call=True)
def array_from_initial(*selected_networks):
return [network for (network,selected) in zip(vlbi_networks_names, selected_networks) if selected]


@app.callback(Output('e-EVN', 'value'),
@@ -386,23 +388,8 @@ def line_cont_setup(is_line_exp):
Input('button-picknetwork', 'n_clicks'),
Input('button-picktimes', 'n_clicks'),
Input('button-mode-continuum', 'n_clicks'),
Input('button-mode-line', 'n_clicks')],
[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):
Input('button-mode-line', 'n_clicks')])
def intro_choices(clicks_pickband, clicks_picknetwork, clicks_picktimes, clicks_continuum, clicks_line):
if clicks_pickband is not None:
return choice_page('network'), dash.no_update
elif clicks_picknetwork is not None:
@@ -479,7 +466,7 @@ def choice_page(choice_card):
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)),
children=ge.initial_window_pick_network(app, 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,
@@ -549,8 +536,8 @@ def main_page(results_visible=False, summary_output=None, fig_elev_output=None,
dcc.Input(id='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'},
className='form-text'),
html.Small(id='error_source',
className='form-text text-muted'),
]),
html.Br(),
html.Div(className='form-group', children=[
@@ -558,7 +545,7 @@ 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="timeselection", inline=True, persistence=True),
value=True, id="timeselection", inline=True, persistence=True),
], inline=True),
html.Div(children=[
html.Div(id='timeselection-div-guess', className='row justify-content-center',
@@ -595,8 +582,7 @@ def main_page(results_visible=False, summary_output=None, fig_elev_output=None,
html.Div(className='form-group', children=[
dcc.Input(id='duration', value=None, type='number', className='form-control',
placeholder="Duration in hours", persistence=True, inputMode='numeric'),
html.Small(id='error_duration', style={'color': 'red'},
className='form-text text-muted')
html.Small(id='error_duration', className='form-text text-danger')
])
])
]),


BIN
assets/network-kvn.jpeg View File

Before After
Width: 602  |  Height: 456  |  Size: 254 KiB

+ 51
- 14
assets/style.css View File

@@ -128,6 +128,12 @@ input[type=time] {
border: 1px solid #CCCCCC !important
}


.card-button {
min-width: 23rem !important;
max-width: 23rem !important;
}

.card.card-antenna {
background-color: white !important;
min-width: 12rem;
@@ -182,6 +188,44 @@ input[type=time] {
bottom: 0.5rem;
}


.card.card-network {
padding: 0;
min-width: 12rem !important;
max-width: 15rem;
}

.card.card-network .card-img {
object-fit: fill;
width: 100%;
height: 50%;
overflow: hidden;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}

.card.card-network .card-title {
font-size: 1rem;
margin-bottom: 0.3rem;
}

.card.card-network .card-title2 {
font-size: 0.9rem;
}

.card.card-network .card-subtitle {
color: #AAAAAA;
font-size: 0.8rem;
margin-bottom: 0.5rem;
}

.card.card-network .card-body {
padding: 0.9rem;
}




.popover-link {
color: #a01d26;
}
@@ -522,6 +566,7 @@ input[type=time] {
/* outline: none; */
/* border: 1px solid #CCCCCC; */
margin: 8px;
padding: 0;
}

.card.card-antenna .card-img {
@@ -571,24 +616,16 @@ input[type=time] {

.card-summary {
background-color: white !important;
/* color: #a01d26; */
/* cursor: pointer; */
/* padding: 18px; */
width: 100% !important;
/* text-align: left; */
/* text-color: #a01d26; */
/* border: none; */
/* outline: none; */
min-width: 100%;
max-width: 100%;
/* border: 1px solid #CCCCCC; */
border-left: 5px solid #a01d26;
/* border-left: 5px solid #a01d26; */
margin: 40px;
min-width: 21rem;
max-width: 21rem;
border: 1px solid #CCCCCC;
border-left: 5px solid #a01d26;
border-radius: .25rem;
min-width: 21rem !important;
max-width: 21rem !important;
/* border: 1px solid #CCCCCC; */
/* border-left: 5px solid #a01d26; */
/* border-radius: .25rem; */
}

.card-summary .card-title {


BIN
assets/waves-Xcm.pxd/QuickLook/Icon.tiff View File


BIN
assets/waves-Xcm.pxd/QuickLook/Thumbnail.tiff View File


+ 0
- 33
assets/waves-Xcm.pxd/data/selectionForContentTransform/meta View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>backingScale</key>
<real>1</real>
<key>mode</key>
<integer>0</integer>
<key>shapeSelectionFilename</key>
<string>shapeSelection</string>
<key>size</key>
<data>
NC10UHpTVFAQAAAAQDGQJ4AAAABAO1t1AAAAAA==
</data>
<key>softness</key>
<real>0.0</real>
<key>timestamp</key>
<real>628075474.02018797</real>
<key>transform</key>
<array>
<real>0.8634530138806179</real>
<real>-0.19596258055776611</real>
<real>0.22132388845389925</real>
<real>0.97520035705471619</real>
<real>750.44436066246851</real>
<real>-60.927162696931958</real>
<real>0.0</real>
<real>0.0</real>
</array>
<key>version</key>
<integer>2</integer>
</dict>
</plist>

+ 0
- 12
assets/waves-Xcm.pxd/data/selectionForContentTransform/shapeSelection/meta View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>backingScale</key>
<real>1</real>
<key>pathFilename</key>
<string>path</string>
<key>version</key>
<integer>1</integer>
</dict>
</plist>

BIN
assets/waves-Xcm.pxd/data/selectionForContentTransform/shapeSelection/path View File


BIN
assets/waves-Xcm.pxd/metadata.info View File


+ 68
- 51
vlbiplanobs/graphical_elements.py View File

@@ -57,11 +57,17 @@ def create_sensitivity_card(title, message):
else:
ps = [html.P(className='card-text', children=message)]

# return [html.Div(className='card', style={'min-width': '15rem', 'max-width': '25rem'}, children=[
return [html.Div(className='card-summary m-3', children=[
html.Div(className='card-body', children=[
html.H5(className='card-title', children=title)] + ps)])
]
# return [html.Div(dbc.Card(
return [dbc.Card(
dbc.CardBody([
html.H5(className='card-title', children=title),
*ps
]), className='card-summary shadow-1-strong')
]
# return [html.Div(className='card-summary m-3', children=[
# html.Div(className='card-body', children=[
# html.H5(className='card-title', children=title)] + ps)])
# ]



@@ -99,6 +105,29 @@ def antenna_cards(app, stations):
return cards


def network_card(app, network_acr, network_name, body, network_img=None):
"""Generates a card showing the basic information from a network.
"""
card = dbc.Card([
dbc.CardImg(src=app.get_asset_url(network_img if network_img is not None else \
f"network-{network_acr.lower()}.png"),
top=True, className='card-img'),
dbc.CardBody([
html.H4(network_acr, className='card-title'),
html.H6(network_name, className='card-title2'),
*[dbc.Checklist(id='initial-e-EVN', className='checkbox', persistence=True,
options=[{'label': 'e-EVN (real time) mode', 'value': False}]) \
if network_acr == 'EVN' else html.Span()],
]),
dbc.CardFooter(
dbc.Checklist(id=f'network-{network_acr.lower()}', className='checkbox', persistence=True,
options=[{'label': ' Select network',
'value': True}], value=[]))
], className="card-network col-sm-3 m-4 shadow-1-strong")
return card




def summary_card_antennas(app, obs):
"""Generates the summary card with the information about which
@@ -287,7 +316,7 @@ def summary_card_rms(app, obs):
[u.MJy, u.kJy, u.Jy, u.mJy, u.uJy])
temp_msg = [html.Div(className='row', style={'height': '0.7rem'}),
html.Div(className='row justify-content-center',
children=html.Img(src=app.get_asset_url("waves.svg"), width='100%',
children=html.Img(src=app.get_asset_url("waves.png"), width='100%',
height='75rem', style={'display': 'inline'}))]
temp_msg += [html.P(f"The expected rms thermal noise for your target is {rms:.3n}/beam when no weighting is applied during imaging. Note that ~20% higher values may be expected for RFI-contaminated bands.")]
temp_msg += [html.P(f"The achieved sensitivity implies a rms of {rms_channel:.3n}/beam per spectral "
@@ -393,28 +422,28 @@ def initial_window_start(app):
directly to manually selecting everything or going through the "wizard" guided mode.
"""
return [
html.Div(children=[
html.Div(html.Button(id='button-initial-wizard', className='btn btn-gray',
html.Div(className='row card-deck justify-content-center text-center', children=[
html.Button(id='button-initial-wizard', className='card-button btn btn-gray m-4',
title='Helps you to configure your observation in a step-by-step process.',
children=dbc.Card(dbc.CardBody([
html.H5("Guided mode", className='card-title'),
html.Img(height='80rem', src=app.get_asset_url('icon-newbie.png'),
className='card-text m-3'),
html.Br(),
html.P("Guided setup of your observation.", className='card-text px-0')
html.P("Guided setup of your observation", className='card-text px-0')
]), className='text-center shadow-0')
), className='col-sm-6 text-center mx-0 px-0'),
html.Div(html.Button(id='button-initial-expert', className='btn btn-gray',
),
html.Button(id='button-initial-expert', className='card-button btn btn-gray m-4',
title='Go to the main window containing all options to configure.',
children=[dbc.Card(dbc.CardBody([
html.H5("Manual mode", className='card-title'),
html.Img(height='80rem', src=app.get_asset_url('icon-expert.png'),
className='card-text m-3'),
html.Br(),
html.P("Manual setup of your observation.", className='card-text px-0')
html.P("Manual setup of your observation", className='card-text px-0')
]), className='text-center shadow-0')]
), className='col-sm-6 text-center mx-0 px-0')
], className='row')
)
])
]


@@ -444,7 +473,7 @@ def initial_window_pick_band():
]


def initial_window_pick_network(vlbi_networks):
def initial_window_pick_network(app, 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,32 +484,20 @@ def initial_window_pick_network(vlbi_networks):
"you will be able to add or remove antennas as wished."])
]),
html.Br(),
html.Div(className='justify-content-center', children=[
dcc.Dropdown(id='initial-array', options=[{'label': vlbi_networks[n], 'value': n} \
for n in vlbi_networks], value=[], persistence=True, multi=True)
html.Div(className='row justify-content-center', children=[
network_card(app, a_network, vlbi_networks[a_network], "") \
for a_network in vlbi_networks
]),
html.Br(),
html.Div(className='form-group', children=[
html.H6(['Real-time correlation?',
*tooltip(idname='popover-eevn',
message="Only available for the EVN (+eMERLIN): real-time correlation mode."
"The data are transferred and correlated in real-time, but "
"not all telescopes are capable for this and the bandwidth "
"may be limited. Observations during the e-EVN epochs.")
]),
dbc.Checklist(id='initial-e-EVN', className='checkbox', persistence=True,
options=[{'label': ' e-EVN mode',
'value': 'e-EVN'}], value=[]),
]),
# TODO: add images of the different networks to explain it.
# html.Br(),
# html.Div(className='row', children=[
# html.Div(),
# ]),
html.Br(),
html.Div(className='row justify-content-center',
children=html.Button('Continue', id='button-picknetwork',
className='btn btn-primary btn-lg')),
# html.Div(hidden=True, children=[
# dcc.Dropdown(id='initial-array', options=[{'label': n, 'value': n} \
# for n in vlbi_networks if n != 'e-EVN'], value=[],
# persistence=True, multi=True)
# ]),
html.Div(style={'height': '20rem'})
]


@@ -497,7 +514,7 @@ def initial_window_pick_time():
html.Div(className='row justify-content-center', children=[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=True, id="initial-timeselection", inline=True, persistence=True),
], className='col-5', inline=True), #),
html.Div(className='col-7', children=[
html.Div(id='initial-timeselection-div-guess', className='row justify-content-center',
@@ -575,30 +592,30 @@ def initial_window_pick_mode(app):
"channels, etc). You will still be able to tune these parameters afterwards."])
], style={'text:align': 'justify !important'}),
html.Br(),
html.Div(children=[
html.Div(html.Button(id='button-mode-continuum', className='btn btn-gray',
html.Div(className='row card-deck justify-content-center text-center', children=[
html.Button(id='button-mode-continuum', className='card-button btn btn-gray m-4',
title='Helps you to configure your observation in a step-by-step process.',
children=dbc.Card(dbc.CardBody([
html.H5("Continuum mode", className='card-title'),
html.Img(height='80rem', src=app.get_asset_url('icon-newbie.png'),
html.Img(height='80rem', src=app.get_asset_url('waves.png'),
className='card-text m-3'),
html.Br(),
html.P("Provides the maximum sensitivity.", className='card-text px-0'),
html.P("Uses the maximum bandwidth available.", className='card-text px-0')
html.P("Provides the maximum sensitivity", className='card-text px-0'),
html.P("Uses the maximum bandwidth available", className='card-text px-0')
]), className='text-center shadow-0')
), className='col-6 text-center mx-0 px-0'),
html.Div(html.Button(id='button-mode-line', className='btn btn-gray',
),
html.Button(id='button-mode-line', className='card-button btn btn-gray m-4',
title='Go to the main window containing all options to configure.',
children=[dbc.Card(dbc.CardBody([
html.H5("Spectral line mode", className='card-title'),
html.Img(height='80rem', src=app.get_asset_url('icon-expert.png'),
html.Img(height='80rem', src=app.get_asset_url('waves-line.png'),
className='card-text m-3'),
html.Br(),
html.P("Provides a much higher frequency resolution.", className='card-text px-0'),
html.P("In general uses a reduced bandwidth.", className='card-text px-0')
html.P("Provides higher frequency resolution", className='card-text px-0'),
html.P("In general uses a reduced bandwidth", className='card-text px-0')
]), className='text-center shadow-0')]
), className='col-6 text-center mx-0 px-0')
], className='row'),
)
]),
html.Div(hidden=True, children=[dbc.Checklist(id='is_line',
options=[{'label': 'line obs', 'value': False}], value=[])])
]
@@ -610,13 +627,13 @@ def initial_window_final():
return [html.Div(children=[
# dcc.Tabs(id='tabs', value=''),
html.Div(className='row justify-content-center', children=[
html.H3('You are know ready'),
html.H3('You are now ready'),
html.P(["Press compute to produce the summary for your observation. "
"You would then see different tabs with the information. "
"You will also be able to change the setup and re-compute it."]),
html.Br(),
]),
html.Span(style={'height': '2rem'}),
html.Span(style={'height': '5rem'}),
html.Div(className='row justify-content-center',
children=html.Button('Compute', id='antenna-selection-button',
className='btn btn-primary btn-lg')),


Loading…
Cancel
Save