Skip to content

Commit 873fe5f

Browse files
committed
Skip real-time plot if higher-frequency data is missing
- Skip generating the real-time view plot when no high-frequency reporting data is available. - Log the issue using `NoDataAvailableError` and clear the figure to avoid rendering an empty plot. - Ensure `rolling_view_real_time` and output dict are safely set to empty DataFrames in such cases. Signed-off-by: cyiallou - Costas <[email protected]>
1 parent 5f0e45b commit 873fe5f

File tree

1 file changed

+67
-48
lines changed

1 file changed

+67
-48
lines changed

src/frequenz/lib/notebooks/solar/maintenance/solar_maintenance_app.py

Lines changed: 67 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,12 @@ async def run_workflow(user_config_changes: dict[str, Any]) -> SolarAnalysisData
409409
rolling_view_average = RollingPreparer(rolling_view_average_config).prepare(
410410
data[[long_term_view_col_to_plot]]
411411
)
412-
rolling_view_real_time = RollingPreparer(rolling_view_real_time_config).prepare(
413-
data_higher_fs[real_time_view_col_to_plot] / normalisation_factor
412+
rolling_view_real_time = (
413+
pd.DataFrame()
414+
if data_higher_fs.empty
415+
else RollingPreparer(rolling_view_real_time_config).prepare(
416+
data_higher_fs[real_time_view_col_to_plot] / normalisation_factor
417+
)
414418
)
415419
daily_production_view = DailyPreparer(daily_plot_config).prepare(data)
416420
statistical_view = ProfilePreparer(statistical_plot_config).prepare(data)
@@ -493,54 +497,67 @@ async def run_workflow(user_config_changes: dict[str, Any]) -> SolarAnalysisData
493497
fig=figures_and_axes["fig_real_time"]["figure"],
494498
ax=figures_and_axes["fig_real_time"]["axes"][0],
495499
)
496-
if plot_settings["show_annotation"]:
497-
if len(real_time_view_col_to_plot) == 1:
498-
for col in real_time_view_col_to_plot:
499-
recent_y = rolling_view_real_time[str(col)].iloc[-2]
500-
_annotate_last_point(
501-
figures_and_axes["fig_real_time"]["axes"][0], recent_y
502-
)
503-
patch = Patch(
504-
color=plot_settings["patch_colour"], label=patch_label
505-
)
506-
figures_and_axes["fig_real_time"]["axes"][0].set_ylabel(real_time_view_ylabel)
507-
508-
if plot_settings["legend_update_on"] == "figure":
509-
_legend_kwargs_copy = plot_settings["legend_kwargs"].copy()
510-
# divide legend labels into groups of 2 if needed
511-
_legend_kwargs_copy["ncol"] = max(
512-
_legend_kwargs_copy["ncol"],
513-
(
514-
len(
515-
figures_and_axes["fig_real_time"]["axes"][
516-
0
517-
].get_legend_handles_labels()[1]
518-
)
519-
+ 1
520-
)
521-
// 2,
522-
)
500+
if data_higher_fs.empty:
501+
reason = NoDataAvailableError("No data available for real-time view.")
502+
print(f"{reason} Skipping this plot.")
503+
print(f"{type(reason).__name__}: {reason}. Skipping this plot.")
504+
# the plotter automatically hides the axis when data is empty
505+
# but we need to deal with the figure itself
506+
# we can safely clear the figure like this because it only plots rolling_view_real_time
507+
figures_and_axes["fig_real_time"]["figure"].clf()
523508
else:
524-
_legend_kwargs_copy = plot_settings["legend_kwargs"]
525-
plot_manager.update_legend(
526-
fig_id="fig_real_time",
527-
axs=[figures_and_axes["fig_real_time"]["axes"][0]],
528-
on=plot_settings["legend_update_on"],
529-
modifications={
530-
"additional_items": (
531-
[(patch, patch_label)] if plot_settings["show_annotation"] else None
532-
),
533-
"replace_label": {
534-
str(col): (
535-
tm.translate("component_{value}", value=col)
536-
if config.split_real_time_view_per_inverter
537-
else production_legend_label
509+
if plot_settings["show_annotation"]:
510+
if len(real_time_view_col_to_plot) == 1:
511+
for col in real_time_view_col_to_plot:
512+
recent_y = rolling_view_real_time[str(col)].iloc[-2]
513+
_annotate_last_point(
514+
figures_and_axes["fig_real_time"]["axes"][0], recent_y
515+
)
516+
patch = Patch(
517+
color=plot_settings["patch_colour"], label=patch_label
518+
)
519+
figures_and_axes["fig_real_time"]["axes"][0].set_ylabel(
520+
real_time_view_ylabel
521+
)
522+
523+
if plot_settings["legend_update_on"] == "figure":
524+
_legend_kwargs_copy = plot_settings["legend_kwargs"].copy()
525+
# divide legend labels into groups of 2 if needed
526+
_legend_kwargs_copy["ncol"] = max(
527+
_legend_kwargs_copy["ncol"],
528+
(
529+
len(
530+
figures_and_axes["fig_real_time"]["axes"][
531+
0
532+
].get_legend_handles_labels()[1]
533+
)
534+
+ 1
538535
)
539-
for col in real_time_view_col_to_plot
536+
// 2,
537+
)
538+
else:
539+
_legend_kwargs_copy = plot_settings["legend_kwargs"]
540+
plot_manager.update_legend(
541+
fig_id="fig_real_time",
542+
axs=[figures_and_axes["fig_real_time"]["axes"][0]],
543+
on=plot_settings["legend_update_on"],
544+
modifications={
545+
"additional_items": (
546+
[(patch, patch_label)]
547+
if plot_settings["show_annotation"]
548+
else None
549+
),
550+
"replace_label": {
551+
str(col): (
552+
tm.translate("component_{value}", value=col)
553+
if config.split_real_time_view_per_inverter
554+
else production_legend_label
555+
)
556+
for col in real_time_view_col_to_plot
557+
},
540558
},
541-
},
542-
**_legend_kwargs_copy,
543-
)
559+
**_legend_kwargs_copy,
560+
)
544561
# ------------------- #
545562

546563
# --- plot the statistical production profile --- #
@@ -810,7 +827,9 @@ async def run_workflow(user_config_changes: dict[str, Any]) -> SolarAnalysisData
810827
for fig in figures_and_axes.keys():
811828
plot_manager.adjust_axes_spacing(fig_id=fig, pixels=100.0)
812829

813-
output.real_time_view[mid] = rolling_view_real_time
830+
output.real_time_view[mid] = (
831+
pd.DataFrame() if data_higher_fs.empty else rolling_view_real_time
832+
)
814833
output.rolling_view_short_term[mid] = rolling_view_short_term
815834
output.rolling_view_long_term[mid] = rolling_view_long_term
816835
output.rolling_view_average[mid] = rolling_view_average

0 commit comments

Comments
 (0)