Plot room heat balance ====================== This script: - Asks the user to open an IES-VE result file. - Plots the room heat balances for each room. This was originally published as an article here: https://www.stevenfirth.com/how-to-plot-room-heat-balance-results-in-ies-using-python/ .. image:: ../images/figure_how_to_plot_room_heat_balances.png .. code-block:: python # PlotRoomHeatBalance # - This script creates a plot of the (annual) heat gains and losses for all rooms in the building. # - The heat gains and losses are plotted as a horizontal stacked bars for each room. # 1. Setup # - import packages import iesve import os import math from tkinter import Tk, messagebox from tkinter.filedialog import askopenfilename import matplotlib.pyplot as plt import matplotlib.ticker # - instances current_project = iesve.VEProject.get_current_project() # - directories dir_current_project = current_project.path.replace('\\','/') print('dir_current_project: ', dir_current_project) if not os.path.exists(dir_current_project): root = Tk() root.withdraw() messagebox.showinfo('Error', 'No IESVE project folder found.', parent = root) root.destroy() quit() dir_vista = os.path.join(dir_current_project, 'vista') # 2. Select results file # - Select file root = Tk() root.withdraw() fp_in = askopenfilename(title = 'Select IES results file', parent = root, initialdir = dir_vista, filetypes = [("APS files","*.aps")]) root.destroy() print('fp_in: ', fp_in) # - Exit if filepath is empty string if fp_in == '': root = Tk() root.withdraw() messagebox.showinfo('User input needed', 'Please select a .aps results file.', parent = root) root.destroy() quit() # - Exit if filepath is not in project filepath elif not dir_current_project in fp_in: root = Tk() root.withdraw() messagebox.showinfo('User input needed', 'Please select a .aps results file in the current IES project.', parent = root) root.destroy() quit() # 3. Get room data # - a dictionary {room_id: room_general_data_dict} realmodel = current_project.models[0] bodies = realmodel.get_bodies(False) # False means get all bodies room_data_dict = {body.id: body.get_room_data().get_general() for body in bodies} # 4. Load gain data # - a dictionary {variable_name: {room_id: annual_total_heat_gain}} # - this selects only room variables which have 'units_type' as "Gain" data = {} with iesve.ResultsReader.open(fp_in) as f: vars = f.get_variables() for var in vars: d = {} if var['model_level'] == 'z' and var['units_type'] == 'Gain': for room_id in list(room_data_dict): x = f.get_room_results(room_id, var['aps_varname'], var['display_name'], 'z') x = sum(x) if x is not None else 0 d[room_id] = x/1000000 # convert to MWh/year data[var['display_name']] = d #for k,v in data.items(): print(k, v) # 5. Plot figure # height = (0.4 * len(room_data_dict)) if height < 2: height = 2 if height > 4: height = 4 # #height = 6 / 1920 * 1080 # fixed aspect ratio for publishing figure # fig, ax = plt.subplots( figsize = ( 6, height ), dpi = 200 ) positive_lefts = [0] * len(room_data_dict) negative_lefts = [0] * len(room_data_dict) # def plot_row(name, data, **kwargs): "" for i, (room_id, height) in enumerate(data.items()): if height > 0: left = positive_lefts[i] positive_lefts[i] += height else: left = negative_lefts[i] negative_lefts[i] += height line = ax.barh( i, height, left = left, label = name if i == 0 else None, edgecolor = 'black', linewidth = 0.5, **kwargs) return line # color_i = 0 for i, (k,v) in enumerate(data.items()): for x in v.values(): if not math.isclose(x,0): # plot variable provided at least one annual total is non-zero plot_row( k, v, color = f'C{color_i}', alpha = 0.5 ) color_i += 1 break ax.legend( loc='center left', bbox_to_anchor=(1, 0.5), fontsize=6 ) ax.set_xlabel('Annual heat gain (MWh/year)') ax.get_xaxis().set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) # thousands separator ax.set_xlim(min(negative_lefts) - (max(positive_lefts) - min(negative_lefts)) * 0.05, max(positive_lefts) + (max(positive_lefts) - min(negative_lefts)) * 0.05) # 5% margin on either side ax.set_yticks(range(len(room_data_dict))) ax.set_yticklabels([x['name'] for x in room_data_dict.values()]) ax.set_ylabel('Room') ax.yaxis.set_tick_params(labelsize=10 - len(room_data_dict) * 3 / 30) # reduces room name font size based on nmber of rooms fig.tight_layout() plt.show()