mabuseif/HVAC
0
1"""2Visualization utilities for HVAC Load Calculator3 4This module provides enhanced visualization functions for creating interactive5and informative charts for the HVAC Load Calculator application.6"""7 8import plotly.express as px9import plotly.graph_objects as go10import pandas as pd11import numpy as np12 13 14def create_load_breakdown_chart(load_components, title="Load Breakdown"):15 """16 Create an enhanced pie chart for load components breakdown.17 18 Args:19 load_components (dict): Dictionary of load components and their values20 title (str): Chart title21 22 Returns:23 plotly.graph_objects.Figure: Interactive pie chart24 """25 # Remove zero values26 load_components = {k: v for k, v in load_components.items() if v > 0}27 28 # Create figure29 fig = go.Figure()30 31 # Add pie chart32 fig.add_trace(go.Pie(33 labels=list(load_components.keys()),34 values=list(load_components.values()),35 textinfo='label+percent',36 insidetextorientation='radial',37 marker=dict(38 colors=px.colors.qualitative.Bold,39 line=dict(color='white', width=2)40 ),41 pull=[0.05 if x == max(load_components.values()) else 0 for x in load_components.values()],42 hovertemplate='<b>%{label}</b><br>%{value:.1f} W<br>%{percent}<extra></extra>'43 ))44 45 # Update layout46 fig.update_layout(47 title={48 'text': title,49 'y': 0.95,50 'x': 0.5,51 'xanchor': 'center',52 'yanchor': 'top',53 'font': dict(size=20)54 },55 legend=dict(56 orientation="h",57 yanchor="bottom",58 y=-0.2,59 xanchor="center",60 x=0.5,61 font=dict(size=12)62 ),63 height=500,64 margin=dict(t=80, b=80, l=40, r=40),65 paper_bgcolor='rgba(0,0,0,0)',66 plot_bgcolor='rgba(0,0,0,0)'67 )68 69 return fig70 71 72def create_component_bar_chart(df, x_col, y_col, color_col=None, title="Component Breakdown"):73 """74 Create an enhanced bar chart for component breakdown.75 76 Args:77 df (pd.DataFrame): DataFrame containing the data78 x_col (str): Column name for x-axis79 y_col (str): Column name for y-axis80 color_col (str, optional): Column name for color grouping81 title (str): Chart title82 83 Returns:84 plotly.graph_objects.Figure: Interactive bar chart85 """86 # Create figure87 if color_col:88 fig = px.bar(89 df,90 x=x_col,91 y=y_col,92 color=color_col,93 title=title,94 color_discrete_sequence=px.colors.qualitative.Bold,95 height=500,96 text=y_col97 )98 else:99 fig = px.bar(100 df,101 x=x_col,102 y=y_col,103 title=title,104 color_discrete_sequence=px.colors.qualitative.Bold,105 height=500,106 text=y_col107 )108 109 # Update layout110 fig.update_layout(111 xaxis_title=x_col,112 yaxis_title=y_col,113 legend_title=color_col if color_col else "",114 font=dict(size=12),115 xaxis={'categoryorder': 'total descending'},116 paper_bgcolor='rgba(0,0,0,0)',117 plot_bgcolor='rgba(0,0,0,0)',118 hovermode="x unified"119 )120 121 # Add data labels122 fig.update_traces(123 texttemplate='%{y:.1f}',124 textposition='outside',125 hovertemplate='<b>%{x}</b><br>%{y:.1f}<extra></extra>'126 )127 128 # Add grid lines129 fig.update_yaxes(130 showgrid=True,131 gridwidth=1,132 gridcolor='rgba(211,211,211,0.3)'133 )134 135 return fig136 137 138def create_stacked_bar_chart(df, x_col, y_cols, names, title="Stacked Bar Chart"):139 """140 Create an enhanced stacked bar chart.141 142 Args:143 df (pd.DataFrame): DataFrame containing the data144 x_col (str): Column name for x-axis145 y_cols (list): List of column names for y-axis values146 names (list): List of names for each y-column147 title (str): Chart title148 149 Returns:150 plotly.graph_objects.Figure: Interactive stacked bar chart151 """152 # Create figure153 fig = go.Figure()154 155 # Add bars for each y column156 for i, y_col in enumerate(y_cols):157 fig.add_trace(go.Bar(158 x=df[x_col],159 y=df[y_col],160 name=names[i],161 hovertemplate=f'<b>{names[i]}</b>: %{{y:.1f}}<extra></extra>'162 ))163 164 # Update layout165 fig.update_layout(166 title=title,167 xaxis_title=x_col,168 yaxis_title="Value",169 barmode='stack',170 height=500,171 legend=dict(172 orientation="h",173 yanchor="bottom",174 y=1.02,175 xanchor="center",176 x=0.5177 ),178 paper_bgcolor='rgba(0,0,0,0)',179 plot_bgcolor='rgba(0,0,0,0)',180 hovermode="x unified"181 )182 183 # Add grid lines184 fig.update_yaxes(185 showgrid=True,186 gridwidth=1,187 gridcolor='rgba(211,211,211,0.3)'188 )189 190 return fig191 192 193def create_grouped_bar_chart(df, x_col, y_cols, names, title="Grouped Bar Chart"):194 """195 Create an enhanced grouped bar chart.196 197 Args:198 df (pd.DataFrame): DataFrame containing the data199 x_col (str): Column name for x-axis200 y_cols (list): List of column names for y-axis values201 names (list): List of names for each y-column202 title (str): Chart title203 204 Returns:205 plotly.graph_objects.Figure: Interactive grouped bar chart206 """207 # Create figure208 fig = go.Figure()209 210 # Add bars for each y column211 for i, y_col in enumerate(y_cols):212 fig.add_trace(go.Bar(213 x=df[x_col],214 y=df[y_col],215 name=names[i],216 hovertemplate=f'<b>{names[i]}</b>: %{{y:.1f}}<extra></extra>'217 ))218 219 # Update layout220 fig.update_layout(221 title=title,222 xaxis_title=x_col,223 yaxis_title="Value",224 barmode='group',225 height=500,226 legend=dict(227 orientation="h",228 yanchor="bottom",229 y=1.02,230 xanchor="center",231 x=0.5232 ),233 paper_bgcolor='rgba(0,0,0,0)',234 plot_bgcolor='rgba(0,0,0,0)',235 hovermode="x unified"236 )237 238 # Add grid lines239 fig.update_yaxes(240 showgrid=True,241 gridwidth=1,242 gridcolor='rgba(211,211,211,0.3)'243 )244 245 return fig246 247 248def create_heat_map_chart(df, x_col, y_col, z_col, title="Heat Map"):249 """250 Create an enhanced heat map chart.251 252 Args:253 df (pd.DataFrame): DataFrame containing the data254 x_col (str): Column name for x-axis255 y_col (str): Column name for y-axis256 z_col (str): Column name for z-axis (color)257 title (str): Chart title258 259 Returns:260 plotly.graph_objects.Figure: Interactive heat map chart261 """262 # Create figure263 fig = px.density_heatmap(264 df,265 x=x_col,266 y=y_col,267 z=z_col,268 title=title,269 color_continuous_scale="Viridis",270 height=500271 )272 273 # Update layout274 fig.update_layout(275 xaxis_title=x_col,276 yaxis_title=y_col,277 font=dict(size=12),278 paper_bgcolor='rgba(0,0,0,0)',279 plot_bgcolor='rgba(0,0,0,0)'280 )281 282 return fig283 284 285def create_line_chart(df, x_col, y_cols, names, title="Line Chart"):286 """287 Create an enhanced line chart.288 289 Args:290 df (pd.DataFrame): DataFrame containing the data291 x_col (str): Column name for x-axis292 y_cols (list): List of column names for y-axis values293 names (list): List of names for each y-column294 title (str): Chart title295 296 Returns:297 plotly.graph_objects.Figure: Interactive line chart298 """299 # Create figure300 fig = go.Figure()301 302 # Add lines for each y column303 for i, y_col in enumerate(y_cols):304 fig.add_trace(go.Scatter(305 x=df[x_col],306 y=df[y_col],307 mode='lines+markers',308 name=names[i],309 hovertemplate=f'<b>{names[i]}</b>: %{{y:.1f}}<extra></extra>'310 ))311 312 # Update layout313 fig.update_layout(314 title=title,315 xaxis_title=x_col,316 yaxis_title="Value",317 height=500,318 legend=dict(319 orientation="h",320 yanchor="bottom",321 y=1.02,322 xanchor="center",323 x=0.5324 ),325 paper_bgcolor='rgba(0,0,0,0)',326 plot_bgcolor='rgba(0,0,0,0)',327 hovermode="x unified"328 )329 330 # Add grid lines331 fig.update_yaxes(332 showgrid=True,333 gridwidth=1,334 gridcolor='rgba(211,211,211,0.3)'335 )336 337 fig.update_xaxes(338 showgrid=True,339 gridwidth=1,340 gridcolor='rgba(211,211,211,0.3)'341 )342 343 return fig344 345 346def create_sankey_diagram(nodes, links, title="Energy Flow"):347 """348 Create a Sankey diagram for energy flow visualization.349 350 Args:351 nodes (list): List of node labels352 links (dict): Dictionary with source, target, and value lists353 title (str): Chart title354 355 Returns:356 plotly.graph_objects.Figure: Interactive Sankey diagram357 """358 # Create figure359 fig = go.Figure(data=[go.Sankey(360 node=dict(361 pad=15,362 thickness=20,363 line=dict(color="black", width=0.5),364 label=nodes,365 color="blue"366 ),367 link=dict(368 source=links['source'],369 target=links['target'],370 value=links['value'],371 hovertemplate='%{source.label} → %{target.label}: %{value:.1f} W<extra></extra>'372 )373 )])374 375 # Update layout376 fig.update_layout(377 title=title,378 font=dict(size=12),379 height=600,380 paper_bgcolor='rgba(0,0,0,0)',381 plot_bgcolor='rgba(0,0,0,0)'382 )383 384 return fig385 386 387def create_gauge_chart(value, min_val, max_val, title="Gauge", threshold_values=None, threshold_colors=None):388 """389 Create a gauge chart for displaying a value within a range.390 391 Args:392 value (float): Value to display393 min_val (float): Minimum value of the range394 max_val (float): Maximum value of the range395 title (str): Chart title396 threshold_values (list, optional): List of threshold values397 threshold_colors (list, optional): List of colors for each threshold398 399 Returns:400 plotly.graph_objects.Figure: Interactive gauge chart401 """402 # Set default thresholds if not provided403 if threshold_values is None:404 threshold_values = [min_val, (min_val + max_val) / 2, max_val]405 406 if threshold_colors is None:407 threshold_colors = ["green", "yellow", "red"]408 409 # Create figure410 fig = go.Figure(go.Indicator(411 mode="gauge+number",412 value=value,413 domain={'x': [0, 1], 'y': [0, 1]},414 title={'text': title},415 gauge={416 'axis': {'range': [min_val, max_val]},417 'bar': {'color': "darkblue"},418 'steps': [419 {'range': [threshold_values[i], threshold_values[i+1]], 'color': threshold_colors[i]} 420 for i in range(len(threshold_values)-1)421 ],422 'threshold': {423 'line': {'color': "red", 'width': 4},424 'thickness': 0.75,425 'value': value426 }427 }428 ))429 430 # Update layout431 fig.update_layout(432 height=300,433 paper_bgcolor='rgba(0,0,0,0)',434 plot_bgcolor='rgba(0,0,0,0)'435 )436 437 return fig438 439 440def create_enhanced_results_visualization(results):441 """442 Create enhanced visualizations for HVAC load calculation results.443 444 Args:445 results (dict): Dictionary containing calculation results446 447 Returns:448 dict: Dictionary of plotly figures449 """450 figures = {}451 452 # Prepare data for load breakdown pie chart453 load_components = {454 'Walls': results.get('wall_loss', 0),455 'Roof': results.get('roof_loss', 0),456 'Floor': results.get('floor_loss', 0),457 'Windows & Doors': results.get('window_loss', 0),458 'Infiltration': results.get('infiltration_loss', 0),459 'Ventilation': results.get('ventilation_loss', 0) - results.get('infiltration_loss', 0)460 }461 462 # Create load breakdown pie chart463 figures['load_breakdown'] = create_load_breakdown_chart(464 load_components, 465 title="Heating Load Components"466 )467 468 # Create energy flow Sankey diagram469 if 'internal_gain' in results and results['internal_gain'] > 0:470 # Create nodes and links for Sankey diagram471 nodes = [472 "Walls", "Roof", "Floor", "Windows & Doors", 473 "Infiltration", "Ventilation", "Internal Gains", 474 "Total Heat Loss", "Net Heating Load"475 ]476 477 links = {478 'source': [0, 1, 2, 3, 4, 5, 7, 6],479 'target': [7, 7, 7, 7, 7, 7, 8, 8],480 'value': [481 load_components['Walls'],482 load_components['Roof'],483 load_components['Floor'],484 load_components['Windows & Doors'],485 load_components['Infiltration'],486 load_components['Ventilation'],487 results['internal_gain'],488 results['total_heat_loss']489 ]490 }491 492 figures['energy_flow'] = create_sankey_diagram(493 nodes, 494 links, 495 title="Heating Energy Flow"496 )497 498 # Create gauge chart for heating load per area499 if 'net_heating_load' in results and 'building_info' in results:500 floor_area = results['building_info'].get('floor_area', 80.0)501 heating_load_per_area = results['net_heating_load'] / floor_area502 503 figures['load_per_area_gauge'] = create_gauge_chart(504 heating_load_per_area,505 0,506 200,507 title="Heating Load per Area (W/m²)",508 threshold_values=[0, 50, 100, 150, 200],509 threshold_colors=["green", "lightgreen", "yellow", "orange", "red"]510 )511 512 return figures513 