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

Tickets/preops 3763 #35

Merged
merged 5 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion schedview/app/scheduler_dashboard/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .scheduler_dashboard import sched_app
from .scheduler_dashboard import scheduler_app

Check warning on line 1 in schedview/app/scheduler_dashboard/__init__.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/__init__.py#L1

Added line #L1 was not covered by tests
88 changes: 43 additions & 45 deletions schedview/app/scheduler_dashboard/scheduler_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from bokeh.models import ColorBar, LinearColorMapper
from bokeh.models.widgets.tables import BooleanFormatter, HTMLTemplateFormatter
from pandas import Timestamp
from panel.io.loading import start_loading_spinner, stop_loading_spinner

Check warning on line 41 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L41

Added line #L41 was not covered by tests
from pytz import timezone

# For the conditions.mjd bugfix
Expand All @@ -51,8 +52,9 @@

DEFAULT_CURRENT_TIME = Time.now()
DEFAULT_TIMEZONE = "America/Santiago"
COLOR_PALETTES = [color for color in bokeh.palettes.__palettes__ if "256" in color]
LOGO = "/assets/lsst_white_logo.png"
COLOR_PALETTES = [color for color in bokeh.palettes.__palettes__ if "256" in color]


pn.extension(
"tabulator",
Expand Down Expand Up @@ -89,7 +91,8 @@
if dataframe_row[url_column] == "":
return dataframe_row[name_column]
else:
return f'<a href="{dataframe_row[url_column]}" target="_blank"> {dataframe_row[name_column]}</a>'
return f'<a href="{dataframe_row[url_column]}" target="_blank"> \

Check warning on line 94 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L94

Added line #L94 was not covered by tests
{dataframe_row[name_column]}</a>'


class Scheduler(param.Parameterized):
Expand Down Expand Up @@ -131,6 +134,7 @@
color_palette = param.Selector(default="Viridis256", objects=COLOR_PALETTES, doc="")
summary_widget = param.Parameter(default=None, doc="")
reward_widget = param.Parameter(default=None, doc="")
show_loading_indicator = param.Boolean(default=False)

Check warning on line 137 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L137

Added line #L137 was not covered by tests

# Param parameters (used in depends decoraters and trigger calls).
_publish_summary_widget = param.Parameter(None)
Expand Down Expand Up @@ -165,25 +169,24 @@
_display_reward = False
_display_dashboard_data = False
_do_not_trigger_update = True
_show_loading_indicator = False
_model_observatory = ModelObservatory(init_load_length=1)

# ------------------------------------------------- User actions
# ------------------------------------------------------------ User actions

@param.depends("scheduler_fname", watch=True)
def _update_scheduler_fname(self):
"""Update the dashboard when a user enters a new filepath/URL."""
self._show_loading_indicator = True
self.show_loading_indicator = True

Check warning on line 179 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L179

Added line #L179 was not covered by tests
self.clear_dashboard()

if not self.read_scheduler():
self.clear_dashboard()
self._show_loading_indicator = False
self.show_loading_indicator = False

Check warning on line 184 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L184

Added line #L184 was not covered by tests
return

if not self.make_scheduler_summary_df():
self.clear_dashboard()
self._show_loading_indicator = False
self.show_loading_indicator = False

Check warning on line 189 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L189

Added line #L189 was not covered by tests
return

self.create_summary_widget()
Expand All @@ -209,12 +212,12 @@
self._display_reward = False
self.param.trigger("_update_headings")

self._show_loading_indicator = False
self.show_loading_indicator = False

Check warning on line 215 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L215

Added line #L215 was not covered by tests

@param.depends("date", watch=True)
def _update_date(self):
"""Update the dashboard when a user chooses a new date/time."""
self._show_loading_indicator = True
self.show_loading_indicator = True

Check warning on line 220 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L220

Added line #L220 was not covered by tests
self.clear_dashboard()

self._date_time = Time(
Expand All @@ -226,7 +229,7 @@

if not self.make_scheduler_summary_df():
self.clear_dashboard()
self._show_loading_indicator = False
self.show_loading_indicator = False

Check warning on line 232 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L232

Added line #L232 was not covered by tests
return

if self.summary_widget is None:
Expand Down Expand Up @@ -255,14 +258,14 @@
self._display_reward = False
self.param.trigger("_update_headings")

self._show_loading_indicator = False
self.show_loading_indicator = False

Check warning on line 261 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L261

Added line #L261 was not covered by tests

@param.depends("USER_tier", watch=True)
def _update_tier(self):
"""Update the dashboard when a user chooses a new tier."""
if not self._display_dashboard_data:
return

print(self.USER_tier)

Check warning on line 268 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L268

Added line #L268 was not covered by tests
self._tier = self.USER_tier
self._survey = 0
self._survey_name = self._scheduler_summary_df[
Expand Down Expand Up @@ -403,7 +406,7 @@
self.update_sky_map_with_survey_map()
self.param.trigger("_publish_map")

# ------------------------------------------------------ Internal workings
# ------------------------------------------------------- Internal workings

def clear_dashboard(self):
"""Clear the dashboard for a new pickle or a new date."""
Expand Down Expand Up @@ -465,7 +468,8 @@
return False

def make_scheduler_summary_df(self):
"""Update conditions, make the reward and scheduler summary dataframes.
"""Update conditions, and make the reward
and scheduler summary dataframes.

Returns
-------
Expand Down Expand Up @@ -584,7 +588,8 @@

@param.depends("_publish_summary_widget")
def publish_summary_widget(self):
"""Publish the summary Tabulator widget to be shown on the dashboard.
"""Publish the summary Tabulator widget
to be displayed on the dashboard.

Returns
-------
Expand Down Expand Up @@ -636,8 +641,8 @@
self._conditions,
self._reward_df.loc[[(int(self._tier[-1]), self._survey)], :],
)
# Duplicate column and apply URL formatting
# to one of the columns.
# Duplicate column and apply
# URL formatting to one of the columns.
survey_reward_df["basis_function_href"] = survey_reward_df.loc[:, "basis_function"]
survey_reward_df["basis_function_href"] = survey_reward_df.apply(
url_formatter,
Expand Down Expand Up @@ -792,15 +797,7 @@
hpix_data_source = self._sky_map_base.plot.select(name="hpix_ds")[0]

# CASE 1: Selection is a reward map.
if self.survey_map not in [
"u_sky",
"g_sky",
"r_sky",
"i_sky",
"z_sky",
"y_sky",
"reward",
]:
if self.survey_map not in ["u_sky", "g_sky", "r_sky", "i_sky", "z_sky", "y_sky", "reward"]:
reward_underscored = self._map_name.replace(" ", "_")
reward_survey_key = list(key for key in self._survey_maps if self._map_name in key)[0]
reward_bokeh_key = list(key for key in hpix_data_source.data if reward_underscored in key)[0]
Expand Down Expand Up @@ -912,8 +909,8 @@

# CASE 2: Reward is scalar and finite.
elif max_basis_reward != -np.inf:
# Create array populated with scalar values where
# the sky brightness map is not NaN.
# Create array populated with scalar values
# where sky brightness map is not NaN.
scalar_array = hpix_data_source.data["u_sky"].copy()
scalar_array[~np.isnan(hpix_data_source.data["u_sky"])] = max_basis_reward
hpix_data_source.data[reward_underscored] = scalar_array
Expand Down Expand Up @@ -995,12 +992,7 @@
self.debug_pane.object = self._debug_string
return self.debug_pane

@param.depends("_show_loading_indicator", watch=True)
def update_loading_indicator(self):
"""Update the app to show or stop showing the loading indicator."""
sched_app.loading = self._show_loading_indicator

# ------------------------------------------------------- Dashboard titles
# ------------------------------------------------------ Dashboard titles

def generate_dashboard_subtitle(self):
"""Select the dashboard subtitle string based on whether whether a
Expand Down Expand Up @@ -1072,7 +1064,8 @@

@param.depends("_update_headings")
def dashboard_subtitle(self):
"""Load subtitle data and create/update a pane to display subtitle.
"""Load subtitle data and create/update
a String pane to display subtitle.

Returns
-------
Expand All @@ -1093,7 +1086,8 @@

@param.depends("_update_headings")
def summary_table_heading(self):
"""Load heading data and create/update a pane to display heading.
"""Load heading data and create/update
a String pane to display heading.

Returns
-------
Expand Down Expand Up @@ -1153,7 +1147,7 @@
return self.map_title_pane


# -------------------------------------------------------------- Key functions
# --------------------------------------------------------------- Key functions


def generate_array_for_key(number_of_columns=4):
Expand Down Expand Up @@ -1322,14 +1316,7 @@
return key


# ----------------------------------------------------------- Create dashboard


# Initialize the dashboard layout.
sched_app = pn.GridSpec(
sizing_mode="stretch_both",
max_height=1000,
).servable()
# ------------------------------------------------------------ Create dashboard


def scheduler_app(date=None, scheduler_pickle=None):
Expand All @@ -1348,6 +1335,12 @@
sched_app : 'panel.layout.grid.GridSpec'
The dashboard.
"""
# Initialize the dashboard layout.
sched_app = pn.GridSpec(

Check warning on line 1339 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L1339

Added line #L1339 was not covered by tests
sizing_mode="stretch_both",
max_height=1000,
).servable()

scheduler = Scheduler()

if date is not None:
Expand All @@ -1356,6 +1349,11 @@
if scheduler_pickle is not None:
scheduler.scheduler_fname = scheduler_pickle

# show dashboard as busy when scheduler.show_loading_spinner is True
@pn.depends(loading=scheduler.param.show_loading_indicator, watch=True)

Check warning on line 1353 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L1353

Added line #L1353 was not covered by tests
def update_loading(loading):
start_loading_spinner(sched_app) if loading else stop_loading_spinner(sched_app)

Check warning on line 1355 in schedview/app/scheduler_dashboard/scheduler_dashboard.py

View check run for this annotation

Codecov / codecov/patch

schedview/app/scheduler_dashboard/scheduler_dashboard.py#L1355

Added line #L1355 was not covered by tests

# Dashboard title.
sched_app[0:8, :] = pn.Row(
pn.Column(
Expand Down
23 changes: 14 additions & 9 deletions tests/test_scheduler_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
- Unit tests are run in alphabetical order.

"""

TEST_PICKLE = str(importlib.resources.files(schedview).joinpath("data", "sample_scheduler.pickle.xz"))
MJD_START = survey_start_mjd()
TEST_DATE = Time(MJD_START + 0.2, format="mjd").datetime
Expand All @@ -66,17 +65,23 @@ class TestSchedulerDashboard(unittest.TestCase):
scheduler.scheduler_fname = TEST_PICKLE
scheduler._date_time = Time(Timestamp(TEST_DATE, tzinfo=ZoneInfo(DEFAULT_TIMEZONE))).mjd

@unittest.skip("Skipping so it does not block implementation of CI")
def setUp(self) -> None:
bokeh.io.reset_output()

def test_scheduler_app(self):
app = scheduler_app(date=TEST_DATE, scheduler_pickle=TEST_PICKLE)
app_bokeh_model = app.get_root()
with TemporaryDirectory() as dir:
out_path = Path(dir)
saved_html_fname = out_path.joinpath("test_page.html")
bokeh.plotting.output_file(filename=saved_html_fname, title="Test Page")
bokeh.plotting.save(app_bokeh_model)
sched_app = scheduler_app(date=TEST_DATE, scheduler_pickle=TEST_PICKLE)
sched_app_bokeh_model = sched_app.get_root()
with TemporaryDirectory() as scheduler_dir:
sched_out_path = Path(scheduler_dir)
sched_saved_html_fname = sched_out_path.joinpath("sched_test_page.html")
bokeh.plotting.output_file(filename=sched_saved_html_fname, title="Scheduler Test Page")
bokeh.plotting.save(sched_app_bokeh_model)
bokeh.io.reset_output()

def test_read_scheduler(self):
self.scheduler = Scheduler()
self.scheduler.scheduler_fname = TEST_PICKLE
self.scheduler._date_time = Time(Timestamp(TEST_DATE, tzinfo=ZoneInfo(DEFAULT_TIMEZONE))).mjd
self.scheduler.read_scheduler()
self.assertIsInstance(self.scheduler._scheduler, CoreScheduler)
self.assertIsInstance(self.scheduler._conditions, Conditions)
Expand Down
Loading