From 89fd9fe18ce2aa0b697c58efe915fe51f01586dc Mon Sep 17 00:00:00 2001 From: "create-issue-branch[bot]" <53036503+create-issue-branch[bot]@users.noreply.github.com> Date: Tue, 29 Jun 2021 22:23:43 +0200 Subject: [PATCH] Offer asset grouping by location (#148) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * group assets by location, keep special 'Charge Point' case. Fix a few spelling problems. Co-authored-by: Nicolas Höning --- documentation/changelog.rst | 2 ++ flexmeasures/data/services/resources.py | 48 +++++++++++++++---------- flexmeasures/ui/views/analytics.py | 16 ++++----- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 725b5ef5c..28555a600 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -7,6 +7,8 @@ v0.6.0 | July XX, 2021 New features ----------- +* Analytics view offers grouping of all assets by location [see `PR #148 `_] + Bugfixes ----------- diff --git a/flexmeasures/data/services/resources.py b/flexmeasures/data/services/resources.py index f66f7fabf..44b0912a0 100644 --- a/flexmeasures/data/services/resources.py +++ b/flexmeasures/data/services/resources.py @@ -116,8 +116,8 @@ def get_asset_group_queries( Valid names are: - "renewables", to query all solar and wind assets - "EVSE", to query all Electric Vehicle Supply Equipment - - "each Charge Point", to query each individual Charge Point - (i.e. all EVSE at 1 location) + - "location", to query each individual location with assets + (i.e. all EVSE at 1 location or each household) :param all_users: if True, do not filter out assets that do not belong to the user (use with care) """ @@ -141,19 +141,18 @@ def get_asset_group_queries( asset_type_name=asset_type.name ) + # 3. Finally, we group assets by location + if "location" in custom_additional_groups: + asset_queries.update(get_location_queries()) + if not all_users: asset_queries = mask_inaccessible_assets(asset_queries) - # 3. We group EVSE assets by location (if they share a location, they belong to the same Charge Point) - if "each Charge Point" in custom_additional_groups: - asset_queries.update(get_charge_point_queries()) - return asset_queries -def get_charge_point_queries() -> Dict[str, Query]: +def get_location_queries() -> Dict[str, Query]: """ - A Charge Point is defined similarly to asset groups (see get_asset_group_queries). We group EVSE assets by location (if they share a location, they belong to the same Charge Point) Like get_asset_group_queries, the values in the returned dict still need an executive call, like all(), count() or first(). @@ -163,18 +162,29 @@ def get_charge_point_queries() -> Dict[str, Query]: evse_display_name = "Seoul Hilton - charger 1" Then: charge_point_display_name = "Seoul Hilton (Charge Point)" + + A Charge Point is a special case. If all assets on a location are of type EVSE, + we can call the location a "Charge Point". """ asset_queries = {} - all_evse_assets = Asset.query.filter( - Asset.asset_type_name.in_(["one-way_evse", "two-way_evse"]) - ).all() - cp_groups = group_assets_by_location(all_evse_assets) - for cp_group in cp_groups: - charge_point_name = cp_group[0].display_name.split(" -")[0] + " (Charge Point)" - asset_queries[charge_point_name] = Asset.query.filter( - Asset.name.in_([evse.name for evse in cp_group]) + all_assets = Asset.query.all() + loc_groups = group_assets_by_location(all_assets) + for loc_group in loc_groups: + if len(loc_group) == 1: + continue + location_type = "(Location)" + if all( + [ + asset.asset_type_name in ["one-way_evse", "two-way_evse"] + for asset in loc_group + ] + ): + location_type = "(Charge Point)" + location_name = f"{loc_group[0].display_name.split(' -')[0]} {location_type}" + asset_queries[location_name] = Asset.query.filter( + Asset.name.in_([asset.name for asset in loc_group]) ) - return mask_inaccessible_assets(asset_queries) + return asset_queries def mask_inaccessible_assets( @@ -316,7 +326,7 @@ def __init__(self, name: str): # Query assets for all users to set some public information about the resource asset_queries = get_asset_group_queries( - custom_additional_groups=["renewables", "EVSE", "each Charge Point"], + custom_additional_groups=["renewables", "EVSE", "location"], all_users=True, ) asset_query = ( @@ -382,7 +392,7 @@ def hover_label(self) -> Optional[str]: @property def parameterized_name(self) -> str: - """Get a parameterized name for use in javascript.""" + """Get a parametrized name for use in javascript.""" return parameterize(self.name) def load_sensor_data( diff --git a/flexmeasures/ui/views/analytics.py b/flexmeasures/ui/views/analytics.py index bc35dfb93..5e81f48ef 100644 --- a/flexmeasures/ui/views/analytics.py +++ b/flexmeasures/ui/views/analytics.py @@ -56,7 +56,7 @@ def analytics_view(): markets = get_markets() assets = get_assets(order_by_asset_attribute="display_name", order_direction="asc") asset_groups = get_asset_group_queries( - custom_additional_groups=["renewables", "EVSE", "each Charge Point"] + custom_additional_groups=["renewables", "EVSE", "location"] ) asset_group_names: List[str] = [ group for group in asset_groups if asset_groups[group].count() > 0 @@ -138,7 +138,7 @@ def analytics_view(): tools=tools, ) # the bottom plots need a separate x axis if they get their own legend (Bokeh complains otherwise) - # this means in that in that corner case zooming will not work across all foour plots + # this means in that in that corner case zooming will not work across all four plots prices_fig = make_prices_figure( data["prices"], data["prices_forecast"], @@ -230,7 +230,7 @@ def analytics_data_view(content, content_type): # Maybe move some of this stuff into get_data_and_metrics assets = get_assets(order_by_asset_attribute="display_name", order_direction="asc") asset_groups = get_asset_group_queries( - custom_additional_groups=["renewables", "EVSE", "each Charge Point"] + custom_additional_groups=["renewables", "EVSE", "location"] ) asset_group_names: List[str] = [ group for group in asset_groups if asset_groups[group].count() > 0 @@ -263,7 +263,7 @@ def analytics_data_view(content, content_type): selected_resource.assets, ) - hor = session["forecast_horizon"] + horizon = session["forecast_horizon"] rev_cost_header = ( "costs/revenues" if show_consumption_as_positive else "revenues/costs" ) @@ -276,19 +276,19 @@ def analytics_data_view(content, content_type): "power_data_label", "power", "power_forecast_label", - f"power_forecast_{hor}", + f"power_forecast_{horizon}", f"{weather_type}_label", f"{weather_type}", f"{weather_type}_forecast_label", - f"{weather_type}_forecast_{hor}", + f"{weather_type}_forecast_{horizon}", "price_label", f"price_on_{selected_market.name}", "price_forecast_label", - f"price_forecast_{hor}", + f"price_forecast_{horizon}", f"{rev_cost_header}_label", rev_cost_header, f"{rev_cost_header}_forecast_label", - f"{rev_cost_header}_forecast_{hor}", + f"{rev_cost_header}_forecast_{horizon}", ] source_units = [ "",