From 5e50b14164bb0880d824130b97683703d780cd8d Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Wed, 21 Jun 2023 10:02:16 +0200 Subject: [PATCH 1/5] feat: sort sensor legend by order of appearance Signed-off-by: F.N. Claessen --- .../data/models/charts/belief_charts.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/flexmeasures/data/models/charts/belief_charts.py b/flexmeasures/data/models/charts/belief_charts.py index 09782470e..f5ee9d253 100644 --- a/flexmeasures/data/models/charts/belief_charts.py +++ b/flexmeasures/data/models/charts/belief_charts.py @@ -112,6 +112,15 @@ def chart_for_multiple_sensors( ] } + # Set up field definition for sensor descriptions + sensor_field_definition = FIELD_DEFINITIONS["sensor_description"] + sensor_field_definition["scale"] = dict( + domain=[ + sensor.to_dict()["description"] + for sensor in flatten_unique(sensors_to_show) + ] + ) + sensors_specs = [] for s in sensors_to_show: # List the sensors that go into one row @@ -164,7 +173,10 @@ def chart_for_multiple_sensors( # Draw a line for each sensor (and each source) layers = [ create_line_layer( - row_sensors, event_start_field_definition, event_value_field_definition + row_sensors, + event_start_field_definition, + event_value_field_definition, + sensor_field_definition, ) ] @@ -186,6 +198,7 @@ def chart_for_multiple_sensors( row_sensors, event_start_field_definition, event_value_field_definition, + sensor_field_definition, shared_tooltip, ) ) @@ -269,6 +282,7 @@ def create_line_layer( sensors: list["Sensor"], # noqa F821 event_start_field_definition: dict, event_value_field_definition: dict, + sensor_field_definition: dict, ): event_resolutions = list(set([sensor.event_resolution for sensor in sensors])) assert ( @@ -286,7 +300,7 @@ def create_line_layer( "encoding": { "x": event_start_field_definition, "y": event_value_field_definition, - "color": FIELD_DEFINITIONS["sensor_description"], + "color": sensor_field_definition, "strokeDash": { "scale": { # Distinguish forecasters and schedulers by line stroke @@ -309,6 +323,7 @@ def create_circle_layer( sensors: list["Sensor"], # noqa F821 event_start_field_definition: dict, event_value_field_definition: dict, + sensor_field_definition: dict, shared_tooltip: list, ): params = [ @@ -348,7 +363,7 @@ def create_circle_layer( "encoding": { "x": event_start_field_definition, "y": event_value_field_definition, - "color": FIELD_DEFINITIONS["sensor_description"], + "color": sensor_field_definition, "size": { "condition": {"value": "200", "test": {"or": or_conditions}}, "value": "0", From 40b9832c81a77435a3b80f615774482aa4c2da71 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Wed, 21 Jun 2023 10:03:30 +0200 Subject: [PATCH 2/5] fix: preserve order when flattening list of lists Signed-off-by: F.N. Claessen --- flexmeasures/utils/coding_utils.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/flexmeasures/utils/coding_utils.py b/flexmeasures/utils/coding_utils.py index 40839ba60..3994a7b72 100644 --- a/flexmeasures/utils/coding_utils.py +++ b/flexmeasures/utils/coding_utils.py @@ -127,9 +127,11 @@ def sort_dict(unsorted_dict: dict) -> dict: def flatten_unique(nested_list_of_objects: list) -> list: """Returns unique objects in a possibly nested (one level) list of objects. + Preserves the original order in which unique objects first occurred. + For example: - >>> flatten_unique([1, [2, 3, 4], 3, 5]) - <<< [1, 2, 3, 4, 5] + >>> flatten_unique([1, [2, 20, 6], 10, [6, 2]]) + <<< [1, 2, 20, 6, 10] """ all_objects = [] for s in nested_list_of_objects: @@ -137,7 +139,7 @@ def flatten_unique(nested_list_of_objects: list) -> list: all_objects.extend(s) else: all_objects.append(s) - return list(set(all_objects)) + return list(dict.fromkeys(all_objects).keys()) def timeit(func): From 140f66707b23cd8e9c0d16c7765559f684e6e029 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Fri, 23 Jun 2023 12:18:16 +0200 Subject: [PATCH 3/5] refactor: 1 less function call Signed-off-by: F.N. Claessen --- flexmeasures/data/models/charts/belief_charts.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/flexmeasures/data/models/charts/belief_charts.py b/flexmeasures/data/models/charts/belief_charts.py index f5ee9d253..879e59509 100644 --- a/flexmeasures/data/models/charts/belief_charts.py +++ b/flexmeasures/data/models/charts/belief_charts.py @@ -90,9 +90,10 @@ def chart_for_multiple_sensors( **override_chart_specs: dict, ): # Determine the shared data resolution + all_shown_sensors = flatten_unique(sensors_to_show) condition = list( sensor.event_resolution - for sensor in flatten_unique(sensors_to_show) + for sensor in all_shown_sensors if sensor.event_resolution > timedelta(0) ) minimum_non_zero_resolution = min(condition) if any(condition) else timedelta(0) @@ -115,10 +116,7 @@ def chart_for_multiple_sensors( # Set up field definition for sensor descriptions sensor_field_definition = FIELD_DEFINITIONS["sensor_description"] sensor_field_definition["scale"] = dict( - domain=[ - sensor.to_dict()["description"] - for sensor in flatten_unique(sensors_to_show) - ] + domain=[sensor.to_dict()["description"] for sensor in all_shown_sensors] ) sensors_specs = [] From e9788d47259252ed225803238a780d8bcc59dd93 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Fri, 23 Jun 2023 12:30:09 +0200 Subject: [PATCH 4/5] fix: prevent mutating the original FIELD_DEFINITIONS dict Signed-off-by: F.N. Claessen --- flexmeasures/data/models/charts/belief_charts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flexmeasures/data/models/charts/belief_charts.py b/flexmeasures/data/models/charts/belief_charts.py index 879e59509..bef9a6a4d 100644 --- a/flexmeasures/data/models/charts/belief_charts.py +++ b/flexmeasures/data/models/charts/belief_charts.py @@ -114,7 +114,7 @@ def chart_for_multiple_sensors( } # Set up field definition for sensor descriptions - sensor_field_definition = FIELD_DEFINITIONS["sensor_description"] + sensor_field_definition = FIELD_DEFINITIONS["sensor_description"].copy() sensor_field_definition["scale"] = dict( domain=[sensor.to_dict()["description"] for sensor in all_shown_sensors] ) From 4fb38087d17e6a7b3c67dfeaeea7bfadebf979cd Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Fri, 23 Jun 2023 12:31:27 +0200 Subject: [PATCH 5/5] docs: changelog entry Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index c2c485c92..d5ee7420b 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -10,6 +10,7 @@ New features ------------- * Allow deleting multiple sensors with a single call to ``flexmeasures delete sensor`` by passing the ``--id`` option multiple times [see `PR #734 `_] +* Make it a lot easier to read off the color legend on the asset page, especially when showing many sensors, as they will now be ordered from top to bottom in the same order as they appear in the chart (as defined in the ``sensors_to_show`` attribute), rather than alphabetically [see `PR #742 `_] Bugfixes -----------