Creating utility functions to produce slides

This commit is contained in:
Khalim Conn-Kowlessar 2024-02-21 11:46:24 +00:00
parent 9f205e3dce
commit 80a542f02e
6 changed files with 118 additions and 18 deletions

View file

@ -343,7 +343,7 @@ class Property:
else:
output["glazed_type_ending"] = "double glazing installed during or after 2002"
if recommendation["type"] == "heating":
if recommendation["type"] in ["heating", "hot_water_tank_insulation"]:
# We update the data, as defined in the recommendaton
simulation_config = recommendation["simulation_config"]
@ -363,9 +363,9 @@ class Property:
"internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation",
"loft_insulation", "room_roof_insulation", "flat_roof_insulation",
"solid_floor_insulation", "suspended_floor_insulation", "exposed_floor_insulation",
"windows_glazing", "solar_pv", "heating",
"windows_glazing", "solar_pv", "heating", "hot_water_tank_insulation"
]:
raise NotImplementedError("Implement me")
raise NotImplementedError("Implement me, given type %s" % recommendation["type"])
output['id'] = "+".join([str(property_id), str(primary_recommendation_id)])

View file

@ -78,6 +78,8 @@ async def trigger_plan(body: PlanTriggerRequest):
# TODO: We should store the trigger file path in the database with the plan so we can track the file that
# triggered the plan
# TODO: Create the ability to congigure/switch off certain measures
try:
session.begin()
logger.info("Getting the inputs")

View file

@ -0,0 +1,65 @@
import matplotlib.pyplot as plt
from sqlalchemy.orm import Session
from backend.app.db.utils import row2dict
from backend.app.db.models.portfolio import PropertyModel
EPC_COLOURS = {
"A": "#008054",
"B": "#1ab559",
"C": "#8ccf45",
"D": "#ffd600",
"E": "#fcab66",
"F": "#f08024",
"G": "#e8143b"
}
def get_properties_by_portfolio_id(session: Session, portfolio_id: int):
"""
This function retrieves all properties associated with a given portfolio_id.
:param session: The SQLAlchemy session used to execute the query.
:param portfolio_id: The ID of the portfolio for which to retrieve properties.
:return: A list of dictionaries, where each dictionary represents a property.
Returns an empty list if no properties are found.
"""
properties = session.query(PropertyModel).filter(PropertyModel.portfolio_id == portfolio_id).all()
# Convert the SQLAlchemy objects to dictionaries
properties_dict = [row2dict(p) for p in properties] if properties else []
return properties_dict
def plot_epc_distribution(df, title='Your units', figsize=(10, 6)):
"""
Plots a horizontal bar chart of EPC rating distribution with percentages annotated on the bars.
:param df: DataFrame with columns ['current_epc_rating', 'count', 'percentage']
:param title: Title of the plot (default is 'EPC Rating Distribution by Percentage')
:param figsize: Figure size as a tuple (default is (10, 6))
"""
# Sort the DataFrame for a consistent plotting order
df_sorted = df.sort_values('percentage', ascending=True)
colors = df_sorted['current_epc_rating'].map(EPC_COLOURS) # Map the EPC ratings to colors
# Create the horizontal bar chart
plt.figure(figsize=figsize)
bars = plt.barh(df_sorted['current_epc_rating'], df_sorted['percentage'], color=colors)
# Annotate the bars with percentage values
for bar in bars:
width = bar.get_width()
label_x_pos = width + 1 # Adjust the offset for the label if necessary
plt.text(label_x_pos, bar.get_y() + bar.get_height() / 2, f'{width}%', va='center')
# Customize the plot aesthetics for better readability and presentation
plt.xlabel('Percentage')
plt.ylabel('EPC Rating')
plt.title(title)
plt.tight_layout() # Adjust layout to not cut off labels
plt.grid(axis='x', linestyle='--') # Add a light grid for better readability
# Show the plot
plt.show()

View file

@ -0,0 +1,26 @@
"""
This script contains the code to generate the data required to populate the slides
We connect to the database amd extract the data for the portfolio needed so it is recommended to use
a environment akin to the backend to run this script
"""
import pandas as pd
from backend.app.db.connection import db_engine
from sqlalchemy.orm import sessionmaker
from etl.customers.slide_utils import get_properties_by_portfolio_id, plot_epc_distribution
PORTFOLIO_ID = 66
def app():
# Connect to database
session = sessionmaker(bind=db_engine)()
# Get the properties for the portfolio
properties = get_properties_by_portfolio_id(session, PORTFOLIO_ID)
# The first visual we want to produce is a horizontal bar chart showing the number of properties at each current
# EPC band
properties_df = pd.DataFrame(properties)
epc_rating_summary = properties_df.groupby("current_epc_rating").size().reset_index(name="count")
epc_rating_summary["percentage"] = epc_rating_summary["count"] / epc_rating_summary["count"].sum() * 100

View file

@ -58,21 +58,22 @@ class Recommendations:
property_recommendations = []
phase = 0
# Building Fabric
self.wall_recomender.recommend(phase=phase)
if self.wall_recomender.recommendations:
property_recommendations.append(self.wall_recomender.recommendations)
phase += 1
# Ventilation recommendations
# We only produce a ventilation recommendation if the property is recommended to have wall or roof insulation
# We will not attribute a SAP impact to the ventilation recommendation, since we've seen that this has no
# real impact on the SAP score. Therefore, we don't need to include phasing for ventilation. If we have any
# wall or roof recommendations, we will ensure that ventilation is included in the simulation
if self.wall_recomender.recommendations or self.roof_recommender.recommendations:
self.ventilation_recomender.recommend()
if self.ventilation_recomender.recommendation:
property_recommendations.append(self.ventilation_recomender.recommendation)
print("WALL RECOMMENDATIONS HAVE BEEN COMMENTED OUT TEMPORARILY - ADD ME BACK IN")
# # Building Fabric
# self.wall_recomender.recommend(phase=phase)
# if self.wall_recomender.recommendations:
# property_recommendations.append(self.wall_recomender.recommendations)
# phase += 1
#
# # Ventilation recommendations
# # We only produce a ventilation recommendation if the property is recommended to have wall or roof insulation
# # We will not attribute a SAP impact to the ventilation recommendation, since we've seen that this has no
# # real impact on the SAP score. Therefore, we don't need to include phasing for ventilation. If we have any
# # wall or roof recommendations, we will ensure that ventilation is included in the simulation
# if self.wall_recomender.recommendations or self.roof_recommender.recommendations:
# self.ventilation_recomender.recommend()
# if self.ventilation_recomender.recommendation:
# property_recommendations.append(self.ventilation_recomender.recommendation)
self.roof_recommender.recommend(phase=phase)
if self.roof_recommender.recommendations:
@ -100,6 +101,12 @@ class Recommendations:
property_recommendations.append(self.heating_recommender.recommendations)
phase += 1
# Hot water
self.hotwater_recommender.recommend(phase=phase)
if self.hotwater_recommender.recommendations:
property_recommendations.append(self.hotwater_recommender.recommendations)
phase += 1
self.lighting_recommender.recommend(phase=phase)
if self.lighting_recommender.recommendation:
property_recommendations.append(self.lighting_recommender.recommendation)