diff --git a/pages/explorer.py b/pages/explorer.py index f40b4e8..2614d10 100644 --- a/pages/explorer.py +++ b/pages/explorer.py @@ -13,7 +13,7 @@ three_var_graph, ) from pages.lib.global_element_ids import ElementIds -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables from pages.lib.global_id_buttons import IdButtons from pages.lib.global_tab_names import TabNames from pages.lib.global_scheme import ( @@ -93,25 +93,19 @@ def section_one(): id_button=IdButtons.EXPLORE_YEARLY_CHART_LABEL, doc_link=DocLinks.TEMP_HUMIDITY_EXPLAINED, ), - dcc.Loading( - type="circle", children=dmc.Paper(id=ElementIds.YEARLY_EXPLORE, p="sm") - ), + dcc.Loading(type="circle", children=dmc.Paper(id=ElementIds.YEARLY_EXPLORE)), title_with_link( text="Daily chart", id_button=IdButtons.EXPLORE_DAILY_CHART_LABEL, doc_link=DocLinks.TEMP_HUMIDITY_EXPLAINED, ), - dcc.Loading( - type="circle", children=dmc.Paper(id=ElementIds.QUERY_DAILY, p="sm") - ), + dcc.Loading(type="circle", children=dmc.Paper(id=ElementIds.QUERY_DAILY)), title_with_link( text="Heatmap chart", id_button=IdButtons.EXPLORE_HEATMAP_CHART_LABEL, doc_link=DocLinks.TEMP_HUMIDITY_EXPLAINED, ), - dcc.Loading( - type="circle", children=dmc.Paper(id=ElementIds.QUERY_HEATMAP, p="sm") - ), + dcc.Loading(type="circle", children=dmc.Paper(id=ElementIds.QUERY_HEATMAP)), title_with_tooltip( text="Descriptive statistics", tooltip_text="count, mean, std, min, max, and percentiles", @@ -209,7 +203,7 @@ def section_two_inputs(): dropdown( id=ElementIds.SEC2_VAR_DROPDOWN, options=explore_dropdown_names, - value=ColNames.RH, + value=Variables.RH.col_name, ), flex=1, ), @@ -293,7 +287,7 @@ def section_two_inputs(): dropdown( id=ElementIds.SEC2_DATA_FILTER_VAR, options=explore_dropdown_names, - value=ColNames.RH, + value=Variables.RH.col_name, ), flex=1, ), @@ -396,7 +390,7 @@ def section_three_inputs(): dropdown( id=ElementIds.TAB6_SEC3_VAR_Y_DROPDOWN, options=explore_dropdown_names, - value=ColNames.RH, + value=Variables.RH.col_name, ), flex=1, ), @@ -484,7 +478,7 @@ def section_three_inputs(): dropdown( id=ElementIds.TAB6_SEC3_FILTER_VAR_DROPDOWN, options=explore_dropdown_names, - value=ColNames.RH, + value=Variables.RH.col_name, ), flex=1, ), @@ -536,14 +530,12 @@ def section_three(): type="circle", children=dmc.Paper( id=ElementIds.THREE_VAR, - p="sm", ), ), dcc.Loading( type="circle", children=dmc.Paper( id=ElementIds.TWO_VAR, - p="sm", ), ), ], @@ -888,13 +880,20 @@ def update_table( ) filtered_df = df[ - (df[ColNames.MONTH] >= start_month) - & (df[ColNames.MONTH] <= end_month) - & (df[ColNames.HOUR] >= start_hour) - & (df[ColNames.HOUR] <= end_hour) + (df[Variables.MONTH.col_name] >= start_month) + & (df[Variables.MONTH.col_name] <= end_month) + & (df[Variables.HOUR.col_name] >= start_hour) + & (df[Variables.HOUR.col_name] <= end_hour) ] return summary_table_tmp_rh_tab( - filtered_df[[ColNames.MONTH, ColNames.HOUR, dd_value, ColNames.MONTH_NAMES]], + filtered_df[ + [ + Variables.MONTH.col_name, + Variables.HOUR.col_name, + dd_value, + Variables.MONTH_NAMES.col_name, + ] + ], dd_value, si_ip, ) diff --git a/pages/lib/charts_data_explorer.py b/pages/lib/charts_data_explorer.py index 4101271..f8541d5 100644 --- a/pages/lib/charts_data_explorer.py +++ b/pages/lib/charts_data_explorer.py @@ -2,8 +2,8 @@ import plotly.express as px import plotly.graph_objects as go from pages.lib.utils import get_max_min_value -from pages.lib.global_scheme import template, mapping_dictionary, month_lst -from pages.lib.global_column_names import ColNames +from pages.lib.global_scheme import template, month_lst +from pages.lib.global_variables import Variables, VariableInfo def custom_heatmap(df, global_local, var, time_filter_info, data_filter_info, si_ip): @@ -29,12 +29,16 @@ def custom_heatmap(df, global_local, var, time_filter_info, data_filter_info, si if df.dropna(subset=[var]).shape[0] == 0: return None - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] - var_name = mapping_dictionary[var][ColNames.NAME] - var_color = mapping_dictionary[var][ColNames.COLOR] - filter_name = mapping_dictionary[filter_var][ColNames.NAME] - filter_unit = mapping_dictionary[filter_var][si_ip][ColNames.UNIT] + variable = VariableInfo.from_col_name(var) + filter_variable = VariableInfo.from_col_name(filter_var) + + var_name = variable.get_name() + var_unit = variable.get_unit(si_ip) + var_range = variable.get_range(si_ip) + var_color = variable.get_color() + + filter_name = filter_variable.get_name() + filter_unit = filter_variable.get_unit(si_ip) if global_local == "global": # Set Global values for Max and minimum @@ -58,15 +62,18 @@ def custom_heatmap(df, global_local, var, time_filter_info, data_filter_info, si fig = go.Figure( data=go.Heatmap( - y=df[ColNames.HOUR], - x=df[ColNames.DOY], + y=df[Variables.HOUR.col_name], + x=df[Variables.DOY.col_name], z=df[var], colorscale=var_color, zmin=range_z[0], zmax=range_z[1], connectgaps=False, hoverongaps=False, - customdata=np.stack((df[ColNames.MONTH_NAMES], df[ColNames.DAY]), axis=-1), + customdata=np.stack( + (df[Variables.MONTH_NAMES.col_name], df[Variables.DAY.col_name]), + axis=-1, + ), hovertemplate=( "" + var @@ -109,12 +116,16 @@ def three_var_graph( min_val = data_filter_info3[2] max_val = data_filter_info3[3] - var_unit_x = mapping_dictionary[var_x][si_ip][ColNames.UNIT] - var_unit_y = mapping_dictionary[var_y][si_ip][ColNames.UNIT] + variable_x = VariableInfo.from_col_name(var_x) + variable_y = VariableInfo.from_col_name(var_y) + variable_color = VariableInfo.from_col_name(color_by) + + var_unit_x = variable_x.get_unit(si_ip) + var_unit_y = variable_y.get_unit(si_ip) + var_range = variable_color.get_range(si_ip) + var_color = variable_color.get_color() var = color_by - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] - var_color = mapping_dictionary[var][ColNames.COLOR] if global_local != "global": # Set maximum and minimum according to data @@ -129,15 +140,15 @@ def three_var_graph( else: df.loc[(df[filter_var] >= max_val) & (df[filter_var] <= min_val)] = None - if df.dropna(subset=[ColNames.MONTH]).shape[0] == 0: + if df.dropna(subset=[Variables.MONTH.col_name]).shape[0] == 0: return None title = ( - mapping_dictionary[var_x][ColNames.NAME] + variable_x.get_name() + " vs " - + mapping_dictionary[var_y][ColNames.NAME] + + variable_y.get_name() + " colored by " - + mapping_dictionary[color_by][ColNames.NAME] + + variable_color.get_name() ) fig = px.scatter( @@ -162,15 +173,18 @@ def three_var_graph( def two_var_graph(df, var_x, var_y, si_ip): + variable_x = VariableInfo.from_col_name(var_x) + variable_y = VariableInfo.from_col_name(var_y) + title = ( "Simultaneous frequency of " - + mapping_dictionary[var_x][ColNames.NAME] + + variable_x.get_name() + " and " - + mapping_dictionary[var_y][ColNames.NAME] + + variable_y.get_name() ) - var_unit_x = mapping_dictionary[var_x][si_ip][ColNames.UNIT] - var_unit_y = mapping_dictionary[var_y][si_ip][ColNames.UNIT] + var_unit_x = variable_x.get_unit(si_ip) + var_unit_y = variable_y.get_unit(si_ip) fig = px.density_heatmap( df, diff --git a/pages/lib/charts_summary.py b/pages/lib/charts_summary.py index d48a0a5..be3eb9b 100644 --- a/pages/lib/charts_summary.py +++ b/pages/lib/charts_summary.py @@ -1,15 +1,15 @@ import pandas as pd import plotly.express as px -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables def world_map(meta): """Return the world map showing the current location.""" - latitude = float(meta[ColNames.LAT]) - longitude = float(meta[ColNames.LON]) - city = meta[ColNames.CITY] - country = meta[ColNames.COUNTRY] - time_zone = float(meta[ColNames.TIME_ZONE]) + latitude = float(meta[Variables.LAT.col_name]) + longitude = float(meta[Variables.LON.col_name]) + city = meta[Variables.CITY.col_name] + country = meta[Variables.COUNTRY.col_name] + time_zone = float(meta[Variables.TIME_ZONE.col_name]) lat_long_df = pd.DataFrame( data={ "Lat": [latitude], diff --git a/pages/lib/charts_sun.py b/pages/lib/charts_sun.py index 9bd9747..b476636 100644 --- a/pages/lib/charts_sun.py +++ b/pages/lib/charts_sun.py @@ -9,24 +9,27 @@ from pages.lib.utils import get_max_min_value from pages.lib.global_scheme import ( template, - mapping_dictionary, degrees_unit, tight_margins, month_lst, ) from plotly.subplots import make_subplots from pvlib import solarposition -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables, VariableInfo def monthly_solar(epw_df, si_ip): g_h_rad_month_ave = ( - epw_df.groupby([ColNames.MONTH, ColNames.HOUR])[ColNames.GLOB_HOR_RAD] + epw_df.groupby([Variables.MONTH.col_name, Variables.HOUR.col_name])[ + Variables.GLOB_HOR_RAD.col_name + ] .median() .reset_index() ) dif_h_rad_month_ave = ( - epw_df.groupby([ColNames.MONTH, ColNames.HOUR])[ColNames.DIF_HOR_RAD] + epw_df.groupby([Variables.MONTH.col_name, Variables.HOUR.col_name])[ + Variables.DIF_HOR_RAD.col_name + ] .median() .reset_index() ) @@ -44,10 +47,12 @@ def monthly_solar(epw_df, si_ip): fig.add_trace( go.Scatter( x=g_h_rad_month_ave.loc[ - g_h_rad_month_ave[ColNames.MONTH] == i + 1, ColNames.HOUR + g_h_rad_month_ave[Variables.MONTH.col_name] == i + 1, + Variables.HOUR.col_name, ], y=g_h_rad_month_ave.loc[ - g_h_rad_month_ave[ColNames.MONTH] == i + 1, ColNames.GLOB_HOR_RAD + g_h_rad_month_ave[Variables.MONTH.col_name] == i + 1, + Variables.GLOB_HOR_RAD.col_name, ], fill="tozeroy", mode="lines", @@ -56,13 +61,16 @@ def monthly_solar(epw_df, si_ip): name="Global", showlegend=is_first, customdata=epw_df.loc[ - epw_df[ColNames.MONTH] == i + 1, ColNames.MONTH_NAMES + epw_df[Variables.MONTH.col_name] == i + 1, + Variables.MONTH_NAMES.col_name, ], hovertemplate=( "" + "Global Horizontal Solar Radiation" + ": %{y:.2f} " - + mapping_dictionary[ColNames.GLOB_HOR_RAD][si_ip][ColNames.UNIT] + + VariableInfo.from_col_name( + Variables.GLOB_HOR_RAD.col_name + ).get_unit(si_ip) + "
" + "Month: %{customdata}
" + "Hour: %{x}:00
" @@ -76,10 +84,12 @@ def monthly_solar(epw_df, si_ip): fig.add_trace( go.Scatter( x=dif_h_rad_month_ave.loc[ - dif_h_rad_month_ave[ColNames.MONTH] == i + 1, ColNames.HOUR + dif_h_rad_month_ave[Variables.MONTH.col_name] == i + 1, + Variables.HOUR.col_name, ], y=dif_h_rad_month_ave.loc[ - dif_h_rad_month_ave[ColNames.MONTH] == i + 1, ColNames.DIF_HOR_RAD + dif_h_rad_month_ave[Variables.MONTH.col_name] == i + 1, + Variables.DIF_HOR_RAD.col_name, ], fill="tozeroy", mode="lines", @@ -88,13 +98,16 @@ def monthly_solar(epw_df, si_ip): name="Diffuse", showlegend=is_first, customdata=epw_df.loc[ - epw_df[ColNames.MONTH] == i + 1, ColNames.MONTH_NAMES + epw_df[Variables.MONTH.col_name] == i + 1, + Variables.MONTH_NAMES.col_name, ], hovertemplate=( "" + "Diffuse Horizontal Solar Radiation" + ": %{y:.2f} " - + mapping_dictionary[ColNames.DIF_HOR_RAD][si_ip][ColNames.UNIT] + + VariableInfo.from_col_name( + Variables.DIF_HOR_RAD.col_name + ).get_unit(si_ip) + "
" + "Month: %{customdata}
" + "Hour: %{x}:00
" @@ -121,16 +134,16 @@ def monthly_solar(epw_df, si_ip): def polar_graph(df, meta, global_local, var, si_ip): """Return the figure for the custom sun path.""" - latitude = float(meta[ColNames.LAT]) - longitude = float(meta[ColNames.LON]) - time_zone = float(meta[ColNames.TIME_ZONE]) - solpos = df.loc[df[ColNames.APPARENT_ELEVATION] > 0, :] - + latitude = float(meta[Variables.LAT.col_name]) + longitude = float(meta[Variables.LON.col_name]) + time_zone = float(meta[Variables.TIME_ZONE.col_name]) + solpos = df.loc[df[Variables.APPARENT_ELEVATION.col_name] > 0, :] if var != "None": - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] - var_name = mapping_dictionary[var][ColNames.NAME] - var_color = mapping_dictionary[var][ColNames.COLOR] + variable = VariableInfo.from_col_name(var) + var_unit = variable.get_unit(si_ip) + var_range = variable.get_range(si_ip) + var_name = variable.get_name() + var_color = variable.get_color() if global_local == "global": # Set Global values for Max and minimum range_z = var_range @@ -145,7 +158,7 @@ def polar_graph(df, meta, global_local, var, si_ip): ) delta = timedelta(days=0, hours=time_zone - 1, minutes=0) times = times - delta - solpos = df.loc[df[ColNames.APPARENT_ELEVATION] > 0, :] + solpos = df.loc[df[Variables.APPARENT_ELEVATION.col_name] > 0, :] if var == "None": var_color = "orange" @@ -176,19 +189,20 @@ def polar_graph(df, meta, global_local, var, si_ip): if var == "None": fig.add_trace( go.Scatterpolar( - r=90 * np.cos(np.radians(90 - solpos[ColNames.APPARENT_ZENITH])), - theta=solpos[ColNames.AZIMUTH], + r=90 + * np.cos(np.radians(90 - solpos[Variables.APPARENT_ZENITH.col_name])), + theta=solpos[Variables.AZIMUTH.col_name], mode="markers", marker_color="orange", marker_size=marker_size, marker_line_width=0, customdata=np.stack( ( - solpos[ColNames.DAY], - solpos[ColNames.MONTH_NAMES], - solpos[ColNames.HOUR], - solpos[ColNames.ELEVATION], - solpos[ColNames.AZIMUTH], + solpos[Variables.DAY.col_name], + solpos[Variables.MONTH_NAMES.col_name], + solpos[Variables.HOUR.col_name], + solpos[Variables.ELEVATION.col_name], + solpos[Variables.AZIMUTH.col_name], ), axis=-1, ), @@ -206,8 +220,9 @@ def polar_graph(df, meta, global_local, var, si_ip): else: fig.add_trace( go.Scatterpolar( - r=90 * np.cos(np.radians(90 - solpos[ColNames.APPARENT_ZENITH])), - theta=solpos[ColNames.AZIMUTH], + r=90 + * np.cos(np.radians(90 - solpos[Variables.APPARENT_ZENITH.col_name])), + theta=solpos[Variables.AZIMUTH.col_name], mode="markers", marker=dict( color=solpos[var], @@ -220,11 +235,11 @@ def polar_graph(df, meta, global_local, var, si_ip): ), customdata=np.stack( ( - solpos[ColNames.DAY], - solpos[ColNames.MONTH_NAMES], - solpos[ColNames.HOUR], - solpos[ColNames.ELEVATION], - solpos[ColNames.AZIMUTH], + solpos[Variables.DAY.col_name], + solpos[Variables.MONTH_NAMES.col_name], + solpos[Variables.HOUR.col_name], + solpos[Variables.ELEVATION.col_name], + solpos[Variables.AZIMUTH.col_name], solpos[var], ), axis=-1, @@ -250,13 +265,13 @@ def polar_graph(df, meta, global_local, var, si_ip): for date in pd.to_datetime(["2019-03-21", "2019-06-21", "2019-12-21"]): times = pd.date_range( date, - date + pd.Timedelta(ColNames.TWENTY_FOUR_HOUR), - freq=ColNames.FIVE_MINUTE, + date + pd.Timedelta(Variables.TWENTY_FOUR_HOUR.col_name), + freq=Variables.FIVE_MINUTE.col_name, tz=tz, ) times = times - delta solpos = solarposition.get_solarposition(times, latitude, longitude) - solpos = solpos.loc[solpos[ColNames.APPARENT_ELEVATION] > 0, :] + solpos = solpos.loc[solpos[Variables.APPARENT_ELEVATION.col_name] > 0, :] fig.add_trace( go.Scatterpolar( @@ -279,13 +294,13 @@ def polar_graph(df, meta, global_local, var, si_ip): for date in pd.to_datetime(["2019-01-21", "2019-02-21", "2019-4-21", "2019-5-21"]): times = pd.date_range( date, - date + pd.Timedelta(ColNames.TWENTY_FOUR_HOUR), - freq=ColNames.FIVE_MINUTE, + date + pd.Timedelta(Variables.TWENTY_FOUR_HOUR.col_name), + freq=Variables.FIVE_MINUTE.col_name, tz=tz, ) times = times - delta solpos = solarposition.get_solarposition(times, latitude, longitude) - solpos = solpos.loc[solpos[ColNames.APPARENT_ELEVATION] > 0, :] + solpos = solpos.loc[solpos[Variables.APPARENT_ELEVATION.col_name] > 0, :] fig.add_trace( go.Scatterpolar( @@ -333,16 +348,16 @@ def polar_graph(df, meta, global_local, var, si_ip): def custom_cartesian_solar(df, meta, global_local, var, si_ip): """Return a graph of a latitude and longitude solar diagram.""" - latitude = float(meta[ColNames.LAT]) - longitude = float(meta[ColNames.LON]) - time_zone = float(meta[ColNames.TIME_ZONE]) + latitude = float(meta[Variables.LAT.col_name]) + longitude = float(meta[Variables.LON.col_name]) + time_zone = float(meta[Variables.TIME_ZONE.col_name]) tz = "UTC" - + variable = VariableInfo.from_col_name(var) if var != "None": - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] - var_name = mapping_dictionary[var][ColNames.NAME] - var_color = mapping_dictionary[var][ColNames.COLOR] + var_unit = variable.get_unit(si_ip) + var_range = variable.get_range(si_ip) + var_name = variable.get_name() + var_color = variable.get_color() if global_local == "global": # Set Global values for Max and minimum range_z = var_range @@ -364,19 +379,19 @@ def custom_cartesian_solar(df, meta, global_local, var, si_ip): if var == "None": fig.add_trace( go.Scatter( - y=df[ColNames.ELEVATION], - x=df[ColNames.AZIMUTH], + y=df[Variables.ELEVATION.col_name], + x=df[Variables.AZIMUTH.col_name], mode="markers", marker_color="orange", marker_size=marker_size, marker_line_width=0, customdata=np.stack( ( - df[ColNames.DAY], - df[ColNames.MONTH_NAMES], - df[ColNames.HOUR], - df[ColNames.ELEVATION], - df[ColNames.AZIMUTH], + df[Variables.DAY.col_name], + df[Variables.MONTH_NAMES.col_name], + df[Variables.HOUR.col_name], + df[Variables.ELEVATION.col_name], + df[Variables.AZIMUTH.col_name], ), axis=-1, ), @@ -394,8 +409,8 @@ def custom_cartesian_solar(df, meta, global_local, var, si_ip): else: fig.add_trace( go.Scatter( - y=df[ColNames.ELEVATION], - x=df[ColNames.AZIMUTH], + y=df[Variables.ELEVATION.col_name], + x=df[Variables.AZIMUTH.col_name], mode="markers", marker=dict( color=df[var], @@ -408,11 +423,11 @@ def custom_cartesian_solar(df, meta, global_local, var, si_ip): ), customdata=np.stack( ( - df[ColNames.DAY], - df[ColNames.MONTH_NAMES], - df[ColNames.HOUR], - df[ColNames.ELEVATION], - df[ColNames.AZIMUTH], + df[Variables.DAY.col_name], + df[Variables.MONTH_NAMES.col_name], + df[Variables.HOUR.col_name], + df[Variables.ELEVATION.col_name], + df[Variables.AZIMUTH.col_name], df[var], ), axis=-1, @@ -438,14 +453,14 @@ def custom_cartesian_solar(df, meta, global_local, var, si_ip): for date in pd.to_datetime(["2019-03-21", "2019-06-21", "2019-12-21"]): times = pd.date_range( date, - date + pd.Timedelta(ColNames.TWENTY_FOUR_HOUR), - freq=ColNames.FIVE_MINUTE, + date + pd.Timedelta(Variables.TWENTY_FOUR_HOUR.col_name), + freq=Variables.FIVE_MINUTE.col_name, tz=tz, ) delta = timedelta(days=0, hours=time_zone - 1, minutes=0) times = times - delta solpos = solarposition.get_solarposition(times, latitude, longitude) - solpos = solpos.loc[solpos[ColNames.APPARENT_ELEVATION] > 0, :] + solpos = solpos.loc[solpos[Variables.APPARENT_ELEVATION.col_name] > 0, :] fig.add_trace( go.Scatter( @@ -467,14 +482,14 @@ def custom_cartesian_solar(df, meta, global_local, var, si_ip): for date in pd.to_datetime(["2019-01-21", "2019-02-21", "2019-4-21", "2019-5-21"]): times = pd.date_range( date, - date + pd.Timedelta(ColNames.TWENTY_FOUR_HOUR), - freq=ColNames.FIVE_MINUTE, + date + pd.Timedelta(Variables.TWENTY_FOUR_HOUR.col_name), + freq=Variables.FIVE_MINUTE.col_name, tz=tz, ) delta = timedelta(days=0, hours=time_zone - 1, minutes=0) times = times - delta solpos = solarposition.get_solarposition(times, latitude, longitude) - solpos = solpos.loc[solpos[ColNames.APPARENT_ELEVATION] > 0, :] + solpos = solpos.loc[solpos[Variables.APPARENT_ELEVATION.col_name] > 0, :] fig.add_trace( go.Scatter( diff --git a/pages/lib/extract_df.py b/pages/lib/extract_df.py index 2e4ba5f..ded1c78 100644 --- a/pages/lib/extract_df.py +++ b/pages/lib/extract_df.py @@ -16,10 +16,10 @@ from pythermalcomfort.models import solar_gain from pythermalcomfort.models import utci from pythermalcomfort.utilities import running_mean_outdoor_temperature - +from config import UnitSystem from pages.lib.global_scheme import month_lst from pages.lib.utils import code_timer -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables, VariableInfo @code_timer @@ -68,7 +68,7 @@ def get_location_info(lst, file_name): # from OneClimaBuilding files extract info about reference years try: - location_info[ColNames.PERIOD] = re.search( + location_info[Variables.PERIOD.col_name] = re.search( r'cord=[\'"]?([^\'" >]+);', lst[5] ).group(1) except AttributeError: @@ -87,7 +87,7 @@ def utci_calc( t_air_col: str, t_rad_col: str, wind_col: str, - rh_col: str = ColNames.RH, + rh_col: str = Variables.RH.col_name, ) -> pd.Series: """Call utci() using values from df columns.""" return utci(df[t_air_col], df[t_rad_col], df[wind_col], df[rh_col]) @@ -102,21 +102,25 @@ def add_utci_variants(df: pd.DataFrame) -> pd.DataFrame: - Sun_noWind : DBT + MRT + wind_speed_utci_0 """ recipes = { - ColNames.UTCI_NO_SUN_WIND: ( - ColNames.DBT, - ColNames.DBT, - ColNames.WIND_SPEED_UTCI, + Variables.UTCI_NO_SUN_WIND.col_name: ( + Variables.DBT.col_name, + Variables.DBT.col_name, + Variables.WIND_SPEED_UTCI.col_name, + ), + Variables.UTCI_NO_SUN_NO_WIND.col_name: ( + Variables.DBT.col_name, + Variables.DBT.col_name, + Variables.WIND_SPEED_UTCI_0.col_name, ), - ColNames.UTCI_NO_SUN_NO_WIND: ( - ColNames.DBT, - ColNames.DBT, - ColNames.WIND_SPEED_UTCI_0, + Variables.UTCI_SUN_WIND.col_name: ( + Variables.DBT.col_name, + Variables.MRT.col_name, + Variables.WIND_SPEED_UTCI.col_name, ), - ColNames.UTCI_SUN_WIND: (ColNames.DBT, ColNames.MRT, ColNames.WIND_SPEED_UTCI), - ColNames.UTCI_SUN_NO_WIND: ( - ColNames.DBT, - ColNames.MRT, - ColNames.WIND_SPEED_UTCI_0, + Variables.UTCI_SUN_NO_WIND.col_name: ( + Variables.DBT.col_name, + Variables.MRT.col_name, + Variables.WIND_SPEED_UTCI_0.col_name, ), } for out_col, (t_air, t_rad, wind) in recipes.items(): @@ -127,10 +131,10 @@ def add_utci_variants(df: pd.DataFrame) -> pd.DataFrame: def add_utci_categories(df: pd.DataFrame) -> pd.DataFrame: """Bin the four UTCI columns into categories.""" mapping = { - ColNames.UTCI_NO_SUN_WIND: ColNames.UTCI_NOSUN_WIND_CATEGORIES, - ColNames.UTCI_NO_SUN_NO_WIND: ColNames.UTCI_NOSUN_NOWIND_CATEGORIES, - ColNames.UTCI_SUN_WIND: ColNames.UTCI_SUN_WIND_CATEGORIES, - ColNames.UTCI_SUN_NO_WIND: ColNames.UTCI_SUN_NOWIND_CATEGORIES, + Variables.UTCI_NO_SUN_WIND.col_name: Variables.UTCI_NOSUN_WIND_CATEGORIES.col_name, + Variables.UTCI_NO_SUN_NO_WIND.col_name: Variables.UTCI_NOSUN_NOWIND_CATEGORIES.col_name, + Variables.UTCI_SUN_WIND.col_name: Variables.UTCI_SUN_WIND_CATEGORIES.col_name, + Variables.UTCI_SUN_NO_WIND.col_name: Variables.UTCI_SUN_NOWIND_CATEGORIES.col_name, } for src_col, dst_col in mapping.items(): df[dst_col] = pd.cut(x=df[src_col], bins=UTCI_BINS, labels=UTCI_LABELS) @@ -156,7 +160,7 @@ def create_df(lst, file_name): # from OneClimaBuilding files extract info about reference years try: - location_info[ColNames.PERIOD] = re.search( + location_info[Variables.PERIOD.col_name] = re.search( r'cord=[\'"]?([^\'" >]+);', lst[5] ).group(1) except AttributeError: @@ -174,35 +178,35 @@ def create_df(lst, file_name): del line[-1] col_names = [ - "year", - "month", - "day", - "hour", - "DBT", - "DPT", - "RH", - "p_atm", - "extr_hor_rad", - "hor_ir_rad", - "glob_hor_rad", - "dir_nor_rad", - "dif_hor_rad", - "glob_hor_ill", - "dir_nor_ill", - "dif_hor_ill", - "Zlumi", - "wind_dir", - ColNames.WIND_SPEED, - "tot_sky_cover", - "Oskycover", - "Vis", - "Cheight", - "PWobs", - "PWcodes", - "Pwater", - "AsolOptD", - "SnowD", - "DaySSnow", + Variables.YEAR.col_name, + Variables.MONTH.col_name, + Variables.DAY.col_name, + Variables.HOUR.col_name, + Variables.DBT.col_name, + Variables.DPT.col_name, + Variables.RH.col_name, + Variables.P_ATM.col_name, + Variables.EXTR_HOR_RAD.col_name, + Variables.HOR_IR_RAD.col_name, + Variables.GLOB_HOR_RAD.col_name, + Variables.DIR_NOR_RAD.col_name, + Variables.DIF_HOR_RAD.col_name, + Variables.GLOB_HOR_ILL.col_name, + Variables.DIR_NOR_ILL.col_name, + Variables.DIF_HOR_ILL.col_name, + Variables.ZLUMI.col_name, + Variables.WIND_DIR.col_name, + Variables.WIND_SPEED.col_name, + Variables.TOT_SKY_COVER.col_name, + Variables.OPAQUE_SKY_COVER.col_name, + Variables.VIS.col_name, + Variables.CLOUD_HEIGHT.col_name, + Variables.PRECIPITATION_OBSERVATION.col_name, + Variables.PRECIPITATION_CODES.col_name, + Variables.PRECIPITATION_WATER.col_name, + Variables.AEROSOL_OPTICAL_DEPTH.col_name, + Variables.SNOW_DEPTH.col_name, + Variables.DAILY_SNOW.col_name, ] # assign column names, if fewer cols are there than supposed assign 9999 to that col @@ -214,70 +218,88 @@ def create_df(lst, file_name): epw_df = pd.DataFrame(columns=col_names, data=lst) # from EnergyPlus files extract info about reference years - if not location_info[ColNames.PERIOD]: - years = epw_df[ColNames.YEAR].astype("int").unique() + if not location_info[Variables.PERIOD.col_name]: + years = epw_df[Variables.YEAR.col_name].astype("int").unique() if len(years) == 1: year_rounded_up = int(math.ceil(years[0] / 10.0)) * 10 - location_info[ColNames.PERIOD] = f"{year_rounded_up - 10}-{year_rounded_up}" + location_info[Variables.PERIOD.col_name] = ( + f"{year_rounded_up - 10}-{year_rounded_up}" + ) else: min_year = int(math.floor(min(years) / 10.0)) * 10 max_year = int(math.ceil(max(years) / 10.0)) * 10 - location_info[ColNames.PERIOD] = f"{min_year}-{max_year}" + location_info[Variables.PERIOD.col_name] = f"{min_year}-{max_year}" # Add fake_year - epw_df[ColNames.FAKE_YEAR] = ColNames.YEAR + epw_df[Variables.FAKE_YEAR.col_name] = Variables.YEAR.col_name # Add in month names month_look_up = {ix + 1: month for ix, month in enumerate(month_lst)} - epw_df[ColNames.MONTH_NAMES] = ( - epw_df[ColNames.MONTH].astype("int").map(month_look_up) + epw_df[Variables.MONTH_NAMES.col_name] = ( + epw_df[Variables.MONTH.col_name].astype("int").map(month_look_up) ) # Change to int type - epw_df[[ColNames.YEAR, ColNames.DAY, ColNames.MONTH, ColNames.HOUR]] = epw_df[ - [ColNames.YEAR, ColNames.DAY, ColNames.MONTH, ColNames.HOUR] + epw_df[ + [ + Variables.YEAR.col_name, + Variables.DAY.col_name, + Variables.MONTH.col_name, + Variables.HOUR.col_name, + ] + ] = epw_df[ + [ + Variables.YEAR.col_name, + Variables.DAY.col_name, + Variables.MONTH.col_name, + Variables.HOUR.col_name, + ] ].astype(int) # Add in DOY df_doy = ( - epw_df.groupby([ColNames.MONTH, ColNames.DAY])[ColNames.HOUR] + epw_df.groupby([Variables.MONTH.col_name, Variables.DAY.col_name])[ + Variables.HOUR.col_name + ] .count() .reset_index() ) - df_doy[ColNames.DOY] = df_doy.index + 1 + df_doy[Variables.DOY.col_name] = df_doy.index + 1 epw_df = pd.merge( epw_df, - df_doy[[ColNames.MONTH, ColNames.DAY, ColNames.DOY]], - on=[ColNames.MONTH, ColNames.DAY], + df_doy[ + [Variables.MONTH.col_name, Variables.DAY.col_name, Variables.DOY.col_name] + ], + on=[Variables.MONTH.col_name, Variables.DAY.col_name], how="left", ) change_to_float = [ - "DBT", - "DPT", - "RH", - "p_atm", - "extr_hor_rad", - "hor_ir_rad", - "glob_hor_rad", - "dir_nor_rad", - "dif_hor_rad", - "glob_hor_ill", - "dir_nor_ill", - "dif_hor_ill", - "Zlumi", - "wind_dir", - ColNames.WIND_SPEED, - "tot_sky_cover", - "Oskycover", - "Vis", - "Cheight", - "PWobs", - "PWcodes", - "Pwater", - "AsolOptD", - "SnowD", - "DaySSnow", + Variables.DBT.col_name, + Variables.DPT.col_name, + Variables.RH.col_name, + Variables.P_ATM.col_name, + Variables.EXTR_HOR_RAD.col_name, + Variables.HOR_IR_RAD.col_name, + Variables.GLOB_HOR_RAD.col_name, + Variables.DIR_NOR_RAD.col_name, + Variables.DIF_HOR_RAD.col_name, + Variables.GLOB_HOR_ILL.col_name, + Variables.DIR_NOR_ILL.col_name, + Variables.DIF_HOR_ILL.col_name, + Variables.ZLUMI.col_name, + Variables.WIND_DIR.col_name, + Variables.WIND_SPEED.col_name, + Variables.TOT_SKY_COVER.col_name, + Variables.OPAQUE_SKY_COVER.col_name, + Variables.VIS.col_name, + Variables.CLOUD_HEIGHT.col_name, + Variables.PRECIPITATION_OBSERVATION.col_name, + Variables.PRECIPITATION_CODES.col_name, + Variables.PRECIPITATION_WATER.col_name, + Variables.AEROSOL_OPTICAL_DEPTH.col_name, + Variables.SNOW_DEPTH.col_name, + Variables.DAILY_SNOW.col_name, ] epw_df[change_to_float] = epw_df[change_to_float].astype(float) @@ -285,24 +307,34 @@ def create_df(lst, file_name): times = pd.date_range( "2019-01-01 00:00:00", "2020-01-01", inclusive="left", freq="h", tz="UTC" ) - epw_df[ColNames.UTC_TIME] = pd.to_datetime(times) - delta = timedelta(days=0, hours=location_info[ColNames.TIME_ZONE] - 1, minutes=0) + epw_df[Variables.UTC_TIME.col_name] = pd.to_datetime(times) + delta = timedelta( + days=0, hours=location_info[Variables.TIME_ZONE.col_name] - 1, minutes=0 + ) times = times - delta - epw_df[ColNames.TIMES] = times + epw_df[Variables.TIMES.col_name] = times epw_df.set_index( - ColNames.TIMES, drop=False, append=False, inplace=True, verify_integrity=False + Variables.TIMES.col_name, + drop=False, + append=False, + inplace=True, + verify_integrity=False, ) # Add in solar position df solar_position = solarposition.get_solarposition( - times, location_info[ColNames.LAT], location_info[ColNames.LON] + times, + location_info[Variables.LAT.col_name], + location_info[Variables.LON.col_name], ) epw_df = pd.concat([epw_df, solar_position], axis=1) # Add in UTCI - sol_altitude = epw_df[ColNames.ELEVATION].mask(epw_df[ColNames.ELEVATION] <= 0, 0) + sol_altitude = epw_df[Variables.ELEVATION.col_name].mask( + epw_df[Variables.ELEVATION.col_name] <= 0, 0 + ) sharp = expand_to_hours(45) - sol_radiation_dir = epw_df[ColNames.DIR_NOR_RAD] + sol_radiation_dir = epw_df[Variables.DIR_NOR_RAD.col_name] sol_transmittance = expand_to_hours(1) # CHECK VALUE f_svv = expand_to_hours(1) # CHECK VALUE f_bes = expand_to_hours(1) # CHECK VALUE @@ -322,44 +354,52 @@ def create_df(lst, file_name): floor_reflectance, ) mrt_df = pd.DataFrame.from_records(mrt) - mrt_df[ColNames.DELTA_MRT] = mrt_df[ColNames.DELTA_MRT].mask( - mrt_df[ColNames.DELTA_MRT] >= 70, 70 + mrt_df[Variables.DELTA_MRT.col_name] = mrt_df[Variables.DELTA_MRT.col_name].mask( + mrt_df[Variables.DELTA_MRT.col_name] >= 70, 70 ) mrt_df = mrt_df.set_index(epw_df.times) epw_df = epw_df.join(mrt_df) - epw_df[ColNames.MRT] = epw_df[ColNames.DELTA_MRT] + epw_df[ColNames.DBT] - epw_df[ColNames.WIND_SPEED_UTCI] = epw_df[ColNames.WIND_SPEED] - epw_df[ColNames.WIND_SPEED_UTCI] = epw_df[ColNames.WIND_SPEED_UTCI].mask( - epw_df[ColNames.WIND_SPEED_UTCI] >= 17, 16.9 - ) - epw_df[ColNames.WIND_SPEED_UTCI] = epw_df[ColNames.WIND_SPEED_UTCI].mask( - epw_df[ColNames.WIND_SPEED_UTCI] <= 0.5, 0.6 - ) - epw_df[ColNames.WIND_SPEED_UTCI_0] = epw_df[ColNames.WIND_SPEED_UTCI].mask( - epw_df[ColNames.WIND_SPEED_UTCI] >= 0, 0.5 + epw_df[Variables.MRT.col_name] = ( + epw_df[Variables.DELTA_MRT.col_name] + epw_df[Variables.DBT.col_name] ) + epw_df[Variables.WIND_SPEED_UTCI.col_name] = epw_df[Variables.WIND_SPEED.col_name] + epw_df[Variables.WIND_SPEED_UTCI.col_name] = epw_df[ + Variables.WIND_SPEED_UTCI.col_name + ].mask(epw_df[Variables.WIND_SPEED_UTCI.col_name] >= 17, 16.9) + epw_df[Variables.WIND_SPEED_UTCI.col_name] = epw_df[ + Variables.WIND_SPEED_UTCI.col_name + ].mask(epw_df[Variables.WIND_SPEED_UTCI.col_name] <= 0.5, 0.6) + epw_df[Variables.WIND_SPEED_UTCI_0.col_name] = epw_df[ + Variables.WIND_SPEED_UTCI.col_name + ].mask(epw_df[Variables.WIND_SPEED_UTCI.col_name] >= 0, 0.5) epw_df = add_utci_variants(epw_df) epw_df = add_utci_categories(epw_df) # Add psy values - ta_rh = np.vectorize(psy.psy_ta_rh)(epw_df[ColNames.DBT], epw_df[ColNames.RH]) + ta_rh = np.vectorize(psy.psy_ta_rh)( + epw_df[Variables.DBT.col_name], epw_df[Variables.RH.col_name] + ) psy_df = pd.DataFrame.from_records(ta_rh) psy_df = psy_df.set_index(epw_df.times) epw_df = epw_df.join(psy_df) # calculate adaptive data - dbt_day_ave = epw_df.groupby([ColNames.DOY])[ColNames.DBT].mean().to_list() + dbt_day_ave = ( + epw_df.groupby([Variables.DOY.col_name])[Variables.DBT.col_name] + .mean() + .to_list() + ) n = 7 - epw_df[ColNames.ADAPTIVE_COMFORT] = np.nan - epw_df[ColNames.ADAPTIVE_CMF_80_LOW] = np.nan - epw_df[ColNames.ADAPTIVE_CMF_80_UP] = np.nan - epw_df[ColNames.ADAPTIVE_CMF_90_LOW] = np.nan - epw_df[ColNames.ADAPTIVE_CMF_90_UP] = np.nan - epw_df[ColNames.ADAPTIVE_CMF_RMT] = np.nan + epw_df[Variables.ADAPTIVE_COMFORT.col_name] = np.nan + epw_df[Variables.ADAPTIVE_CMF_80_LOW.col_name] = np.nan + epw_df[Variables.ADAPTIVE_CMF_80_UP.col_name] = np.nan + epw_df[Variables.ADAPTIVE_CMF_90_LOW.col_name] = np.nan + epw_df[Variables.ADAPTIVE_CMF_90_UP.col_name] = np.nan + epw_df[Variables.ADAPTIVE_CMF_RMT.col_name] = np.nan for day in epw_df.DOY.unique(): i = day - 1 if i < n: @@ -380,19 +420,21 @@ def create_df(lst, file_name): v=0.5, limit_inputs=False, ) - epw_df.loc[epw_df.DOY == day, ColNames.ADAPTIVE_CMF_RMT] = rmt - epw_df.loc[epw_df.DOY == day, ColNames.ADAPTIVE_COMFORT] = r[ColNames.TMP_CMF] - epw_df.loc[epw_df.DOY == day, ColNames.ADAPTIVE_CMF_80_LOW] = r[ - ColNames.TMP_CMF_80_LOW + epw_df.loc[epw_df.DOY == day, Variables.ADAPTIVE_CMF_RMT.col_name] = rmt + epw_df.loc[epw_df.DOY == day, Variables.ADAPTIVE_COMFORT.col_name] = r[ + Variables.TMP_CMF.col_name ] - epw_df.loc[epw_df.DOY == day, ColNames.ADAPTIVE_CMF_80_UP] = r[ - ColNames.TMP_CMF_80_UP + epw_df.loc[epw_df.DOY == day, Variables.ADAPTIVE_CMF_80_LOW.col_name] = r[ + Variables.TMP_CMF_80_LOW.col_name ] - epw_df.loc[epw_df.DOY == day, ColNames.ADAPTIVE_CMF_90_LOW] = r[ - ColNames.TMP_CMF_90_LOW + epw_df.loc[epw_df.DOY == day, Variables.ADAPTIVE_CMF_80_UP.col_name] = r[ + Variables.TMP_CMF_80_UP.col_name ] - epw_df.loc[epw_df.DOY == day, ColNames.ADAPTIVE_CMF_90_UP] = r[ - ColNames.TMP_CMF_90_UP + epw_df.loc[epw_df.DOY == day, Variables.ADAPTIVE_CMF_90_LOW.col_name] = r[ + Variables.TMP_CMF_90_LOW.col_name + ] + epw_df.loc[epw_df.DOY == day, Variables.ADAPTIVE_CMF_90_UP.col_name] = r[ + Variables.TMP_CMF_90_UP.col_name ] return epw_df, location_info @@ -408,47 +450,55 @@ def convert_SI_to_IP(df: pd.DataFrame, name: str) -> None: return match name: case ( - ColNames.DBT - | ColNames.DPT - | ColNames.T_WB - | ColNames.T_DP - | ColNames.UTCI_SUN_WIND - | ColNames.UTCI_NO_SUN_WIND - | ColNames.UTCI_SUN_NO_WIND - | ColNames.UTCI_NO_SUN_NO_WIND - | ColNames.ADAPTIVE_COMFORT - | ColNames.ADAPTIVE_CMF_80_LOW - | ColNames.ADAPTIVE_CMF_80_UP - | ColNames.ADAPTIVE_CMF_90_LOW - | ColNames.ADAPTIVE_CMF_90_UP + Variables.DBT.col_name + | Variables.DPT.col_name + | Variables.T_WB.col_name + | Variables.T_DP.col_name + | Variables.UTCI_SUN_WIND.col_name + | Variables.UTCI_NO_SUN_WIND.col_name + | Variables.UTCI_SUN_NO_WIND.col_name + | Variables.UTCI_NO_SUN_NO_WIND.col_name + | Variables.ADAPTIVE_COMFORT.col_name + | Variables.ADAPTIVE_CMF_80_LOW.col_name + | Variables.ADAPTIVE_CMF_80_UP.col_name + | Variables.ADAPTIVE_CMF_90_LOW.col_name + | Variables.ADAPTIVE_CMF_90_UP.col_name ): df[name] = df[name] * 1.8 + 32 - case ColNames.P_ATM | ColNames.P_VAP | ColNames.P_SAT: + case ( + Variables.P_ATM.col_name + | Variables.P_VAP.col_name + | Variables.P_SAT.col_name + ): df[name] = df[name] * 0.000145038 case ( - ColNames.EXTR_HOR_RAD - | ColNames.HOR_IR_RAD - | ColNames.GLOB_HOR_RAD - | ColNames.DIR_NOR_RAD - | ColNames.DIF_HOR_RAD + Variables.EXTR_HOR_RAD.col_name + | Variables.HOR_IR_RAD.col_name + | Variables.GLOB_HOR_RAD.col_name + | Variables.DIR_NOR_RAD.col_name + | Variables.DIF_HOR_RAD.col_name ): df[name] = df[name] * 0.3169983306 - case ColNames.GLOB_HOR_ILL | ColNames.DIR_NOR_ILL | ColNames.DIF_HOR_ILL: + case ( + Variables.GLOB_HOR_ILL.col_name + | Variables.DIR_NOR_ILL.col_name + | Variables.DIF_HOR_ILL.col_name + ): df[name] = df[name] * 0.0929 - case ColNames.ZLUMI: + case Variables.ZLUMI.col_name: df[name] = df[name] * 0.0929 - case ColNames.WIND_SPEED: + case Variables.WIND_SPEED.col_name: df[name] = df[name] * 196.85039370078738 - case ColNames.VIS: + case Variables.VIS.col_name: df[name] = df[name] * 0.6215 - case ColNames.EH: + case Variables.EH.col_name: df[name] = df[name] * 0.000429923 case _: @@ -456,6 +506,23 @@ def convert_SI_to_IP(df: pd.DataFrame, name: str) -> None: pass +def convert_df_units(df: pd.DataFrame, unit_system: str) -> pd.DataFrame: + """Convert DataFrame columns to the specified unit system.""" + if unit_system != UnitSystem.IP: + return df # Currently we only support SI → IP + + df_converted = df.copy() + + for attr in dir(Variables): + if attr.isupper(): + var = getattr(Variables, attr) + if isinstance(var, VariableInfo): + col = var.col_name + convert_SI_to_IP(df_converted, col) + + return df_converted + + def convert_data(df, mapping_json): mapping_dict = json.loads(mapping_json) for key in mapping_dict: diff --git a/pages/lib/global_column_names.py b/pages/lib/global_column_names.py deleted file mode 100644 index 7980b90..0000000 --- a/pages/lib/global_column_names.py +++ /dev/null @@ -1,120 +0,0 @@ -class ColNames: - # ==================== Time related column ==================== - YEAR = "year" # year - PERIOD = "period" # period - MONTH = "month" # month - DAY = "day" # day - HOUR = "hour" # hour - MINUTE = "minute" # minute - - # ==================== Location related column ==================== - LAT = "lat" # Latitude - LON = "lon" # Longitude - CITY = "city" # City - COUNTRY = "country" # Country - TIME_ZONE = "time_zone" # Time Zone - - # ==================== Meteorological data column ==================== - DBT = "DBT" # Dry Bulb Temperature - DPT = "DPT" # Dew Point Temperature - RH = "RH" # Relative Humidity - HI_RH = "hiRH" # High Relative Humidity - LO_RH = "loRH" # Low Relative Humidity - HR = "hr" # Absolute Humidity - EH = "h" # Enthalpy - P_ATM = "p_atm" # Atmospheric Pressure - P_VAP = "p_vap" # Vapor partial Pressure - P_SAT = "p_sat" # Saturation Pressure - T_WB = "t_wb" # Wet Bulb Temperature - T_DP = "t_dp" # Dew Point Temperature - - # ==================== Radiation-related column ==================== - EXTR_HOR_RAD = "extr_hor_rad" # Extraterrestrial Horizontal Radiation - HOR_IR_RAD = "hor_ir_rad" # Horizontal Infrared Radiation - GLOB_HOR_RAD = "glob_hor_rad" # Global Horizontal Radiation - DIR_NOR_RAD = "dir_nor_rad" # Direct Normal Radiation - DIF_HOR_RAD = "dif_hor_rad" # Diffuse Horizontal Radiation - - # ==================== Lighting-related columns ==================== - GLOB_HOR_ILL = "glob_hor_ill" # Global Horizontal Illuminance - DIR_NOR_ILL = "dir_nor_ill" # Direct Normal Illuminance - DIF_HOR_ILL = "dif_hor_ill" # Diffuse Horizontal Illuminance - - # ==================== Other columns ==================== - ZLUMI = "Zlumi" # Luminance - WIND_DIR = "wind_dir" # Wind Direction - WIND_SPEED = "wind_speed" # Wind Speed - WIND_SPEED_UTCI = "wind_speed_utci" # Wind Speed Utci - WIND_SPEED_UTCI_0 = "wind_speed_utci_0" # Wind Speed Utci 0 - TOT_SKY_COVER = "tot_sky_cover" # Total Sky Cover - OSKYCOVER = "Oskycover" # Opaque Sky Cover - VIS = "Vis" # Visibility - CHEIGHT = "Cheight" # Cloud Height - # PWobs = "PWobs" # Precipitation Observation - # PWcodes = "PWcodes" # Precipitation Codes - # Pwater = "Pwater" # Precipitation Water - # AsolOptD = "AsolOptD" # Aerosol Optical Depth - # SnowD = "SnowD" # Snow Depth - # DaySSnow = "DaySSnow" # Daily Snow - ELEVATION = "elevation" # Elevation - EQUATION_OF_TIME = "equation_of_time" # Equation of time - APPARENT_ELEVATION = "apparent_elevation" # Apparent Elevation - APPARENT_ZENITH = "apparent_zenith" # Apparent Zenith - AZIMUTH = "azimuth" # Azimuth - ZENITH = "zenith" # Zenith - MRT = "MRT" - DELTA_MRT = "delta_mrt" - UTCI_SUN_WIND = "utci_Sun_Wind" # Utci Sun Wind - UTCI_SUN_NO_WIND = "utci_Sun_noWind" # Utci Sun no Wind - UTCI_NO_SUN_WIND = "utci_noSun_Wind" # Utci no Sun Wind - UTCI_NO_SUN_NO_WIND = "utci_noSun_noWind" # Utci no Sun no Wind - UTCI_SUN_WIND_CATEGORIES = "utci_Sun_Wind_categories" # Utci Sun Wind Categories - UTCI_SUN_NOWIND_CATEGORIES = ( - "utci_Sun_noWind_categories" # Utci Sun no Wind Categories - ) - UTCI_NOSUN_WIND_CATEGORIES = ( - "utci_noSun_Wind_categories" # Utci no Sun Wind Categories - ) - UTCI_NOSUN_NOWIND_CATEGORIES = ( - "utci_noSun_noWind_categories" # Utci no Sun no Wind Categories - ) - ADAPTIVE_COMFORT = "adaptive_comfort" # Adaptive comfort - ADAPTIVE_CMF_80_LOW = "adaptive_cmf_80_low" # Adaptive comfort 80 low - ADAPTIVE_CMF_80_UP = "adaptive_cmf_80_up" # Adaptive comfort 80 up - ADAPTIVE_CMF_90_LOW = "adaptive_cmf_90_low" # Adaptive comfort 90 low - ADAPTIVE_CMF_90_UP = "adaptive_cmf_90_up" # Adaptive comfort 90 up - ADAPTIVE_CMF_RMT = "adaptive_cmf_rmt" # Adaptive comfort rmt - NV_ALLOWED = "nv_allowed" - TMP_CMF = "tmp_cmf" - TMP_CMF_80_LOW = "tmp_cmf_80_low" - TMP_CMF_80_UP = "tmp_cmf_80_up" - TMP_CMF_90_LOW = "tmp_cmf_90_low" - TMP_CMF_90_UP = "tmp_cmf_90_up" - CONVERSION_FUNCTION = "conversion_function" - - # ==================== Calculation column ==================== - FAKE_YEAR = "fake_year" # Fake Year - MONTH_NAMES = "month_names" # Month names - UTC_TIME = "UTC_time" # UTC Time - DOY = "DOY" # Day of Year - - COLOR = "color" - NAME = "name" - RANGE = "range" - UNIT = "unit" - TWENTY_FOUR_HOUR = "24h" - FIVE_MINUTE = "5min" - TIMES = "times" - - PATH = "path" - FILE_NAME = "filename" - WIND_DIR_BINS = "WindDir_bins" - WIND_SPD_BINS = "WindSpd_bins" - - TO_IMAGE_BUTTON_OPTIONS = "toImageButtonOptions" - INVERT = "invert" - FEATURES = "features" - GEOMETRY_COORDINATES = "geometry.coordinates" - PROP_ID = "prop_id" - SITE_ELEVATION = "site_elevation" - NONE = "None" diff --git a/pages/lib/global_scheme.py b/pages/lib/global_scheme.py index 0793276..36fd2d0 100644 --- a/pages/lib/global_scheme.py +++ b/pages/lib/global_scheme.py @@ -1,7 +1,6 @@ import plotly.io as pio -from pages.lib.global_column_names import ColNames -from config import UnitSystem +from pages.lib.global_variables import Variables, VariableInfo # Colors Dictionary blue_red_yellow = ["#00b3ff", "#000082", "#ff0000", "#ffff00"] @@ -111,791 +110,105 @@ temperature_unit = "\u00b0C" thermal_stress_label = "Thermal stress" -mapping_dictionary = { - ColNames.NONE: {ColNames.NAME: "None"}, - ColNames.DOY: { - ColNames.NAME: "Day of the year", - ColNames.UNIT: "days", - ColNames.RANGE: [0, 365], - }, - ColNames.DAY: {ColNames.NAME: "day", ColNames.RANGE: [1, 31]}, - ColNames.MONTH: { - ColNames.NAME: "months", - ColNames.UNIT: "months", - ColNames.RANGE: [1, 12], - }, - ColNames.HOUR: { - ColNames.NAME: "Hour", - ColNames.COLOR: [ - "#000000", - "#355e7e", - "#6b5c7b", - "#c06c84", - "#f8b195", - "#c92a42", - "#c92a42", - "#c92a42", - "#000000", - ], - ColNames.UNIT: "h", - ColNames.RANGE: [1, 24], - }, - ColNames.DBT: { - ColNames.NAME: "Dry bulb temperature", - ColNames.COLOR: ["#00b3ff", "#000082", "#ff0000", "#ffff00"], - UnitSystem.SI: { - ColNames.UNIT: "°C", - ColNames.RANGE: [-40, 50], - }, - UnitSystem.IP: { - ColNames.UNIT: "°F", - ColNames.RANGE: [-40, 122], - }, - }, - ColNames.DPT: { - ColNames.NAME: "Dew point temperature", - ColNames.COLOR: ["#00b3ff", "#000082", "#ff0000", "#ffff00"], - UnitSystem.SI: { - ColNames.UNIT: "°C", - ColNames.RANGE: [-50, 35], - }, - UnitSystem.IP: { - ColNames.UNIT: "°F", - ColNames.RANGE: [-58, 95], - }, - }, - ColNames.RH: { - ColNames.NAME: "Relative humidity", - ColNames.COLOR: ["#ffe600", "#00c8ff", "#0000ff"], - UnitSystem.SI: { - ColNames.UNIT: "%", - ColNames.RANGE: [0, 100], - }, - UnitSystem.IP: { - ColNames.UNIT: "%", - ColNames.RANGE: [0, 100], - }, - }, - ColNames.P_ATM: { - ColNames.NAME: "Atmospheric pressure", - ColNames.COLOR: [ - "#ffffff", - "#b2f2ff", - "#33ddff", - "#00aaff", - "#0055ff", - "#0000ff", - "#aa00ff", - "#ff00ff", - "#cc0000", - "#ffaa00", - ], - UnitSystem.SI: { - ColNames.UNIT: "Pa", - ColNames.RANGE: [95000, 105000], - }, - UnitSystem.IP: { - ColNames.UNIT: "Psi", - ColNames.RANGE: [95000 * 0.000145038, 1050000.000145038], - }, - }, - ColNames.EXTR_HOR_RAD: { - ColNames.NAME: "Extraterrestrial horizontal irradiation", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "Wh/m2", - ColNames.RANGE: [0, 1200], - }, - UnitSystem.IP: { - ColNames.UNIT: "Btu/ft2", - ColNames.RANGE: [0, 1200 * 0.3169983306], - }, - }, - ColNames.HOR_IR_RAD: { - ColNames.NAME: "Horizontal infrared radiation", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "Wh/m2", - ColNames.RANGE: [0, 500], - }, - UnitSystem.IP: { - ColNames.UNIT: "Btu/ft2", - ColNames.RANGE: [0, 500 * 0.3169983306], - }, - }, - ColNames.GLOB_HOR_RAD: { - ColNames.NAME: "Global horizontal radiation", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "Wh/m2", - ColNames.RANGE: [0, 1200], - }, - UnitSystem.IP: { - ColNames.UNIT: "Btu/ft2", - ColNames.RANGE: [0, 1200 * 0.3169983306], - }, - }, - ColNames.DIR_NOR_RAD: { - ColNames.NAME: "Direct normal radiation", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "Wh/m2", - ColNames.RANGE: [0, 1200], - }, - UnitSystem.IP: { - ColNames.UNIT: "Btu/ft2", - ColNames.RANGE: [0, 1200 * 0.3169983306], - }, - }, - ColNames.DIF_HOR_RAD: { - ColNames.NAME: "Diffuse horizontal radiation", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "Wh/m2", - ColNames.RANGE: [0, 1200], - }, - UnitSystem.IP: { - ColNames.UNIT: "Btu/ft2", - ColNames.RANGE: [0, 1200 * 0.3169983306], - }, - }, - ColNames.GLOB_HOR_ILL: { - ColNames.NAME: "Global horizontal illuminance", - ColNames.COLOR: ["#4d6daa", "#a0beed", "#f1e969", "#eb7d05", "#d81600"], - UnitSystem.SI: { - ColNames.UNIT: "lux", - ColNames.RANGE: [0, 120000], - }, - UnitSystem.IP: { - ColNames.UNIT: "fc", - ColNames.RANGE: [0, 120000 * 0.0929], - }, - }, - ColNames.DIR_NOR_ILL: { - ColNames.NAME: "Direct normal illuminance", - ColNames.COLOR: ["#4d6daa", "#a0beed", "#f1e969", "#eb7d05", "#d81600"], - UnitSystem.SI: { - ColNames.UNIT: "lux", - ColNames.RANGE: [0, 120000], - }, - UnitSystem.IP: { - ColNames.UNIT: "fc", - ColNames.RANGE: [0, 120000 * 0.0929], - }, - }, - ColNames.DIF_HOR_ILL: { - ColNames.NAME: "Diffuse horizontal illuminance", - ColNames.COLOR: ["#4d6daa", "#a0beed", "#f1e969", "#eb7d05", "#d81600"], - UnitSystem.SI: { - ColNames.UNIT: "lux", - ColNames.RANGE: [0, 120000], - }, - UnitSystem.IP: { - ColNames.UNIT: "fc", - ColNames.RANGE: [0, 120000 * 0.0929], - }, - }, - ColNames.ZLUMI: { - ColNames.NAME: "Zenith luminance", - ColNames.COLOR: [ - "#730a8c", - "#0d0db3", - "#0f85be", - "#0f85be", - "#b11421", - "#fdf130", - ], - UnitSystem.SI: { - ColNames.UNIT: "cd/m2", - ColNames.RANGE: [0, 60000], - }, - UnitSystem.IP: { - ColNames.UNIT: "cd/ft2", - ColNames.RANGE: [0, 60000 * 0.0929], - }, - }, - ColNames.WIND_DIR: { - ColNames.NAME: "Wind direction", - ColNames.COLOR: ["#0072dd", "#00c420", "#eded00", "#be00d5", "#0072dd"], - UnitSystem.SI: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [0, 360], - }, - UnitSystem.IP: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [0, 360], - }, - }, - ColNames.WIND_SPEED: { - ColNames.NAME: "Wind speed", - ColNames.COLOR: [ - "#D3D3D3", - "#b2f2ff", - "#33ddff", - "#00aaff", - "#0055ff", - "#0000ff", - "#aa00ff", - "#ff00ff", - "#cc0000", - "#ffaa00", - ], - UnitSystem.SI: { - ColNames.UNIT: "m/s", - ColNames.RANGE: [0, 20], - }, - UnitSystem.IP: { - ColNames.UNIT: "fpm", - ColNames.RANGE: [0, 20 * 196.85039370078738], - }, - }, - ColNames.TOT_SKY_COVER: { - ColNames.NAME: "Total sky cover", - ColNames.COLOR: cloud_colors, - UnitSystem.SI: { - ColNames.UNIT: "tenths", - ColNames.RANGE: [0, 10], - }, - UnitSystem.IP: { - ColNames.UNIT: "tenths", - ColNames.RANGE: [0, 10], - }, - }, - ColNames.OSKYCOVER: { - ColNames.NAME: "Opaque sky cover", - ColNames.COLOR: cloud_colors, - UnitSystem.SI: { - ColNames.UNIT: "tenths", - ColNames.RANGE: [0, 10], - }, - UnitSystem.IP: { - ColNames.UNIT: "tenths", - ColNames.RANGE: [0, 10], - }, - }, - ColNames.VIS: { - ColNames.NAME: "Visibility", - ColNames.COLOR: cloud_colors, - UnitSystem.SI: { - ColNames.UNIT: "km", - ColNames.RANGE: [0, 100], - }, - UnitSystem.IP: { - ColNames.UNIT: "miles", - ColNames.RANGE: [0, 100 * 0.6215], - }, - }, - ColNames.APPARENT_ZENITH: { - ColNames.NAME: "Apparent zenith", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [0, 180], - }, - UnitSystem.IP: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [0, 180], - }, - }, - ColNames.ZENITH: { - ColNames.NAME: "Zenith", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [0, 180], - }, - UnitSystem.IP: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [0, 180], - }, - }, - ColNames.APPARENT_ELEVATION: { - ColNames.NAME: "Apparent elevation", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [-90, 90], - }, - UnitSystem.IP: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [-90, 90], - }, - }, - ColNames.ELEVATION: { - ColNames.NAME: "Elevation", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [-90, 90], - }, - UnitSystem.IP: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [-90, 90], - }, - }, - ColNames.AZIMUTH: { - ColNames.NAME: "Azimuth", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [0, 360], - }, - UnitSystem.IP: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [0, 360], - }, - }, - ColNames.EQUATION_OF_TIME: { - ColNames.NAME: "Equation of time", - ColNames.COLOR: [ - "#293a59", - "#960c2c", - "#ff0000", - "#ff7b00", - "#fffc00", - "#ffff7b", - "#ffffff", - ], - UnitSystem.SI: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [-20, 20], - }, - UnitSystem.IP: { - ColNames.UNIT: "°deg", - ColNames.RANGE: [-20, 20], - }, - }, - ColNames.UTCI_SUN_WIND: { - ColNames.NAME: "UTCI: Sun & Wind", - ColNames.COLOR: ["#00b3ff", "#000082", "#ff0000", "#ffff00"], - UnitSystem.SI: { - ColNames.UNIT: "°C", - ColNames.RANGE: [-70, 70], - }, - UnitSystem.IP: { - ColNames.UNIT: "°F", - ColNames.RANGE: [-94, 158], - }, - }, - ColNames.UTCI_NO_SUN_WIND: { - ColNames.NAME: "UTCI: no Sun & Wind", - ColNames.COLOR: ["#00b3ff", "#000082", "#ff0000", "#ffff00"], - UnitSystem.SI: { - ColNames.UNIT: "°C", - ColNames.RANGE: [-70, 70], - }, - UnitSystem.IP: { - ColNames.UNIT: "°F", - ColNames.RANGE: [-94, 158], - }, - }, - ColNames.UTCI_SUN_NO_WIND: { - ColNames.NAME: "UTCI: Sun & no Wind", - ColNames.COLOR: ["#00b3ff", "#000082", "#ff0000", "#ffff00"], - UnitSystem.SI: { - ColNames.UNIT: "°C", - ColNames.RANGE: [-70, 70], - }, - UnitSystem.IP: { - ColNames.UNIT: "°F", - ColNames.RANGE: [-94, 158], - }, - }, - ColNames.UTCI_NO_SUN_NO_WIND: { - ColNames.NAME: "UTCI: no Sun & no Wind", - ColNames.COLOR: ["#00b3ff", "#000082", "#ff0000", "#ffff00"], - UnitSystem.SI: { - ColNames.UNIT: "°C", - ColNames.RANGE: [-70, 70], - }, - UnitSystem.IP: { - ColNames.UNIT: "°F", - ColNames.RANGE: [-94, 158], - }, - }, - ColNames.UTCI_SUN_WIND_CATEGORIES: { - ColNames.NAME: "UTCI: Sun & Wind : categories", - ColNames.COLOR: [ - [0, "#2B2977"], - [0.0555, "#2B2977"], - [0.0555, "#38429B"], - [0.1665, "#38429B"], - [0.1665, "#4253A4"], - [0.2775, "#4253A4"], - [0.2775, "#4B62AD"], - [0.3885, "#4B62AD"], - [0.3885, "#68B8E7"], - [0.4995, "#68B8E7"], - [0.4995, "#53B848"], - [0.6105, "#53B848"], - [0.6105, "#EE8522"], - [0.7215, "#EE8522"], - [0.7215, "#EA2C24"], - [0.8325, "#EA2C24"], - [0.8325, "#B12224"], - [0.9435, "#B12224"], - [0.9435, "#751613"], - [1.0, "#751613"], - ], - UnitSystem.SI: { - ColNames.UNIT: thermal_stress_label, - ColNames.RANGE: [-5, 4], - }, - UnitSystem.IP: { - ColNames.UNIT: thermal_stress_label, - ColNames.RANGE: [-5, 4], - }, - }, - ColNames.UTCI_NOSUN_WIND_CATEGORIES: { - ColNames.NAME: "UTCI: no Sun & Wind : categories", - ColNames.COLOR: [ - [0, "#2B2977"], - [0.0555, "#2B2977"], - [0.0555, "#38429B"], - [0.1665, "#38429B"], - [0.1665, "#4253A4"], - [0.2775, "#4253A4"], - [0.2775, "#4B62AD"], - [0.3885, "#4B62AD"], - [0.3885, "#68B8E7"], - [0.4995, "#68B8E7"], - [0.4995, "#53B848"], - [0.6105, "#53B848"], - [0.6105, "#EE8522"], - [0.7215, "#EE8522"], - [0.7215, "#EA2C24"], - [0.8325, "#EA2C24"], - [0.8325, "#B12224"], - [0.9435, "#B12224"], - [0.9435, "#751613"], - [1.0, "#751613"], - ], - UnitSystem.SI: { - ColNames.UNIT: thermal_stress_label, - ColNames.RANGE: [-5, 4], - }, - UnitSystem.IP: { - ColNames.UNIT: thermal_stress_label, - ColNames.RANGE: [-5, 4], - }, - }, - ColNames.UTCI_SUN_NOWIND_CATEGORIES: { - ColNames.NAME: "UTCI: Sun & no Wind : categories", - ColNames.COLOR: [ - [0, "#2B2977"], - [0.0555, "#2B2977"], - [0.0555, "#38429B"], - [0.1665, "#38429B"], - [0.1665, "#4253A4"], - [0.2775, "#4253A4"], - [0.2775, "#4B62AD"], - [0.3885, "#4B62AD"], - [0.3885, "#68B8E7"], - [0.4995, "#68B8E7"], - [0.4995, "#53B848"], - [0.6105, "#53B848"], - [0.6105, "#EE8522"], - [0.7215, "#EE8522"], - [0.7215, "#EA2C24"], - [0.8325, "#EA2C24"], - [0.8325, "#B12224"], - [0.9435, "#B12224"], - [0.9435, "#751613"], - [1.0, "#751613"], - ], - UnitSystem.SI: { - ColNames.UNIT: thermal_stress_label, - ColNames.RANGE: [-5, 4], - }, - UnitSystem.IP: { - ColNames.UNIT: thermal_stress_label, - ColNames.RANGE: [-5, 4], - }, - }, - ColNames.UTCI_NOSUN_NOWIND_CATEGORIES: { - ColNames.NAME: "UTCI: no Sun & no Wind : categories", - ColNames.COLOR: [ - [0, "#2B2977"], - [0.0555, "#2B2977"], - [0.0555, "#38429B"], - [0.1665, "#38429B"], - [0.1665, "#4253A4"], - [0.2775, "#4253A4"], - [0.2775, "#4B62AD"], - [0.3885, "#4B62AD"], - [0.3885, "#68B8E7"], - [0.4995, "#68B8E7"], - [0.4995, "#53B848"], - [0.6105, "#53B848"], - [0.6105, "#EE8522"], - [0.7215, "#EE8522"], - [0.7215, "#EA2C24"], - [0.8325, "#EA2C24"], - [0.8325, "#B12224"], - [0.9435, "#B12224"], - [0.9435, "#751613"], - [1.0, "#751613"], - ], - UnitSystem.SI: { - ColNames.UNIT: thermal_stress_label, - ColNames.RANGE: [-5, 4], - }, - UnitSystem.IP: { - ColNames.UNIT: thermal_stress_label, - ColNames.RANGE: [-5, 4], - }, - }, - ColNames.P_VAP: { - ColNames.NAME: "Vapor partial pressure", - ColNames.COLOR: ["#ffe600", "#00c8ff", "#0000ff"], - UnitSystem.SI: { - ColNames.UNIT: "Pa", - ColNames.RANGE: [0, 5000], - }, - UnitSystem.IP: { - ColNames.UNIT: "Psi", - ColNames.RANGE: [0, 5000 * 0.000145038], - }, - }, - ColNames.P_SAT: { - ColNames.NAME: "Saturation pressure", - UnitSystem.SI: { - ColNames.UNIT: "Pa", - ColNames.RANGE: [0, 5000], - }, - UnitSystem.IP: { - ColNames.UNIT: "Psi", - ColNames.RANGE: [0, 5000 * 0.000145038], - }, - }, - ColNames.HR: { - ColNames.NAME: "Absolute humidity", - ColNames.COLOR: ["#ffe600", "#00c8ff", "#0000ff"], - UnitSystem.SI: { - ColNames.UNIT: "g water/kg dry air", - ColNames.RANGE: [0, 0.03 * 1000], - }, - UnitSystem.IP: { - ColNames.UNIT: "lb water/klb dry air", - ColNames.RANGE: [0, 0.03 * 1000], - }, - }, - ColNames.T_WB: { - ColNames.NAME: "Wet bulb temperature", - ColNames.COLOR: ["#00b3ff", "#000082", "#ff0000", "#ffff00"], - UnitSystem.SI: { - ColNames.UNIT: "°C", - ColNames.RANGE: [-40, 50], - }, - UnitSystem.IP: { - ColNames.UNIT: "°F", - ColNames.RANGE: [-40, 122], - }, - }, - ColNames.T_DP: { - ColNames.NAME: "Dew point temperature", - ColNames.COLOR: ["#00b3ff", "#000082", "#ff0000", "#ffff00"], - UnitSystem.SI: { - ColNames.UNIT: "°C", - ColNames.RANGE: [-40, 50], - }, - UnitSystem.IP: { - ColNames.UNIT: "°F", - ColNames.RANGE: [-40, 122], - }, - }, - ColNames.EH: { - ColNames.NAME: "Enthalpy", - ColNames.COLOR: ["#00b3ff", "#000082", "#ff0000", "#ffff00"], - UnitSystem.SI: { - ColNames.UNIT: "J/kg dry air", - ColNames.RANGE: [0, 110000], - }, - UnitSystem.IP: { - ColNames.UNIT: "Btu/lb dry air", - ColNames.RANGE: [0, 110000 * 0.000429923], - }, - }, -} - # Dropdown Names variables_sun_cloud_tab_dropdown = [ - ColNames.NONE, - ColNames.T_WB, - ColNames.DPT, - ColNames.DBT, - ColNames.RH, - ColNames.P_VAP, - ColNames.HR, - ColNames.EXTR_HOR_RAD, - ColNames.HOR_IR_RAD, - ColNames.GLOB_HOR_RAD, - ColNames.DIR_NOR_RAD, - ColNames.DIF_HOR_RAD, - ColNames.GLOB_HOR_ILL, - ColNames.DIR_NOR_ILL, - ColNames.DIF_HOR_ILL, - ColNames.ZLUMI, - ColNames.WIND_DIR, - ColNames.WIND_SPEED, - ColNames.TOT_SKY_COVER, - ColNames.OSKYCOVER, - ColNames.VIS, + Variables.NONE.col_name, + Variables.T_WB.col_name, + Variables.DPT.col_name, + Variables.DBT.col_name, + Variables.RH.col_name, + Variables.P_VAP.col_name, + Variables.HR.col_name, + Variables.EXTR_HOR_RAD.col_name, + Variables.HOR_IR_RAD.col_name, + Variables.GLOB_HOR_RAD.col_name, + Variables.DIR_NOR_RAD.col_name, + Variables.DIF_HOR_RAD.col_name, + Variables.GLOB_HOR_ILL.col_name, + Variables.DIR_NOR_ILL.col_name, + Variables.DIF_HOR_ILL.col_name, + Variables.ZLUMI.col_name, + Variables.WIND_DIR.col_name, + Variables.WIND_SPEED.col_name, + Variables.TOT_SKY_COVER.col_name, + Variables.OPAQUE_SKY_COVER.col_name, + Variables.VIS.col_name, ] variables_dropdown = [ - ColNames.T_WB, - ColNames.DPT, - ColNames.DBT, - ColNames.RH, - ColNames.P_VAP, - ColNames.HR, - ColNames.EXTR_HOR_RAD, - ColNames.HOR_IR_RAD, - ColNames.GLOB_HOR_RAD, - ColNames.DIR_NOR_RAD, - ColNames.DIF_HOR_RAD, - ColNames.GLOB_HOR_ILL, - ColNames.DIR_NOR_ILL, - ColNames.DIF_HOR_ILL, - ColNames.ZLUMI, - ColNames.WIND_DIR, - ColNames.WIND_SPEED, - ColNames.TOT_SKY_COVER, - ColNames.OSKYCOVER, - ColNames.VIS, + Variables.T_WB.col_name, + Variables.DPT.col_name, + Variables.DBT.col_name, + Variables.RH.col_name, + Variables.P_VAP.col_name, + Variables.HR.col_name, + Variables.EXTR_HOR_RAD.col_name, + Variables.HOR_IR_RAD.col_name, + Variables.GLOB_HOR_RAD.col_name, + Variables.DIR_NOR_RAD.col_name, + Variables.DIF_HOR_RAD.col_name, + Variables.GLOB_HOR_ILL.col_name, + Variables.DIR_NOR_ILL.col_name, + Variables.DIF_HOR_ILL.col_name, + Variables.ZLUMI.col_name, + Variables.WIND_DIR.col_name, + Variables.WIND_SPEED.col_name, + Variables.TOT_SKY_COVER.col_name, + Variables.OPAQUE_SKY_COVER.col_name, + Variables.VIS.col_name, ] variables_more_variables_dropdown = [ - ColNames.UTCI_SUN_WIND, - ColNames.UTCI_NO_SUN_WIND, - ColNames.UTCI_SUN_NO_WIND, - ColNames.UTCI_NO_SUN_NO_WIND, - ColNames.UTCI_SUN_WIND_CATEGORIES, - ColNames.UTCI_NOSUN_WIND_CATEGORIES, - ColNames.UTCI_SUN_NOWIND_CATEGORIES, - ColNames.UTCI_NOSUN_NOWIND_CATEGORIES, - ColNames.T_DP, - ColNames.ELEVATION, - ColNames.AZIMUTH, - ColNames.P_SAT, + Variables.UTCI_SUN_WIND.col_name, + Variables.UTCI_NO_SUN_WIND.col_name, + Variables.UTCI_SUN_NO_WIND.col_name, + Variables.UTCI_NO_SUN_NO_WIND.col_name, + Variables.UTCI_SUN_WIND_CATEGORIES.col_name, + Variables.UTCI_NOSUN_WIND_CATEGORIES.col_name, + Variables.UTCI_SUN_NOWIND_CATEGORIES.col_name, + Variables.UTCI_NOSUN_NOWIND_CATEGORIES.col_name, + Variables.T_DP.col_name, + Variables.ELEVATION.col_name, + Variables.AZIMUTH.col_name, + Variables.P_SAT.col_name, ] variables_sun_cloud_tab_explore_dropdown = [ - ColNames.EXTR_HOR_RAD, - ColNames.HOR_IR_RAD, - ColNames.GLOB_HOR_RAD, - ColNames.DIR_NOR_RAD, - ColNames.DIF_HOR_RAD, - ColNames.GLOB_HOR_ILL, - ColNames.DIR_NOR_ILL, - ColNames.DIF_HOR_ILL, - ColNames.ZLUMI, - ColNames.OSKYCOVER, + Variables.EXTR_HOR_RAD.col_name, + Variables.HOR_IR_RAD.col_name, + Variables.GLOB_HOR_RAD.col_name, + Variables.DIR_NOR_RAD.col_name, + Variables.DIF_HOR_RAD.col_name, + Variables.GLOB_HOR_ILL.col_name, + Variables.DIR_NOR_ILL.col_name, + Variables.DIF_HOR_ILL.col_name, + Variables.ZLUMI.col_name, + Variables.OPAQUE_SKY_COVER.col_name, ] variables_outdoor_dropdown = [ - ColNames.UTCI_SUN_WIND, - ColNames.UTCI_SUN_NO_WIND, - ColNames.UTCI_NO_SUN_WIND, - ColNames.UTCI_NO_SUN_NO_WIND, + Variables.UTCI_SUN_WIND.col_name, + Variables.UTCI_SUN_NO_WIND.col_name, + Variables.UTCI_NO_SUN_WIND.col_name, + Variables.UTCI_NO_SUN_NO_WIND.col_name, ] sun_cloud_tab_dropdown_names = { - mapping_dictionary[key][ColNames.NAME]: key + VariableInfo.from_col_name(key).get_name(): key for key in variables_sun_cloud_tab_dropdown } dropdown_names = { - mapping_dictionary[key][ColNames.NAME]: key for key in variables_dropdown + VariableInfo.from_col_name(key).get_name(): key for key in variables_dropdown } more_variables_dropdown = { - mapping_dictionary[key][ColNames.NAME]: key + VariableInfo.from_col_name(key).get_name(): key for key in variables_more_variables_dropdown } sun_cloud_tab_explore_dropdown_names = { - mapping_dictionary[key][ColNames.NAME]: key + VariableInfo.from_col_name(key).get_name(): key for key in variables_sun_cloud_tab_explore_dropdown } outdoor_dropdown_names = { - mapping_dictionary[key][ColNames.NAME]: key for key in variables_outdoor_dropdown + VariableInfo.from_col_name(key).get_name(): key + for key in variables_outdoor_dropdown } diff --git a/pages/lib/global_variables.py b/pages/lib/global_variables.py new file mode 100644 index 0000000..baf12b8 --- /dev/null +++ b/pages/lib/global_variables.py @@ -0,0 +1,663 @@ +from dataclasses import dataclass +from typing import Optional, List, Any +from config import UnitSystem + + +@dataclass +class IP: + """Metadata for the Imperial Units (IP)""" + + unit: str + range: List[float] + + +@dataclass +class VariableInfo: + """Column metadata: default unit/range/color represent the common display; + if SI or IP is provided, they will override the default values as needed.""" + + col_name: str + name: Optional[str] = None + unit: Optional[str] = None + range: Optional[List[float]] = None + color: Optional[List[Any]] = None + IP: Optional[IP] = None + + def get_name(self) -> Optional[str]: + """Returns the display name of the variable.""" + return self.name + + def get_unit(self, system: str) -> Optional[str]: + """Returns the unit of the variable based on the specified unit system.""" + if system == UnitSystem.IP and self.IP: + return self.IP.unit + return self.unit + + def get_range(self, system: str) -> Optional[List[float]]: + """Returns the valid value range of the variable based on the specified unit system.""" + if system == UnitSystem.IP and self.IP: + return self.IP.range + return self.range + + def get_color(self) -> Optional[List[Any]]: + """Returns the color settings of the variable, if available.""" + return self.color + + @classmethod + def from_col_name(cls, col_name: str) -> "VariableInfo": + """Returns the VariableInfo object by matching the column name.""" + for attr_name in dir(Variables): + variable = getattr(Variables, attr_name) + if isinstance(variable, cls) and variable.col_name == col_name: + return variable + raise KeyError(f"No VariableInfo found for col_name='{col_name}'") + + +class Variables: + # ==================== Basic Variables ==================== + NONE = VariableInfo(col_name="None", name="None", unit="", range=[]) + + # ==================== Time Related Variables ==================== + DOY = VariableInfo( + col_name="DOY", name="Day of the year", unit="days", range=[0, 365] + ) + DAY = VariableInfo(col_name="day", name="day", unit="", range=[1, 31]) + YEAR = VariableInfo(col_name="year") + PERIOD = VariableInfo(col_name="period") + MINUTE = VariableInfo(col_name="minute") + FAKE_YEAR = VariableInfo(col_name="fake_year") + MONTH_NAMES = VariableInfo(col_name="month_names") + UTC_TIME = VariableInfo(col_name="UTC_time") + MONTH = VariableInfo(col_name="month", name="months", unit="months", range=[1, 12]) + HOUR = VariableInfo( + col_name="hour", + name="Hour", + unit="h", + range=[1, 24], + color=[ + "#000000", + "#355e7e", + "#6b5c7b", + "#c06c84", + "#f8b195", + "#c92a42", + "#c92a42", + "#c92a42", + "#000000", + ], + ) + + # ==================== Location Related Variables ==================== + LAT = VariableInfo(col_name="lat") # Latitude + LON = VariableInfo(col_name="lon") # Longitude + CITY = VariableInfo(col_name="city") + COUNTRY = VariableInfo(col_name="country") + TIME_ZONE = VariableInfo(col_name="time_zone") + SITE_ELEVATION = VariableInfo(col_name="site_elevation") + + # ==================== Basic Meteorological Data ==================== + DBT = VariableInfo( + col_name="DBT", + name="Dry bulb temperature", + unit="°C", + range=[-40, 50], + color=["#00b3ff", "#000082", "#ff0000", "#ffff00"], + IP=IP(unit="°F", range=[-40, 122]), + ) + DPT = VariableInfo( + col_name="DPT", + name="Dew point temperature", + unit="°C", + range=[-50, 35], + color=["#00b3ff", "#000082", "#ff0000", "#ffff00"], + IP=IP(unit="°F", range=[-58, 95]), + ) + RH = VariableInfo( + col_name="RH", + name="Relative humidity", + unit="%", + range=[0, 100], + color=["#ffe600", "#00c8ff", "#0000ff"], + ) + + P_ATM = VariableInfo( + col_name="p_atm", + name="Atmospheric pressure", + unit="Pa", + range=[95000, 105000], + color=[ + "#ffffff", + "#b2f2ff", + "#33ddff", + "#00aaff", + "#0055ff", + "#0000ff", + "#aa00ff", + "#ff00ff", + "#cc0000", + "#ffaa00", + ], + IP=IP(unit="Psi", range=[95000 * 0.000145038, 105000 * 0.000145038]), + ) + + # ==================== Radiation Related Variables ==================== + EXTR_HOR_RAD = VariableInfo( + col_name="extr_hor_rad", + name="Extraterrestrial horizontal irradiation", + unit="Wh/m2", + range=[0, 1200], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + IP=IP(unit="Btu/ft2", range=[0, 1200 * 0.3169983306]), + ) + HOR_IR_RAD = VariableInfo( + col_name="hor_ir_rad", + name="Horizontal infrared radiation", + unit="Wh/m2", + range=[0, 500], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + IP=IP(unit="Btu/ft2", range=[0, 500 * 0.3169983306]), + ) + GLOB_HOR_RAD = VariableInfo( + col_name="glob_hor_rad", + name="Global horizontal radiation", + unit="Wh/m2", + range=[0, 1200], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + IP=IP(unit="Btu/ft2", range=[0, 1200 * 0.3169983306]), + ) + DIR_NOR_RAD = VariableInfo( + col_name="dir_nor_rad", + name="Direct normal radiation", + unit="Wh/m2", + range=[0, 1200], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + IP=IP(unit="Btu/ft2", range=[0, 1200 * 0.3169983306]), + ) + DIF_HOR_RAD = VariableInfo( + col_name="dif_hor_rad", + name="Diffuse horizontal radiation", + unit="Wh/m2", + range=[0, 1200], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + IP=IP(unit="Btu/ft2", range=[0, 1200 * 0.3169983306]), + ) + + # ==================== Lighting Related Variables ==================== + GLOB_HOR_ILL = VariableInfo( + col_name="glob_hor_ill", + name="Global horizontal illuminance", + unit="lux", + range=[0, 120000], + color=["#4d6daa", "#a0beed", "#f1e969", "#eb7d05", "#d81600"], + IP=IP(unit="fc", range=[0, 120000 * 0.0929]), + ) + DIR_NOR_ILL = VariableInfo( + col_name="dir_nor_ill", + name="Direct normal illuminance", + unit="lux", + range=[0, 120000], + color=["#4d6daa", "#a0beed", "#f1e969", "#eb7d05", "#d81600"], + IP=IP(unit="fc", range=[0, 120000 * 0.0929]), + ) + DIF_HOR_ILL = VariableInfo( + col_name="dif_hor_ill", + name="Diffuse horizontal illuminance", + unit="lux", + range=[0, 120000], + color=["#4d6daa", "#a0beed", "#f1e969", "#eb7d05", "#d81600"], + IP=IP(unit="fc", range=[0, 120000 * 0.0929]), + ) + + ZLUMI = VariableInfo( + col_name="Zlumi", + name="Zenith luminance", + unit="cd/m2", + range=[0, 60000], + color=["#730a8c", "#0d0db3", "#0f85be", "#0f85be", "#b11421", "#fdf130"], + IP=IP(unit="cd/ft2", range=[0, 60000 * 0.0929]), + ) + + # ==================== Wind Related Variables ==================== + WIND_DIR = VariableInfo( + col_name="wind_dir", + name="Wind direction", + unit="°deg", + range=[0, 360], + color=["#0072dd", "#00c420", "#eded00", "#be00d5", "#0072dd"], + ) + WIND_SPEED = VariableInfo( + col_name="wind_speed", + name="Wind speed", + unit="m/s", + range=[0, 20], + color=[ + "#D3D3D3", + "#b2f2ff", + "#33ddff", + "#00aaff", + "#0055ff", + "#0000ff", + "#aa00ff", + "#ff00ff", + "#cc0000", + "#ffaa00", + ], + IP=IP(unit="fpm", range=[0, 20 * 196.85039370078738]), + ) + + TOT_SKY_COVER = VariableInfo( + col_name="tot_sky_cover", + name="Total sky cover", + unit="tenths", + range=[0, 10], + color=[ + "#7ec9f3", + "#e6eae9", + "#c2c2c2", + ], + ) + OPAQUE_SKY_COVER = VariableInfo( + col_name="Oskycover", + name="Opaque sky cover", + unit="tenths", + range=[0, 10], + color=[ + "#7ec9f3", + "#e6eae9", + "#c2c2c2", + ], + ) + VIS = VariableInfo( + col_name="Vis", + name="Visibility", + unit="km", + range=[0, 100], + color=[ + "#7ec9f3", + "#e6eae9", + "#c2c2c2", + ], + IP=IP(unit="miles", range=[0, 100 * 0.6215]), + ) + + # ==================== Solar Position Related Variables ==================== + APPARENT_ZENITH = VariableInfo( + col_name="apparent_zenith", + name="Apparent zenith", + unit="°deg", + range=[0, 180], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + ) + ZENITH = VariableInfo( + col_name="zenith", + name="Zenith", + unit="°deg", + range=[0, 180], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + ) + APPARENT_ELEVATION = VariableInfo( + col_name="apparent_elevation", + name="Apparent elevation", + unit="°deg", + range=[-90, 90], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + ) + ELEVATION = VariableInfo( + col_name="elevation", + name="Elevation", + unit="°deg", + range=[-90, 90], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + ) + AZIMUTH = VariableInfo( + col_name="azimuth", + name="Azimuth", + unit="°deg", + range=[0, 360], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + ) + EQUATION_OF_TIME = VariableInfo( + col_name="equation_of_time", + name="Equation of time", + unit="°deg", + range=[-20, 20], + color=[ + "#293a59", + "#960c2c", + "#ff0000", + "#ff7b00", + "#fffc00", + "#ffff7b", + "#ffffff", + ], + ) + + # ==================== UTCI Comfort Related Variables ==================== + UTCI_SUN_WIND = VariableInfo( + col_name="utci_Sun_Wind", + name="UTCI: Sun & Wind", + unit="°C", + range=[-70, 70], + color=["#00b3ff", "#000082", "#ff0000", "#ffff00"], + IP=IP(unit="°F", range=[-94, 158]), + ) + UTCI_NO_SUN_WIND = VariableInfo( + col_name="utci_noSun_Wind", + name="UTCI: no Sun & Wind", + unit="°C", + range=[-70, 70], + color=["#00b3ff", "#000082", "#ff0000", "#ffff00"], + IP=IP(unit="°F", range=[-94, 158]), + ) + UTCI_SUN_NO_WIND = VariableInfo( + col_name="utci_Sun_noWind", + name="UTCI: Sun & no Wind", + unit="°C", + range=[-70, 70], + color=["#00b3ff", "#000082", "#ff0000", "#ffff00"], + IP=IP(unit="°F", range=[-94, 158]), + ) + UTCI_NO_SUN_NO_WIND = VariableInfo( + col_name="utci_noSun_noWind", + name="UTCI: no Sun & no Wind", + unit="°C", + range=[-70, 70], + color=["#00b3ff", "#000082", "#ff0000", "#ffff00"], + IP=IP(unit="°F", range=[-94, 158]), + ) + + UTCI_SUN_WIND_CATEGORIES = VariableInfo( + col_name="utci_Sun_Wind_categories", + name="UTCI: Sun & Wind : categories", + unit="Thermal stress", + range=[-5, 4], + color=[ + [0, "#2B2977"], + [0.0555, "#2B2977"], + [0.0555, "#38429B"], + [0.1665, "#38429B"], + [0.1665, "#4253A4"], + [0.2775, "#4253A4"], + [0.2775, "#4B62AD"], + [0.3885, "#4B62AD"], + [0.3885, "#68B8E7"], + [0.4995, "#68B8E7"], + [0.4995, "#53B848"], + [0.6105, "#53B848"], + [0.6105, "#EE8522"], + [0.7215, "#EE8522"], + [0.7215, "#EA2C24"], + [0.8325, "#EA2C24"], + [0.8325, "#B12224"], + [0.9435, "#B12224"], + [0.9435, "#751613"], + [1.0, "#751613"], + ], + ) + UTCI_NOSUN_WIND_CATEGORIES = VariableInfo( + col_name="utci_noSun_Wind_categories", + name="UTCI: no Sun & Wind : categories", + unit="Thermal stress", + range=[-5, 4], + color=[ + [0, "#2B2977"], + [0.0555, "#2B2977"], + [0.0555, "#38429B"], + [0.1665, "#38429B"], + [0.1665, "#4253A4"], + [0.2775, "#4253A4"], + [0.2775, "#4B62AD"], + [0.3885, "#4B62AD"], + [0.3885, "#68B8E7"], + [0.4995, "#68B8E7"], + [0.4995, "#53B848"], + [0.6105, "#53B848"], + [0.6105, "#EE8522"], + [0.7215, "#EE8522"], + [0.7215, "#EA2C24"], + [0.8325, "#EA2C24"], + [0.8325, "#B12224"], + [0.9435, "#B12224"], + [0.9435, "#751613"], + [1.0, "#751613"], + ], + ) + UTCI_SUN_NOWIND_CATEGORIES = VariableInfo( + col_name="utci_Sun_noWind_categories", + name="UTCI: Sun & no Wind : categories", + unit="Thermal stress", + range=[-5, 4], + color=[ + [0, "#2B2977"], + [0.0555, "#2B2977"], + [0.0555, "#38429B"], + [0.1665, "#38429B"], + [0.1665, "#4253A4"], + [0.2775, "#4253A4"], + [0.2775, "#4B62AD"], + [0.3885, "#4B62AD"], + [0.3885, "#68B8E7"], + [0.4995, "#68B8E7"], + [0.4995, "#53B848"], + [0.6105, "#53B848"], + [0.6105, "#EE8522"], + [0.7215, "#EE8522"], + [0.7215, "#EA2C24"], + [0.8325, "#EA2C24"], + [0.8325, "#B12224"], + [0.9435, "#B12224"], + [0.9435, "#751613"], + [1.0, "#751613"], + ], + ) + UTCI_NOSUN_NOWIND_CATEGORIES = VariableInfo( + col_name="utci_noSun_noWind_categories", + name="UTCI: no Sun & no Wind : categories", + unit="Thermal stress", + range=[-5, 4], + color=[ + [0, "#2B2977"], + [0.0555, "#2B2977"], + [0.0555, "#38429B"], + [0.1665, "#38429B"], + [0.1665, "#4253A4"], + [0.2775, "#4253A4"], + [0.2775, "#4B62AD"], + [0.3885, "#4B62AD"], + [0.3885, "#68B8E7"], + [0.4995, "#68B8E7"], + [0.4995, "#53B848"], + [0.6105, "#53B848"], + [0.6105, "#EE8522"], + [0.7215, "#EE8522"], + [0.7215, "#EA2C24"], + [0.8325, "#EA2C24"], + [0.8325, "#B12224"], + [0.9435, "#B12224"], + [0.9435, "#751613"], + [1.0, "#751613"], + ], + ) + + # ==================== Additional Meteorological Data ==================== + P_VAP = VariableInfo( + col_name="p_vap", + name="Vapor partial pressure", + unit="Pa", + range=[0, 5000], + color=["#ffe600", "#00c8ff", "#0000ff"], + IP=IP(unit="Psi", range=[0, 5000 * 0.000145038]), + ) + P_SAT = VariableInfo( + col_name="p_sat", + name="Saturation pressure", + unit="Pa", + range=[0, 5000], + IP=IP(unit="Psi", range=[0, 5000 * 0.000145038]), + ) + HR = VariableInfo( + col_name="hr", + name="Absolute humidity", + unit="g water/kg dry air", + range=[0, 0.03 * 1000], + color=["#ffe600", "#00c8ff", "#0000ff"], + IP=IP(unit="lb water/klb dry air", range=[0, 0.03 * 1000]), + ) + T_WB = VariableInfo( + col_name="t_wb", + name="Wet bulb temperature", + unit="°C", + range=[-40, 50], + color=["#00b3ff", "#000082", "#ff0000", "#ffff00"], + IP=IP(unit="°F", range=[-40, 122]), + ) + T_DP = VariableInfo( + col_name="t_dp", + name="Dew point temperature", + unit="°C", + range=[-40, 50], + color=["#00b3ff", "#000082", "#ff0000", "#ffff00"], + IP=IP(unit="°F", range=[-40, 122]), + ) + EH = VariableInfo( + col_name="h", + name="Enthalpy", + unit="J/kg dry air", + range=[0, 110000], + color=["#00b3ff", "#000082", "#ff0000", "#ffff00"], + IP=IP(unit="Btu/lb dry air", range=[0, 110000 * 0.000429923]), + ) + + # ==================== Additional Humidity Data ==================== + HI_RH = VariableInfo(col_name="hiRH") + LO_RH = VariableInfo(col_name="loRH") + + # ==================== Additional Wind Data ==================== + WIND_SPEED_UTCI = VariableInfo(col_name="wind_speed_utci") + WIND_SPEED_UTCI_0 = VariableInfo(col_name="wind_speed_utci_0") + + # ==================== Additional Weather Data ==================== + CLOUD_HEIGHT = VariableInfo(col_name="Cheight") + PRECIPITATION_OBSERVATION = VariableInfo( + col_name="PWobs" + ) # Precipitation Observation + PRECIPITATION_CODES = VariableInfo(col_name="PWcodes") # Precipitation Codes + PRECIPITATION_WATER = VariableInfo(col_name="Pwater") # Precipitation Water + AEROSOL_OPTICAL_DEPTH = VariableInfo(col_name="AsolOptD") # Aerosol Optical Depth + SNOW_DEPTH = VariableInfo(col_name="SnowD") # Snow Depth + DAILY_SNOW = VariableInfo(col_name="DaySSnow") # Daily Snow + MRT = VariableInfo(col_name="MRT") + DELTA_MRT = VariableInfo(col_name="delta_mrt") + + # ==================== Adaptive Comfort Variables ==================== + ADAPTIVE_COMFORT = VariableInfo(col_name="adaptive_comfort") + ADAPTIVE_CMF_80_LOW = VariableInfo(col_name="adaptive_cmf_80_low") + ADAPTIVE_CMF_80_UP = VariableInfo(col_name="adaptive_cmf_80_up") + ADAPTIVE_CMF_90_LOW = VariableInfo(col_name="adaptive_cmf_90_low") + ADAPTIVE_CMF_90_UP = VariableInfo(col_name="adaptive_cmf_90_up") + ADAPTIVE_CMF_RMT = VariableInfo(col_name="adaptive_cmf_rmt") + NV_ALLOWED = VariableInfo(col_name="nv_allowed") + TMP_CMF = VariableInfo(col_name="tmp_cmf") + TMP_CMF_80_LOW = VariableInfo(col_name="tmp_cmf_80_low") + TMP_CMF_80_UP = VariableInfo(col_name="tmp_cmf_80_up") + TMP_CMF_90_LOW = VariableInfo(col_name="tmp_cmf_90_low") + TMP_CMF_90_UP = VariableInfo(col_name="tmp_cmf_90_up") + CONVERSION_FUNCTION = VariableInfo(col_name="conversion_function") + + # ==================== UI and Display Variables ==================== + COLOR = VariableInfo(col_name="color") + NAME = VariableInfo(col_name="name") + RANGE = VariableInfo(col_name="range") + UNIT = VariableInfo(col_name="unit") + TWENTY_FOUR_HOUR = VariableInfo(col_name="24h") + FIVE_MINUTE = VariableInfo(col_name="5min") + TIMES = VariableInfo(col_name="times") + PATH = VariableInfo(col_name="path") + FILE_NAME = VariableInfo(col_name="filename") + WIND_DIR_BINS = VariableInfo(col_name="WindDir_bins") + WIND_SPD_BINS = VariableInfo(col_name="WindSpd_bins") + TO_IMAGE_BUTTON_OPTIONS = VariableInfo(col_name="toImageButtonOptions") + INVERT = VariableInfo(col_name="invert") + FEATURES = VariableInfo(col_name="features") + GEOMETRY_COORDINATES = VariableInfo(col_name="geometry.coordinates") + PROP_ID = VariableInfo(col_name="prop_id") diff --git a/pages/lib/layout.py b/pages/lib/layout.py index 71b1119..90c0f49 100644 --- a/pages/lib/layout.py +++ b/pages/lib/layout.py @@ -2,7 +2,7 @@ from dash import dcc, Input, Output, State, callback import dash_mantine_components as dmc from dash_iconify import DashIconify -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables from config import DocLinks, UnitSystem from pages.lib.global_element_ids import ElementIds @@ -59,17 +59,17 @@ def create_navbar(): # Secondary Menu sub_links = [ dmc.NavLink( - label=page[ColNames.NAME], + label=page[Variables.NAME.col_name], leftSection=DashIconify( - icon=NavBarIcons.get_icon(page[ColNames.NAME]), width=20 + icon=NavBarIcons.get_icon(page[Variables.NAME.col_name]), width=20 ), - href=page[ColNames.PATH], - id=f"nav-{page[ColNames.PATH].replace('/', '')}", + href=page[Variables.PATH.col_name], + id=f"nav-{page[Variables.PATH.col_name].replace('/', '')}", active=False, styles=nav_link_styles, ) for page in dash.page_registry.values() - if page[ColNames.NAME] not in ["404"] + if page[Variables.NAME.col_name] not in ["404"] ] parent_group = dmc.NavLink( @@ -404,18 +404,18 @@ def toggle_navbar_and_width( @callback( [ - Output(f"nav-{page[ColNames.PATH].replace('/', '')}", "active") + Output(f"nav-{page[Variables.PATH.col_name].replace('/', '')}", "active") for page in dash.page_registry.values() - if page[ColNames.NAME] not in ["404"] + if page[Variables.NAME.col_name] not in ["404"] ], Input(ElementIds.MAIN_URL, "pathname"), prevent_initial_call=True, ) def update_nav_active_state(pathname): return [ - pathname == page[ColNames.PATH] + pathname == page[Variables.PATH.col_name] for page in dash.page_registry.values() - if page[ColNames.NAME] not in ["404"] + if page[Variables.NAME.col_name] not in ["404"] ] diff --git a/pages/lib/template_graphs.py b/pages/lib/template_graphs.py index 4916381..0d3bae3 100644 --- a/pages/lib/template_graphs.py +++ b/pages/lib/template_graphs.py @@ -5,20 +5,20 @@ from config import UnitSystem from pages.lib.utils import get_max_min_value -from pages.lib.global_scheme import mapping_dictionary import dash_bootstrap_components as dbc from .global_scheme import month_lst, template, tight_margins -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables, VariableInfo from .utils import code_timer, determine_month_and_hour_filter def violin(df, var, global_local, si_ip): """Return day night violin based on the 'var' col""" - mask_day = (df[ColNames.HOUR] >= 8) & (df[ColNames.HOUR] < 20) - mask_night = (df[ColNames.HOUR] < 8) | (df[ColNames.HOUR] >= 20) - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] - var_name = mapping_dictionary[var][ColNames.NAME] + mask_day = (df[Variables.HOUR.col_name] >= 8) & (df[Variables.HOUR.col_name] < 20) + mask_night = (df[Variables.HOUR.col_name] < 8) | (df[Variables.HOUR.col_name] >= 20) + variable = VariableInfo.from_col_name(var) + var_unit = variable.get_unit(si_ip) + var_range = variable.get_range(si_ip) + var_name = variable.get_name() data_day = df.loc[mask_day, var] data_night = df.loc[mask_night, var] @@ -30,7 +30,7 @@ def violin(df, var, global_local, si_ip): fig = go.Figure() fig.add_trace( go.Violin( - x=df[ColNames.FAKE_YEAR], + x=df[Variables.FAKE_YEAR.col_name], y=data_day, line_color="#ffaa00", name="Day", @@ -42,7 +42,7 @@ def violin(df, var, global_local, si_ip): fig.add_trace( go.Violin( - x=df[ColNames.FAKE_YEAR], + x=df[Variables.FAKE_YEAR.col_name], y=data_night, line_color="#00264d", name="Night", @@ -84,10 +84,11 @@ def violin(df, var, global_local, si_ip): @code_timer def yearly_profile(df, var, global_local, si_ip): """Return yearly profile figure based on the 'var' col.""" - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] - var_name = mapping_dictionary[var][ColNames.NAME] - var_color = mapping_dictionary[var][ColNames.COLOR] + variable = VariableInfo.from_col_name(var) + var_unit = variable.get_unit(si_ip) + var_range = variable.get_range(si_ip) + var_name = variable.get_name() + var_color = variable.get_color() if global_local == "global": # Set Global values for Max and minimum @@ -105,7 +106,7 @@ def yearly_profile(df, var, global_local, si_ip): ) trace1 = go.Bar( - x=df[ColNames.UTC_TIME].dt.date.unique(), + x=df[Variables.UTC_TIME.col_name].dt.date.unique(), y=dbt_day["max"] - dbt_day["min"], base=dbt_day["min"], marker_color=var_single_color, @@ -114,8 +115,8 @@ def yearly_profile(df, var, global_local, si_ip): customdata=np.stack( ( dbt_day["mean"], - df.iloc[::24, :][ColNames.MONTH_NAMES], - df.iloc[::24, :][ColNames.DAY], + df.iloc[::24, :][Variables.MONTH_NAMES.col_name], + df.iloc[::24, :][Variables.DAY.col_name], ), axis=-1, ), @@ -131,7 +132,7 @@ def yearly_profile(df, var, global_local, si_ip): ) trace2 = go.Scatter( - x=df[ColNames.UTC_TIME].dt.date.unique(), + x=df[Variables.UTC_TIME.col_name].dt.date.unique(), y=dbt_day["mean"], name="Average " + var_name, mode="lines", @@ -140,8 +141,8 @@ def yearly_profile(df, var, global_local, si_ip): customdata=np.stack( ( dbt_day["mean"], - df.iloc[::24, :][ColNames.MONTH_NAMES], - df.iloc[::24, :][ColNames.DAY], + df.iloc[::24, :][Variables.MONTH_NAMES.col_name], + df.iloc[::24, :][Variables.DAY.col_name], ), axis=-1, ), @@ -152,16 +153,28 @@ def yearly_profile(df, var, global_local, si_ip): ), ) - if var == ColNames.DBT: + if var == Variables.DBT.col_name: # plot ashrae adaptive comfort limits (80%) - lo80 = df.groupby(ColNames.DOY)[ColNames.ADAPTIVE_CMF_80_LOW].mean().values - hi80 = df.groupby(ColNames.DOY)[ColNames.ADAPTIVE_CMF_80_UP].mean().values - rmt = df.groupby(ColNames.DOY)[ColNames.ADAPTIVE_CMF_RMT].mean().values + lo80 = ( + df.groupby(Variables.DOY.col_name)[Variables.ADAPTIVE_CMF_80_LOW.col_name] + .mean() + .values + ) + hi80 = ( + df.groupby(Variables.DOY.col_name)[Variables.ADAPTIVE_CMF_80_UP.col_name] + .mean() + .values + ) + rmt = ( + df.groupby(Variables.DOY.col_name)[Variables.ADAPTIVE_CMF_RMT.col_name] + .mean() + .values + ) # set color https://github.com/CenterForTheBuiltEnvironment/clima/issues/113 implementation var_bar_colors = np.where((rmt > 40) | (rmt < 10), "lightgray", "darkgray") trace3 = go.Bar( - x=df[ColNames.UTC_TIME].dt.date.unique(), + x=df[Variables.UTC_TIME.col_name].dt.date.unique(), y=hi80 - lo80, base=lo80, name="ASHRAE adaptive comfort (80%)", @@ -173,11 +186,19 @@ def yearly_profile(df, var, global_local, si_ip): ) # plot ashrae adaptive comfort limits (90%) - lo90 = df.groupby(ColNames.DOY)[ColNames.ADAPTIVE_CMF_90_LOW].mean().values - hi90 = df.groupby(ColNames.DOY)[ColNames.ADAPTIVE_CMF_90_UP].mean().values + lo90 = ( + df.groupby(Variables.DOY.col_name)[Variables.ADAPTIVE_CMF_90_LOW.col_name] + .mean() + .values + ) + hi90 = ( + df.groupby(Variables.DOY.col_name)[Variables.ADAPTIVE_CMF_90_UP.col_name] + .mean() + .values + ) trace4 = go.Bar( - x=df[ColNames.UTC_TIME].dt.date.unique(), + x=df[Variables.UTC_TIME.col_name].dt.date.unique(), y=hi90 - lo90, base=lo90, name="ASHRAE adaptive comfort (90%)", @@ -189,17 +210,17 @@ def yearly_profile(df, var, global_local, si_ip): ) data = [trace3, trace4, trace1, trace2] - elif var == ColNames.RH: + elif var == Variables.RH.col_name: # plot relative Humidity limits (30-70%) lo_rh = [30] * 365 hi_rh = [70] * 365 - lo_rh_df = pd.DataFrame({ColNames.LO_RH: lo_rh}) - hi_rh_df = pd.DataFrame({ColNames.HI_RH: hi_rh}) + lo_rh_df = pd.DataFrame({Variables.LO_RH.col_name: lo_rh}) + hi_rh_df = pd.DataFrame({Variables.HI_RH.col_name: hi_rh}) trace3 = go.Bar( - x=df[ColNames.UTC_TIME].dt.date.unique(), - y=hi_rh_df[ColNames.HI_RH] - lo_rh_df[ColNames.LO_RH], - base=lo_rh_df[ColNames.LO_RH], + x=df[Variables.UTC_TIME.col_name].dt.date.unique(), + y=hi_rh_df[Variables.HI_RH.col_name] - lo_rh_df[Variables.LO_RH.col_name], + base=lo_rh_df[Variables.LO_RH.col_name], name="humidity comfort band", marker_opacity=0.3, marker_color="silver", @@ -244,10 +265,11 @@ def yearly_profile(df, var, global_local, si_ip): # @code_timer def daily_profile(df, var, global_local, si_ip): """Return the daily profile based on the 'var' col.""" - var_name = mapping_dictionary[var][ColNames.NAME] - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] - var_color = mapping_dictionary[var][ColNames.COLOR] + variable = VariableInfo.from_col_name(var) + var_name = variable.get_name() + var_unit = variable.get_unit(si_ip) + var_range = variable.get_range(si_ip) + var_color = variable.get_color() if global_local == "global": # Set Global values for Max and minimum range_y = var_range @@ -258,7 +280,9 @@ def daily_profile(df, var, global_local, si_ip): var_single_color = var_color[len(var_color) // 2] var_month_ave = ( - df.groupby([ColNames.MONTH, ColNames.HOUR])[var].median().reset_index() + df.groupby([Variables.MONTH.col_name, Variables.HOUR.col_name])[var] + .median() + .reset_index() ) fig = make_subplots( rows=1, @@ -270,15 +294,20 @@ def daily_profile(df, var, global_local, si_ip): for i in range(12): fig.add_trace( go.Scatter( - x=df.loc[df[ColNames.MONTH] == i + 1, ColNames.HOUR], - y=df.loc[df[ColNames.MONTH] == i + 1, var], + x=df.loc[ + df[Variables.MONTH.col_name] == i + 1, Variables.HOUR.col_name + ], + y=df.loc[df[Variables.MONTH.col_name] == i + 1, var], mode="markers", marker_color=var_single_color, opacity=0.5, marker_size=3, name=month_lst[i], showlegend=False, - customdata=df.loc[df[ColNames.MONTH] == i + 1, ColNames.MONTH_NAMES], + customdata=df.loc[ + df[Variables.MONTH.col_name] == i + 1, + Variables.MONTH_NAMES.col_name, + ], hovertemplate=( "" + var @@ -294,9 +323,12 @@ def daily_profile(df, var, global_local, si_ip): fig.add_trace( go.Scatter( x=var_month_ave.loc[ - var_month_ave[ColNames.MONTH] == i + 1, ColNames.HOUR + var_month_ave[Variables.MONTH.col_name] == i + 1, + Variables.HOUR.col_name, + ], + y=var_month_ave.loc[ + var_month_ave[Variables.MONTH.col_name] == i + 1, var ], - y=var_month_ave.loc[var_month_ave[ColNames.MONTH] == i + 1, var], mode="lines", line_color=var_single_color, line_width=3, @@ -340,9 +372,10 @@ def heatmap_with_filter( title, ): """General function that returns a heatmap.""" - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] - var_color = mapping_dictionary[var][ColNames.COLOR] + variable = VariableInfo.from_col_name(var) + var_unit = variable.get_unit(si_ip) + var_range = variable.get_range(si_ip) + var_color = variable.get_color() df = filter_df_by_month_and_hour( df, time_filter, month, hour, invert_month, invert_hour, var @@ -352,7 +385,7 @@ def heatmap_with_filter( month, hour, invert_month, invert_hour ) - if df.dropna(subset=[ColNames.MONTH]).shape[0] == 0: + if df.dropna(subset=[Variables.MONTH.col_name]).shape[0] == 0: return ( dbc.Alert( "No data is available in this location under these conditions. Please " @@ -372,13 +405,17 @@ def heatmap_with_filter( range_z = [data_min, data_max] fig = go.Figure( data=go.Heatmap( - y=df[ColNames.HOUR] - 0.5, # Offset by 0.5 to center the hour labels - x=df[ColNames.UTC_TIME].dt.date, + y=df[Variables.HOUR.col_name] + - 0.5, # Offset by 0.5 to center the hour labels + x=df[Variables.UTC_TIME.col_name].dt.date, z=df[var], colorscale=var_color, zmin=range_z[0], zmax=range_z[1], - customdata=np.stack((df[ColNames.MONTH_NAMES], df[ColNames.DAY]), axis=-1), + customdata=np.stack( + (df[Variables.MONTH_NAMES.col_name], df[Variables.DAY.col_name]), + axis=-1, + ), hovertemplate=( "" + var @@ -417,9 +454,10 @@ def heatmap_with_filter( def heatmap(df, var, global_local, si_ip): """General function that returns a heatmap.""" - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] - var_color = mapping_dictionary[var][ColNames.COLOR] + variable = VariableInfo.from_col_name(var) + var_unit = variable.get_unit(si_ip) + var_range = variable.get_range(si_ip) + var_color = variable.get_color() if global_local == "global": # Set Global values for Max and minimum @@ -430,13 +468,16 @@ def heatmap(df, var, global_local, si_ip): range_z = [data_min, data_max] fig = go.Figure( data=go.Heatmap( - y=df[ColNames.HOUR], - x=df[ColNames.UTC_TIME].dt.date, + y=df[Variables.HOUR.col_name], + x=df[Variables.UTC_TIME.col_name].dt.date, z=df[var], colorscale=var_color, zmin=range_z[0], zmax=range_z[1], - customdata=np.stack((df[ColNames.MONTH_NAMES], df[ColNames.DAY]), axis=-1), + customdata=np.stack( + (df[Variables.MONTH_NAMES.col_name], df[Variables.DAY.col_name]), + axis=-1, + ), hovertemplate=( "" + var @@ -486,19 +527,29 @@ def wind_rose(df, title, month, hour, labels, si_ip): end_hour = hour[1] if start_month <= end_month: df = df.loc[ - (df[ColNames.MONTH] >= start_month) & (df[ColNames.MONTH] <= end_month) + (df[Variables.MONTH.col_name] >= start_month) + & (df[Variables.MONTH.col_name] <= end_month) ] else: df = df.loc[ - (df[ColNames.MONTH] <= end_month) | (df[ColNames.MONTH] >= start_month) + (df[Variables.MONTH.col_name] <= end_month) + | (df[Variables.MONTH.col_name] >= start_month) ] if start_hour <= end_hour: - df = df.loc[(df[ColNames.HOUR] > start_hour) & (df[ColNames.HOUR] <= end_hour)] + df = df.loc[ + (df[Variables.HOUR.col_name] > start_hour) + & (df[Variables.HOUR.col_name] <= end_hour) + ] else: - df = df.loc[(df[ColNames.HOUR] <= end_hour) | (df[ColNames.HOUR] >= start_hour)] + df = df.loc[ + (df[Variables.HOUR.col_name] <= end_hour) + | (df[Variables.HOUR.col_name] >= start_hour) + ] + + wind_speed_variable = VariableInfo.from_col_name(Variables.WIND_SPEED.col_name) - spd_colors = mapping_dictionary[ColNames.WIND_SPEED][ColNames.COLOR] - spd_unit = mapping_dictionary[ColNames.WIND_SPEED][si_ip][ColNames.UNIT] + spd_colors = wind_speed_variable.get_color() + spd_unit = wind_speed_variable.get_unit(si_ip) spd_bins = [-1, 0.5, 1.5, 3.3, 5.5, 7.9, 10.7, 13.8, 17.1, 20.7, np.inf] if si_ip == UnitSystem.IP: spd_bins = convert_bins(spd_bins) @@ -507,29 +558,36 @@ def wind_rose(df, title, month, hour, labels, si_ip): dir_bins = np.arange(-22.5 / 2, 360 + 22.5, 22.5) dir_labels = (dir_bins[:-1] + dir_bins[1:]) / 2 total_count = df.shape[0] - calm_count = df.query(f"{ColNames.WIND_SPEED} == 0").shape[0] + calm_count = df.query(f"{Variables.WIND_SPEED.col_name} == 0").shape[0] # Create a temporary DataFrame with binned data df_binned = df.assign( WindSpd_bins=lambda d: pd.cut( - d[ColNames.WIND_SPEED], bins=spd_bins, labels=spd_labels, right=True + d[Variables.WIND_SPEED.col_name], + bins=spd_bins, + labels=spd_labels, + right=True, ), WindDir_bins=lambda d: pd.cut( - d[ColNames.WIND_DIR], bins=dir_bins, labels=dir_labels, right=False + d[Variables.WIND_DIR.col_name], + bins=dir_bins, + labels=dir_labels, + right=False, ), ) # Rename the category in the 'WindDir_bins' column - df_binned[ColNames.WIND_DIR_BINS] = df_binned[ColNames.WIND_DIR_BINS].rename( - {360.0: 0.0} - ) + df_binned[Variables.WIND_DIR_BINS.col_name] = df_binned[ + Variables.WIND_DIR_BINS.col_name + ].rename({360.0: 0.0}) rose = ( df_binned.groupby( - by=[ColNames.WIND_SPD_BINS, ColNames.WIND_DIR_BINS], observed=False + by=[Variables.WIND_SPD_BINS.col_name, Variables.WIND_DIR_BINS.col_name], + observed=False, ) .size() - .unstack(level=ColNames.WIND_SPD_BINS) + .unstack(level=Variables.WIND_SPD_BINS.col_name) .fillna(0) .assign(calm=lambda d: calm_count / d.shape[0]) .sort_index(axis=1) @@ -633,7 +691,7 @@ def thermal_stress_stacked_barchart( month, hour, invert_month, invert_hour ) - if df.dropna(subset=[ColNames.MONTH]).shape[0] == 0: + if df.dropna(subset=[Variables.MONTH.col_name]).shape[0] == 0: return ( dbc.Alert( "No data is available in this location under these conditions. Please " @@ -646,7 +704,7 @@ def thermal_stress_stacked_barchart( isNormalized = True if normalize else False if isNormalized: new_df = ( - df.groupby(ColNames.MONTH)[var] + df.groupby(Variables.MONTH.col_name)[var] .value_counts(normalize=True) .unstack(var) .fillna(0) @@ -654,7 +712,12 @@ def thermal_stress_stacked_barchart( new_df = new_df.set_axis(categories, axis=1) new_df.reset_index(inplace=True) else: - new_df = df.groupby(ColNames.MONTH)[var].value_counts().unstack(var).fillna(0) + new_df = ( + df.groupby(Variables.MONTH.col_name)[var] + .value_counts() + .unstack(var) + .fillna(0) + ) new_df = new_df.set_axis(categories, axis=1) new_df.reset_index(inplace=True) @@ -731,13 +794,14 @@ def barchart(df, var, time_filter_info, data_filter_info, normalize, si_ip): start_hour = time_filter_info[2][0] end_hour = time_filter_info[2][1] - filter_var = str(data_filter_info[1]) - filter_name = mapping_dictionary[filter_var][ColNames.NAME] - filter_unit = mapping_dictionary[filter_var][si_ip][ColNames.UNIT] + filter_variable = VariableInfo.from_col_name(str(data_filter_info[1])) + filter_name = filter_variable.get_name() + filter_unit = filter_variable.get_unit(si_ip) - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - var_name = mapping_dictionary[var][ColNames.NAME] - var_color = mapping_dictionary[var][ColNames.COLOR] + var_variable = VariableInfo.from_col_name(var) + var_unit = var_variable.get_unit(si_ip) + var_name = var_variable.get_name() + var_color = var_variable.get_color() color_below = var_color[0] color_above = var_color[-1] @@ -758,13 +822,13 @@ def barchart(df, var, time_filter_info, data_filter_info, normalize, si_ip): query = ( f"month=={str(i)} and ({filter_var}>={min_val} and {filter_var}<={max_val})" ) - a = new_df.query(query)[ColNames.DOY].count() + a = new_df.query(query)[Variables.DOY.col_name].count() month_in.append(a) query = f"month=={str(i)} and ({filter_var}<{min_val})" - b = new_df.query(query)[ColNames.DOY].count() + b = new_df.query(query)[Variables.DOY.col_name].count() month_below.append(b) query = f"month=={str(i)} and {filter_var}>{max_val}" - c = new_df.query(query)[ColNames.DOY].count() + c = new_df.query(query)[Variables.DOY.col_name].count() month_above.append(c) go.Figure() @@ -885,9 +949,9 @@ def filter_df_by_month_and_hour( if time_filter: # Month filter - time_filtering(df, start_month, end_month, ColNames.MONTH, var) + time_filtering(df, start_month, end_month, Variables.MONTH.col_name, var) # Hour filter - time_filtering(df, start_hour, end_hour, ColNames.HOUR, var) + time_filtering(df, start_hour, end_hour, Variables.HOUR.col_name, var) return df diff --git a/pages/lib/utils.py b/pages/lib/utils.py index c95c908..ea55395 100644 --- a/pages/lib/utils.py +++ b/pages/lib/utils.py @@ -8,8 +8,8 @@ import dash_mantine_components as dmc from config import UnitSystem -from pages.lib.global_scheme import fig_config, mapping_dictionary, month_lst -from pages.lib.global_column_names import ColNames +from pages.lib.global_scheme import fig_config, month_lst +from pages.lib.global_variables import Variables, VariableInfo def code_timer(func): @@ -35,14 +35,14 @@ def generate_chart_name(tab_name, meta=None, custom_inputs=None, units=None): if units: custom_str += f"_{units}" if meta: - file_name = ( - f"{meta[ColNames.CITY]}_{meta[ColNames.COUNTRY]}_{tab_name}{custom_str}" - ) - figure_config[ColNames.TO_IMAGE_BUTTON_OPTIONS][ColNames.FILE_NAME] = file_name + file_name = f"{meta[Variables.CITY.col_name]}_{meta[Variables.COUNTRY.col_name]}_{tab_name}{custom_str}" + figure_config[Variables.TO_IMAGE_BUTTON_OPTIONS.col_name][ + Variables.FILE_NAME.col_name + ] = file_name else: - figure_config[ColNames.TO_IMAGE_BUTTON_OPTIONS][ColNames.FILE_NAME] = ( - f"{tab_name}{custom_str}" - ) + figure_config[Variables.TO_IMAGE_BUTTON_OPTIONS.col_name][ + Variables.FILE_NAME.col_name + ] = f"{tab_name}{custom_str}" return figure_config @@ -59,12 +59,13 @@ def generate_units_degree(si_ip): def generate_custom_inputs(var): - if var in mapping_dictionary: - var_fullname = mapping_dictionary[var][ColNames.NAME] - custom_inputs = "".join(word.capitalize() for word in var_fullname.split(" ")) - return custom_inputs - else: - return None + try: + variable = VariableInfo.from_col_name(var) + if variable.name: + return "".join(word.capitalize() for word in variable.name.split(" ")) + except KeyError: + pass + return None def generate_custom_inputs_time(start_month, end_month, start_hour, end_hour): @@ -93,19 +94,24 @@ def generate_custom_inputs_explorer( month_names = [""] + month_lst start_month_abbr = month_names[int(start_month)] end_month_abbr = month_names[int(end_month)] - if var in mapping_dictionary: - var_fullname = "".join( - word.capitalize() - for word in mapping_dictionary[var][ColNames.NAME].split(" ") + try: + var_name = VariableInfo.from_col_name(var).get_name() + var_fullname = ( + "".join(word.capitalize() for word in var_name.split(" ")) + if var_name + else var ) - else: + except KeyError: var_fullname = var - if filter_var in mapping_dictionary: - filter_fullname = "".join( - word.capitalize() - for word in mapping_dictionary[filter_var][ColNames.NAME].split(" ") + + try: + filter_name = VariableInfo.from_col_name(filter_var).get_name() + filter_fullname = ( + "".join(word.capitalize() for word in filter_name.split(" ")) + if filter_name + else filter_var ) - else: + except KeyError: filter_fullname = filter_var custom_inputs = f"{var_fullname}_{start_month_abbr}-{end_month_abbr}_{start_hour:02d}-{end_hour:02d}_{filter_fullname}_{min_val}-{max_val}" return custom_inputs @@ -124,20 +130,19 @@ def generate_custom_inputs_psy( month_names = [""] + month_lst start_month_abbr = month_names[int(start_month)] end_month_abbr = month_names[int(end_month)] - if colorby_var in mapping_dictionary: - colorby_fullname = "".join( - word.capitalize() - for word in mapping_dictionary[colorby_var][ColNames.NAME].split(" ") - ) - else: - colorby_fullname = colorby_var - if data_filter_var in mapping_dictionary: - data_filter_fullname = "".join( - word.capitalize() - for word in mapping_dictionary[data_filter_var][ColNames.NAME].split(" ") - ) - else: - data_filter_fullname = data_filter_var + + def format_variable_name(var: str) -> str: + try: + variable = VariableInfo.from_col_name(var) + name = variable.get_name() + return ( + "".join(word.capitalize() for word in name.split(" ")) if name else var + ) + except KeyError: + return var + + colorby_fullname = format_variable_name(colorby_var) + data_filter_fullname = format_variable_name(data_filter_var) if colorby_var == "None": custom_inputs = f"{start_month_abbr}-{end_month_abbr}_{start_hour:02d}-{end_hour:02d}_{data_filter_fullname}_{min_val}-{max_val}" @@ -169,8 +174,6 @@ def title_with_tooltip(text, tooltip_text, id_button): ) else: return dmc.Group( - mt="md", - px="md", children=[ dmc.Title(text, order=3), ], @@ -210,13 +213,17 @@ def title_with_link( def summary_table_tmp_rh_tab(df, value, si_ip): df_summary = ( - df.groupby([ColNames.MONTH_NAMES, ColNames.MONTH])[value] + df.groupby([Variables.MONTH_NAMES.col_name, Variables.MONTH.col_name])[value] .describe(percentiles=[0.01, 0.25, 0.5, 0.75, 0.99]) .round(2) ) - df_summary = df_summary.reset_index(level=ColNames.MONTH_NAMES).sort_index() + df_summary = df_summary.reset_index( + level=Variables.MONTH_NAMES.col_name + ).sort_index() df_summary = df_summary.drop(["count"], axis=1) - df_summary = df_summary.rename(columns={ColNames.MONTH_NAMES: ColNames.MONTH}) + df_summary = df_summary.rename( + columns={Variables.MONTH_NAMES.col_name: Variables.MONTH.col_name} + ) df_sum = ( df[value] @@ -224,12 +231,15 @@ def summary_table_tmp_rh_tab(df, value, si_ip): .round(2) .to_frame() ) - df_sum = df_sum.T.assign(count="Year").rename(columns={"count": ColNames.MONTH}) + df_sum = df_sum.T.assign(count="Year").rename( + columns={"count": Variables.MONTH.col_name} + ) df_summary = pd.concat([df_summary, df_sum]) unit = ( - mapping_dictionary[value][si_ip][ColNames.UNIT] + VariableInfo.from_col_name(value) + .get_unit(si_ip) .replace("", "") .replace("", "") ) @@ -237,7 +247,7 @@ def summary_table_tmp_rh_tab(df, value, si_ip): columns=[ ( {"name": i, "id": i} - if i == ColNames.MONTH + if i == Variables.MONTH.col_name else {"name": f"{i} ({unit})", "id": i} ) for i in df_summary.columns @@ -258,10 +268,14 @@ def summary_table_tmp_rh_tab(df, value, si_ip): def determine_month_and_hour_filter(month, hour, invert_month, invert_hour): start_month, end_month = month - if invert_month == [ColNames.INVERT] and (start_month != 1 or end_month != 12): + if invert_month == [Variables.INVERT.col_name] and ( + start_month != 1 or end_month != 12 + ): end_month, start_month = month start_hour, end_hour = hour - if invert_hour == [ColNames.INVERT] and (start_hour != 0 or end_hour != 24): + if invert_hour == [Variables.INVERT.col_name] and ( + start_hour != 0 or end_hour != 24 + ): end_hour, start_hour = hour return start_month, end_month, start_hour, end_hour diff --git a/pages/natural_ventilation.py b/pages/natural_ventilation.py index 4cd2cc9..9f18520 100644 --- a/pages/natural_ventilation.py +++ b/pages/natural_ventilation.py @@ -9,13 +9,12 @@ from config import PageUrls, DocLinks, PageInfo, UnitSystem from pages.lib.global_scheme import ( template, - mapping_dictionary, tight_margins, month_lst, ) from pages.lib.utils import get_max_min_value from pages.lib.template_graphs import filter_df_by_month_and_hour -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables, VariableInfo from pages.lib.global_element_ids import ElementIds from pages.lib.global_id_buttons import IdButtons from pages.lib.global_tab_names import TabNames @@ -286,8 +285,8 @@ def nv_heatmap( month, hour, invert_month, invert_hour ) - var = ColNames.DBT - filter_var = ColNames.DPT + var = Variables.DBT.col_name + filter_var = Variables.DPT.col_name if dbt_data_filter and (min_dbt_val <= max_dbt_val): df.loc[(df[var] < min_dbt_val) | (df[var] > max_dbt_val), var] = None @@ -295,7 +294,7 @@ def nv_heatmap( if dpt_data_filter: df.loc[(df[filter_var] < -200) | (df[filter_var] > max_dpt_val), var] = None - if df.dropna(subset=[ColNames.MONTH]).shape[0] == 0: + if df.dropna(subset=[Variables.MONTH.col_name]).shape[0] == 0: return ( dmc.Alert( title="Notice", @@ -314,17 +313,20 @@ def nv_heatmap( df, time_filter, month, hour, invert_month, invert_hour, var ) - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] + variable = VariableInfo.from_col_name(var) + filter = VariableInfo.from_col_name(filter_var) - filter_unit = mapping_dictionary[filter_var][si_ip][ColNames.UNIT] + var_unit = variable.get_unit(si_ip) - var_range = mapping_dictionary[var][si_ip][ColNames.RANGE] + filter_unit = filter.get_unit(si_ip) - var_name = mapping_dictionary[var][ColNames.NAME] + var_range = variable.get_range(si_ip) - filter_name = mapping_dictionary[filter_var][ColNames.NAME] + var_name = variable.get_name() - var_color = mapping_dictionary[var][ColNames.COLOR] + filter_name = filter.get_name() + + var_color = variable.get_color() if global_local == "global": range_z = var_range @@ -348,15 +350,19 @@ def nv_heatmap( fig = go.Figure( data=go.Heatmap( - y=df[ColNames.HOUR] - 0.5, # Offset by 0.5 to center the hour labels - x=df[ColNames.UTC_TIME].dt.date, + y=df[Variables.HOUR.col_name] + - 0.5, # Offset by 0.5 to center the hour labels + x=df[Variables.UTC_TIME.col_name].dt.date, z=df[var], colorscale=var_color, zmin=range_z[0], zmax=range_z[1], connectgaps=False, hoverongaps=False, - customdata=np.stack((df[ColNames.MONTH_NAMES], df[ColNames.DAY]), axis=-1), + customdata=np.stack( + (df[Variables.MONTH_NAMES.col_name], df[Variables.DAY.col_name]), + axis=-1, + ), hovertemplate=( "" + var @@ -455,19 +461,22 @@ def nv_bar_chart( month, hour, invert_month, invert_hour ) - var = ColNames.DBT - filter_var = ColNames.DPT + var = Variables.DBT.col_name + filter_var = Variables.DPT.col_name + + variable = VariableInfo.from_col_name(var) + filter = VariableInfo.from_col_name(filter_var) - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] - filter_unit = mapping_dictionary[filter_var][si_ip][ColNames.UNIT] + var_unit = variable.get_unit(si_ip) + filter_unit = filter.get_unit(si_ip) - var_name = mapping_dictionary[var][ColNames.NAME] + var_name = variable.get_name() - filter_name = mapping_dictionary[filter_var][ColNames.NAME] + filter_name = filter.get_name() color_in = "dodgerblue" - df[ColNames.NV_ALLOWED] = 1 + df[Variables.NV_ALLOWED.col_name] = 1 df = filter_df_by_month_and_hour( df, time_filter, month, hour, invert_month, invert_hour, "nv_allowed" @@ -475,20 +484,27 @@ def nv_bar_chart( # this should be the total after filtering by time tot_month_hours = ( - df.groupby(df[ColNames.UTC_TIME].dt.month)[ColNames.NV_ALLOWED].sum().values + df.groupby(df[Variables.UTC_TIME.col_name].dt.month)[ + Variables.NV_ALLOWED.col_name + ] + .sum() + .values ) if dbt_data_filter and (min_dbt_val <= max_dbt_val): df.loc[ - (df[var] < min_dbt_val) | (df[var] > max_dbt_val), ColNames.NV_ALLOWED + (df[var] < min_dbt_val) | (df[var] > max_dbt_val), + Variables.NV_ALLOWED.col_name, ] = 0 if dpt_data_filter: - df.loc[(df[filter_var] > max_dpt_val), ColNames.NV_ALLOWED] = 0 + df.loc[(df[filter_var] > max_dpt_val), Variables.NV_ALLOWED.col_name] = 0 n_hours_nv_allowed = ( - df.dropna(subset=ColNames.NV_ALLOWED) - .groupby(df[ColNames.UTC_TIME].dt.month)[ColNames.NV_ALLOWED] + df.dropna(subset=Variables.NV_ALLOWED.col_name) + .groupby(df[Variables.UTC_TIME.col_name].dt.month)[ + Variables.NV_ALLOWED.col_name + ] .sum() .values ) @@ -498,7 +514,7 @@ def nv_bar_chart( if not normalize: fig = go.Figure( go.Bar( - x=df[ColNames.MONTH_NAMES].unique(), + x=df[Variables.MONTH_NAMES.col_name].unique(), y=n_hours_nv_allowed, name="", marker_color=color_in, @@ -520,7 +536,7 @@ def nv_bar_chart( else: trace1 = go.Bar( - x=df[ColNames.MONTH_NAMES].unique(), + x=df[Variables.MONTH_NAMES.col_name].unique(), y=per_time_nv_allowed, name="", marker_color=color_in, diff --git a/pages/outdoor.py b/pages/outdoor.py index a7d9ba4..d0483c4 100644 --- a/pages/outdoor.py +++ b/pages/outdoor.py @@ -7,7 +7,7 @@ from config import PageUrls, DocLinks, PageInfo from pages.lib.global_element_ids import ElementIds -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables from pages.lib.global_id_buttons import IdButtons from pages.lib.global_tab_names import TabNames from pages.lib.global_scheme import ( @@ -211,10 +211,10 @@ def update_outdoor_comfort_output(_, df): Description of the best weather condition(s). """ cols = [ - ColNames.UTCI_NOSUN_WIND_CATEGORIES, - ColNames.UTCI_NOSUN_NOWIND_CATEGORIES, - ColNames.UTCI_SUN_WIND_CATEGORIES, - ColNames.UTCI_SUN_NOWIND_CATEGORIES, + Variables.UTCI_NOSUN_WIND_CATEGORIES.col_name, + Variables.UTCI_NOSUN_NOWIND_CATEGORIES.col_name, + Variables.UTCI_SUN_WIND_CATEGORIES.col_name, + Variables.UTCI_SUN_NOWIND_CATEGORIES.col_name, ] cols_with_the_highest_number_of_zero = [] highest_count = 0 diff --git a/pages/psy-chart.py b/pages/psy-chart.py index 4aca01e..b17969a 100644 --- a/pages/psy-chart.py +++ b/pages/psy-chart.py @@ -12,7 +12,7 @@ from config import PageUrls, DocLinks, PageInfo, UnitSystem from pages.lib.utils import get_max_min_value from pages.lib.global_element_ids import ElementIds -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables, VariableInfo from pages.lib.global_id_buttons import IdButtons from pages.lib.global_tab_names import TabNames from pages.lib.global_scheme import ( @@ -21,7 +21,6 @@ more_variables_dropdown, sun_cloud_tab_explore_dropdown_names, template, - mapping_dictionary, tight_margins, ) from pages.lib.template_graphs import filter_df_by_month_and_hour @@ -143,7 +142,7 @@ def inputs(): dropdown( id=ElementIds.PSY_VAR_DROPDOWN, options=dropdown_names, - value=ColNames.RH, + value=Variables.RH.col_name, ), flex=1, ), @@ -262,7 +261,7 @@ def update_psych_chart( mask = (df[data_filter_var] >= max_val) & (df[data_filter_var] <= min_val) df[mask] = None - if df.dropna(subset=[ColNames.MONTH]).shape[0] == 0: + if df.dropna(subset=[Variables.MONTH.col_name]).shape[0] == 0: return ( dmc.Alert( "No data is available in this location under these conditions. Please " @@ -279,24 +278,27 @@ def update_psych_chart( elif var == "Frequency": var_color = ["rgba(255,255,255,0)", "rgb(0,150,255)", "rgb(0,0,150)"] else: - var_unit = mapping_dictionary[var][si_ip][ColNames.UNIT] + var_unit = VariableInfo.from_col_name(var).get_unit(si_ip) - var_name = mapping_dictionary[var][ColNames.NAME] + var_name = VariableInfo.from_col_name(var).get_name() - var_color = mapping_dictionary[var][ColNames.COLOR] + var_color = VariableInfo.from_col_name(var).get_color() if global_local == "global": # Set Global values for Max and minimum - var_range_x = mapping_dictionary[ColNames.DBT][si_ip][ColNames.RANGE] - var_range_y = mapping_dictionary[ColNames.HR][si_ip][ColNames.RANGE] + variable_x = VariableInfo.from_col_name(Variables.DBT.col_name) + variable_y = VariableInfo.from_col_name(Variables.HR.col_name) + + var_range_x = variable_x.get_range(si_ip) + var_range_y = variable_y.get_range(si_ip) else: # Set maximum and minimum according to data - data_max, data_min = get_max_min_value(df[ColNames.DBT]) + data_max, data_min = get_max_min_value(df[Variables.DBT.col_name]) var_range_x = [data_min, data_max] - data_max = round(df[ColNames.HR].max(), 4) - data_min = round(df[ColNames.HR].min(), 4) + data_max = round(df[Variables.HR.col_name].max(), 4) + data_min = round(df[Variables.HR.col_name].min(), 4) var_range_y = [data_min * 1000, data_max * 1000] title = "Psychrometric Chart" @@ -312,7 +314,7 @@ def update_psych_chart( hr_list = np.vectorize(psy.psy_ta_rh)(dbt_list, rh) hr_df = pd.DataFrame.from_records(hr_list) name = "rh" + str(rh) - rh_df[name] = hr_df[ColNames.HR] + rh_df[name] = hr_df[Variables.HR.col_name] fig = go.Figure() @@ -342,13 +344,13 @@ def update_psych_chart( ) ) - df_hr_multiply = list(df[ColNames.HR]) + df_hr_multiply = list(df[Variables.HR.col_name]) for k in range(len(df_hr_multiply)): df_hr_multiply[k] = df_hr_multiply[k] * 1000 if var == "None": fig.add_trace( go.Scatter( - x=df[ColNames.DBT], + x=df[Variables.DBT.col_name], y=df_hr_multiply, showlegend=False, mode="markers", @@ -358,16 +360,18 @@ def update_psych_chart( showscale=False, opacity=0.2, ), - hovertemplate=mapping_dictionary[ColNames.DBT][ColNames.NAME] + hovertemplate=VariableInfo.from_col_name( + Variables.DBT.col_name + ).get_name() + ": %{x:.2f}" - + mapping_dictionary[ColNames.DBT][ColNames.NAME], + + VariableInfo.from_col_name(Variables.DBT.col_name).get_name(), name="", ) ) elif var == "Frequency": fig.add_trace( go.Histogram2d( - x=df[ColNames.DBT], + x=df[Variables.DBT.col_name], y=df_hr_multiply, name="", colorscale=var_color, @@ -411,7 +415,7 @@ def update_psych_chart( fig.add_trace( go.Scatter( - x=df[ColNames.DBT], + x=df[Variables.DBT.col_name], y=df_hr_multiply, showlegend=False, mode="markers", @@ -424,23 +428,25 @@ def update_psych_chart( colorbar=var_colorbar, ), customdata=np.stack( - (df[ColNames.RH], df["h"], df[var], df["t_dp"]), axis=-1 + (df[Variables.RH.col_name], df["h"], df[var], df["t_dp"]), axis=-1 ), - hovertemplate=mapping_dictionary[ColNames.DBT][ColNames.NAME] + hovertemplate=VariableInfo.from_col_name( + Variables.DBT.col_name + ).get_name() + ": %{x:.2f}" - + mapping_dictionary[ColNames.DBT][si_ip][ColNames.UNIT] + + VariableInfo.from_col_name(Variables.DBT.col_name).get_unit(si_ip) + "
" - + mapping_dictionary[ColNames.RH][ColNames.NAME] + + VariableInfo.from_col_name(Variables.RH.col_name).get_name() + ": %{customdata[0]:.2f}" - + mapping_dictionary[ColNames.RH][si_ip][ColNames.UNIT] + + VariableInfo.from_col_name(Variables.RH.col_name).get_unit(si_ip) + "
" - + mapping_dictionary["h"][ColNames.NAME] + + VariableInfo.from_col_name("h").get_name() + ": %{customdata[1]:.2f}" - + mapping_dictionary["h"][si_ip][ColNames.UNIT] + + VariableInfo.from_col_name("h").get_unit(si_ip) + "
" - + mapping_dictionary["t_dp"][ColNames.NAME] + + VariableInfo.from_col_name("t_dp").get_name() + ": %{customdata[3]:.2f}" - + mapping_dictionary["t_dp"][si_ip][ColNames.UNIT] + + VariableInfo.from_col_name("t_dp").get_unit(si_ip) + "
" + "
" + var_name @@ -451,10 +457,14 @@ def update_psych_chart( ) xtitle_name = ( - "Temperature" + " " + mapping_dictionary[ColNames.DBT][si_ip][ColNames.UNIT] + "Temperature" + + " " + + VariableInfo.from_col_name(Variables.DBT.col_name).get_unit(si_ip) ) ytitle_name = ( - "Humidity Ratio" + " " + mapping_dictionary[ColNames.HR][si_ip][ColNames.UNIT] + "Humidity Ratio" + + " " + + VariableInfo.from_col_name(Variables.HR.col_name).get_unit(si_ip) ) fig.update_layout(template=template, margin=tight_margins) fig.update_xaxes( diff --git a/pages/select.py b/pages/select.py index 63db215..498cc67 100644 --- a/pages/select.py +++ b/pages/select.py @@ -10,13 +10,12 @@ from dash_extensions.enrich import Serverside, Output, Input, State, html, dcc, callback from pandas import json_normalize -from pages.lib.extract_df import convert_data +from pages.lib.extract_df import convert_df_units from pages.lib.extract_df import create_df, get_data, get_location_info -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables from pages.lib.global_element_ids import ElementIds from pages.lib.global_tab_names import TabNames -from pages.lib.global_scheme import mapping_dictionary -from config import PageUrls, PageInfo, UnitSystem +from config import PageUrls, PageInfo from pages.lib.utils import generate_chart_name dash.register_page( @@ -149,7 +148,7 @@ def submitted_data( """Process the uploaded file or download the EPW from the URL""" ctx = dash.callback_context - if ctx.triggered[0][ColNames.PROP_ID] == "modal-yes-button.n_clicks": + if ctx.triggered[0][Variables.PROP_ID.col_name] == "modal-yes-button.n_clicks": lines = get_data(url_store) if lines is None: return ( @@ -171,7 +170,7 @@ def submitted_data( ) elif ( - ctx.triggered[0][ColNames.PROP_ID] == "upload-data.contents" + ctx.triggered[0][Variables.PROP_ID.col_name] == "upload-data.contents" and list_of_contents is not None ): content_type, content_string = list_of_contents[0].split(",") @@ -231,9 +230,9 @@ def submitted_data( def switch_si_ip(_, si_ip_input, url_store, lines): if lines is not None: df, _ = create_df(lines, url_store) - map_json = json.dumps(mapping_dictionary) - if si_ip_input == UnitSystem.IP: - map_json = convert_data(df, map_json) + + df = convert_df_units(df, si_ip_input) + return Serverside(df), si_ip_input else: return ( @@ -290,7 +289,10 @@ def enable_tabs_when_data_is_loaded(meta, data): False, False, True, # changelog always disabled - "Current Location: " + meta[ColNames.CITY] + ", " + meta[ColNames.COUNTRY], + "Current Location: " + + meta[Variables.CITY.col_name] + + ", " + + meta[Variables.COUNTRY.col_name], ) @@ -340,11 +342,11 @@ def plot_location_epw_files(pathname): with open("./assets/data/epw_location.json", encoding="utf8") as data_file: data = json.load(data_file) - df = json_normalize(data[ColNames.FEATURES]) - df[[ColNames.LON, ColNames.LAT]] = pd.DataFrame( - df[ColNames.GEOMETRY_COORDINATES].tolist() + df = json_normalize(data[Variables.FEATURES.col_name]) + df[[Variables.LON.col_name, Variables.LAT.col_name]] = pd.DataFrame( + df[Variables.GEOMETRY_COORDINATES.col_name].tolist() ) - df[ColNames.LAT] += 0.010 + df[Variables.LAT.col_name] += 0.010 df = df.rename(columns={"properties.epw": "Source"}) fig = px.scatter_mapbox( @@ -363,7 +365,7 @@ def plot_location_epw_files(pathname): df_one_building, lat="lat", lon="lon", - hover_name=df_one_building[ColNames.NAME], + hover_name=df_one_building[Variables.NAME.col_name], color_discrete_sequence=["#4895ef"], hover_data=[ "period", diff --git a/pages/summary.py b/pages/summary.py index 7f11a30..e651273 100644 --- a/pages/summary.py +++ b/pages/summary.py @@ -9,9 +9,9 @@ from config import PageUrls, DocLinks, PageInfo, UnitSystem from pages.lib.charts_summary import world_map from pages.lib.extract_df import get_data -from pages.lib.global_scheme import template, tight_margins, mapping_dictionary +from pages.lib.global_scheme import template, tight_margins from pages.lib.template_graphs import violin -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables, VariableInfo from pages.lib.global_element_ids import ElementIds from pages.lib.global_id_buttons import IdButtons from pages.lib.global_tab_names import TabNames @@ -196,11 +196,13 @@ def update_map(meta): ) def update_location_info(ts, df, meta, si_ip): """Update the contents of tab two. Passing in the general info (df, meta).""" - location = f"Location: {meta[ColNames.CITY]}, {meta[ColNames.COUNTRY]}" - lon = f" Longitude: {meta[ColNames.LON]}" - lat = f"Latitude: {meta[ColNames.LAT]}" + location = ( + f"Location: {meta[Variables.CITY.col_name]}, {meta[Variables.COUNTRY.col_name]}" + ) + lon = f" Longitude: {meta[Variables.LON.col_name]}" + lat = f"Latitude: {meta[Variables.LAT.col_name]}" - site_elevation = round(float(meta[ColNames.SITE_ELEVATION]), 2) + site_elevation = round(float(meta[Variables.SITE_ELEVATION.col_name]), 2) if si_ip != UnitSystem.SI: site_elevation = round(site_elevation * 3.281, 2) elevation = f"Elevation above sea level: {site_elevation} ft" @@ -209,14 +211,14 @@ def update_location_info(ts, df, meta, si_ip): elevation = f"Elevation above sea level: {site_elevation} m" period = "" - if meta[ColNames.PERIOD]: - start, stop = meta[ColNames.PERIOD].split("-") + if meta[Variables.PERIOD.col_name]: + start, stop = meta[Variables.PERIOD.col_name].split("-") period = f"This file is based on data collected between {start} and {stop}" climate_text = "" try: r = requests.get( - f"http://climateapi.scottpinkelman.com/api/v1/location/{meta[ColNames.LAT]}/{meta[ColNames.LON]}" + f"http://climateapi.scottpinkelman.com/api/v1/location/{meta[Variables.LAT.col_name]}/{meta[Variables.LON.col_name]}" ) if r.status_code == 200: j = r.json()["return_values"][0] @@ -226,27 +228,27 @@ def update_location_info(ts, df, meta, si_ip): # global horizontal irradiance # Note that the value is divided by 1000, so a corresponding change is made in the unit: - total_solar_rad_value = round(df[ColNames.GLOB_HOR_RAD].sum() / 1000, 2) - total_solar_rad_unit = "k" + mapping_dictionary[ColNames.GLOB_HOR_RAD][si_ip][ - ColNames.UNIT - ].replace("", "").replace("", "") + total_solar_rad_value = round(df[Variables.GLOB_HOR_RAD.col_name].sum() / 1000, 2) + total_solar_rad_unit = "k" + VariableInfo.from_col_name( + Variables.GLOB_HOR_RAD.col_name + ).get_unit(si_ip).replace("", "").replace("", "") total_solar_rad = f"Annual cumulative horizontal solar radiation: {total_solar_rad_value} {total_solar_rad_unit}" - glob_sum = df[ColNames.GLOB_HOR_RAD].sum() + glob_sum = df[Variables.GLOB_HOR_RAD.col_name].sum() diffuse_percentage = ( - round(df[ColNames.DIF_HOR_RAD].sum() / glob_sum * 100, 1) if glob_sum > 0 else 0 + round(df[Variables.DIF_HOR_RAD.col_name].sum() / glob_sum * 100, 1) + if glob_sum > 0 + else 0 ) total_diffuse_rad = ( f"Percentage of diffuse horizontal solar radiation: {diffuse_percentage} %" ) - tmp_unit = mapping_dictionary[ColNames.DBT][si_ip][ColNames.UNIT] + tmp_unit = VariableInfo.from_col_name(Variables.DBT.col_name).get_unit(si_ip) - average_yearly_tmp = ( - f"Average yearly temperature: {df[ColNames.DBT].mean().round(1)} {tmp_unit}" - ) - hottest_yearly_tmp = f"Hottest yearly temperature (99%): {df[ColNames.DBT].quantile(0.99).round(1)} {tmp_unit}" - coldest_yearly_tmp = f"Coldest yearly temperature (1%): {df[ColNames.DBT].quantile(0.01).round(1)} {tmp_unit}" + average_yearly_tmp = f"Average yearly temperature: {df[Variables.DBT.col_name].mean().round(1)} {tmp_unit}" + hottest_yearly_tmp = f"Hottest yearly temperature (99%): {df[Variables.DBT.col_name].quantile(0.99).round(1)} {tmp_unit}" + coldest_yearly_tmp = f"Coldest yearly temperature (1%): {df[Variables.DBT.col_name].quantile(0.01).round(1)} {tmp_unit}" return [ dmc.Text(location, fw=700), @@ -298,18 +300,18 @@ def degree_day_chart(ts, n_clicks, df, meta, hdd_value, cdd_value, si_ip): color_cdd = "dodgerblue" hdd_array, cdd_array = [], [] - months = df[ColNames.MONTH_NAMES].unique() + months = df[Variables.MONTH_NAMES.col_name].unique() for i in range(1, 13): query_month = "month==" a = df.query(query_month + str(i) + " and DBT<=" + str(hdd_setpoint))[ - ColNames.DBT + Variables.DBT.col_name ].sub(hdd_setpoint) hdd_array.append(int(a.sum(skipna=True) / 24)) a = df.query(query_month + str(i) + " and DBT>=" + str(cdd_setpoint))[ - ColNames.DBT + Variables.DBT.col_name ].sub(cdd_setpoint) cdd_array.append(int(a.sum(skipna=True) / 24)) @@ -383,7 +385,7 @@ def update_violin_tdb(ts, global_local, df, meta, si_ip): return dcc.Graph( id=ElementIds.TDB_PROFILE_GRAPH, config=generate_chart_name(TabNames.DRY_BULB_TEMPERATURE, meta, units), - figure=violin(df, ColNames.DBT, global_local, si_ip), + figure=violin(df, Variables.DBT.col_name, global_local, si_ip), ) @@ -405,7 +407,7 @@ def update_tab_wind(ts, global_local, df, meta, si_ip): return dcc.Graph( id=ElementIds.WIND_PROFILE_GRAPH, config=generate_chart_name(TabNames.WIND_SPEED, meta, units), - figure=violin(df, ColNames.WIND_SPEED, global_local, si_ip), + figure=violin(df, Variables.WIND_SPEED.col_name, global_local, si_ip), ) @@ -427,7 +429,7 @@ def update_tab_rh(ts, global_local, df, meta, si_ip): return dcc.Graph( id=ElementIds.RH_PROFILE_GRAPH, config=generate_chart_name(TabNames.RELATIVE_HUMIDITY, meta, units), - figure=violin(df, ColNames.RH, global_local, si_ip), + figure=violin(df, Variables.RH.col_name, global_local, si_ip), ) @@ -449,7 +451,7 @@ def update_tab_gh_rad(ts, global_local, df, meta, si_ip): return dcc.Graph( id=ElementIds.GH_RAD_PROFILE_GRAPH, config=generate_chart_name(TabNames.GLOBAL_HORIZONTAL_RADIATION, meta, units), - figure=violin(df, ColNames.GLOB_HOR_RAD, global_local, si_ip), + figure=violin(df, Variables.GLOB_HOR_RAD.col_name, global_local, si_ip), ) @@ -470,12 +472,12 @@ def download_clima_dataframe(n_clicks, df, meta, si_ip): if si_ip == UnitSystem.SI: return dcc.send_data_frame( df.to_csv, - f"df_{meta[ColNames.CITY]}_{meta[ColNames.COUNTRY]}_Clima_SIunit.csv", + f"df_{meta[Variables.CITY.col_name]}_{meta[Variables.COUNTRY.col_name]}_Clima_SIunit.csv", ) else: return dcc.send_data_frame( df.to_csv, - f"df_{meta[ColNames.CITY]}_{meta[ColNames.COUNTRY]}_Clima_IPunit.csv", + f"df_{meta[Variables.CITY.col_name]}_{meta[Variables.COUNTRY.col_name]}_Clima_IPunit.csv", ) else: print("df not loaded yet") @@ -496,7 +498,7 @@ def download_epw(n_clicks, meta): lines[0] = lines[0].replace("b'", "") return dict( content="\n".join(lines), - filename=f"{meta[ColNames.CITY]}_{meta[ColNames.COUNTRY]}.epw", + filename=f"{meta[Variables.CITY.col_name]}_{meta[Variables.COUNTRY.col_name]}.epw", ) else: raise PreventUpdate diff --git a/pages/sun.py b/pages/sun.py index 5307acc..3999dac 100644 --- a/pages/sun.py +++ b/pages/sun.py @@ -8,7 +8,7 @@ from dash import dcc from dash_extensions.enrich import Output, Input, State, callback -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables from pages.lib.global_id_buttons import IdButtons from pages.lib.global_tab_names import TabNames from config import PageUrls, DocLinks, PageInfo, UnitSystem @@ -203,7 +203,7 @@ def monthly_and_cloud_chart(_, df, meta, si_ip): # Cloud Cover cover = barchart( - df, ColNames.TOT_SKY_COVER, [False], [False, "", 3, 7], True, si_ip + df, Variables.TOT_SKY_COVER.col_name, [False], [False, "", 3, 7], True, si_ip ) cover = cover.update_layout( margin=tight_margins, diff --git a/pages/t_rh.py b/pages/t_rh.py index a9c01b6..932a9df 100644 --- a/pages/t_rh.py +++ b/pages/t_rh.py @@ -5,7 +5,7 @@ from config import PageUrls, DocLinks, PageInfo from pages.lib.global_scheme import dropdown_names from pages.lib.template_graphs import heatmap, yearly_profile, daily_profile -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables from pages.lib.global_element_ids import ElementIds from pages.lib.global_id_buttons import IdButtons from pages.lib.global_tab_names import TabNames @@ -101,7 +101,7 @@ def layout(): ) def update_yearly_chart(_, global_local, dd_value, df, meta, si_ip): if dd_value == dropdown_names[var_to_plot[0]]: - dbt_yearly = yearly_profile(df, ColNames.DBT, global_local, si_ip) + dbt_yearly = yearly_profile(df, Variables.DBT.col_name, global_local, si_ip) dbt_yearly.update_layout(xaxis=dict(rangeslider=dict(visible=True))) units = generate_units_degree(si_ip) return dcc.Graph( @@ -111,7 +111,7 @@ def update_yearly_chart(_, global_local, dd_value, df, meta, si_ip): figure=dbt_yearly, ) else: - rh_yearly = yearly_profile(df, ColNames.RH, global_local, si_ip) + rh_yearly = yearly_profile(df, Variables.RH.col_name, global_local, si_ip) rh_yearly.update_layout(xaxis=dict(rangeslider=dict(visible=True))) units = generate_units(si_ip) return dcc.Graph( @@ -143,15 +143,15 @@ def update_daily(_, global_local, dd_value, df, meta, si_ip): figure=daily_profile( df[ [ - ColNames.DBT, - ColNames.HOUR, - ColNames.UTC_TIME, - ColNames.MONTH_NAMES, - ColNames.DAY, - ColNames.MONTH, + Variables.DBT.col_name, + Variables.HOUR.col_name, + Variables.UTC_TIME.col_name, + Variables.MONTH_NAMES.col_name, + Variables.DAY.col_name, + Variables.MONTH.col_name, ] ], - ColNames.DBT, + Variables.DBT.col_name, global_local, si_ip, ), @@ -163,15 +163,15 @@ def update_daily(_, global_local, dd_value, df, meta, si_ip): figure=daily_profile( df[ [ - ColNames.RH, - ColNames.HOUR, - ColNames.UTC_TIME, - ColNames.MONTH_NAMES, - ColNames.DAY, - ColNames.MONTH, + Variables.RH.col_name, + Variables.HOUR.col_name, + Variables.UTC_TIME.col_name, + Variables.MONTH_NAMES.col_name, + Variables.DAY.col_name, + Variables.MONTH.col_name, ] ], - ColNames.RH, + Variables.RH.col_name, global_local, si_ip, ), @@ -202,14 +202,14 @@ def update_heatmap(_, global_local, dd_value, df, meta, si_ip): figure=heatmap( df[ [ - ColNames.DBT, - ColNames.HOUR, - ColNames.UTC_TIME, - ColNames.MONTH_NAMES, - ColNames.DAY, + Variables.DBT.col_name, + Variables.HOUR.col_name, + Variables.UTC_TIME.col_name, + Variables.MONTH_NAMES.col_name, + Variables.DAY.col_name, ] ], - ColNames.DBT, + Variables.DBT.col_name, global_local, si_ip, ), @@ -221,14 +221,14 @@ def update_heatmap(_, global_local, dd_value, df, meta, si_ip): figure=heatmap( df[ [ - ColNames.RH, - ColNames.HOUR, - ColNames.UTC_TIME, - ColNames.MONTH_NAMES, - ColNames.DAY, + Variables.RH.col_name, + Variables.HOUR.col_name, + Variables.UTC_TIME.col_name, + Variables.MONTH_NAMES.col_name, + Variables.DAY.col_name, ] ], - ColNames.RH, + Variables.RH.col_name, global_local, si_ip, ), @@ -249,7 +249,14 @@ def update_heatmap(_, global_local, dd_value, df, meta, si_ip): def update_table(_, dd_value, df, si_ip): """Update the contents of descriptive statistics table.""" return summary_table_tmp_rh_tab( - df[[ColNames.MONTH, ColNames.HOUR, dd_value, ColNames.MONTH_NAMES]], + df[ + [ + Variables.MONTH.col_name, + Variables.HOUR.col_name, + dd_value, + Variables.MONTH_NAMES.col_name, + ] + ], dd_value, si_ip, ) diff --git a/pages/wind.py b/pages/wind.py index 195f4b6..e9d0d9f 100644 --- a/pages/wind.py +++ b/pages/wind.py @@ -7,7 +7,7 @@ from config import PageUrls, DocLinks, PageInfo from pages.lib.global_scheme import month_lst from pages.lib.template_graphs import heatmap, wind_rose -from pages.lib.global_column_names import ColNames +from pages.lib.global_variables import Variables from pages.lib.global_id_buttons import IdButtons from pages.lib.global_tab_names import TabNames from pages.lib.utils import ( @@ -222,7 +222,7 @@ def custom_wind_rose(): children=[ dmc.Title( "Start Month:", - order=6, + order=5, w="8rem", ta="right", ), @@ -359,7 +359,7 @@ def update_annual_wind_rose(_, df, meta, si_ip): ], ) def update_tab_wind_speed(_, global_local, df, meta, si_ip): - speed = heatmap(df, ColNames.WIND_SPEED, global_local, si_ip) + speed = heatmap(df, Variables.WIND_SPEED.col_name, global_local, si_ip) units = generate_units(si_ip) return dcc.Graph( config=generate_chart_name(TabNames.WIND_SPEED, meta, units), @@ -377,7 +377,7 @@ def update_tab_wind_speed(_, global_local, df, meta, si_ip): ], ) def update_tab_wind_direction(global_local, df, meta, si_ip): - direction = heatmap(df, ColNames.WIND_DIR, global_local, si_ip) + direction = heatmap(df, Variables.WIND_DIR.col_name, global_local, si_ip) units = generate_units(si_ip) return dcc.Graph( config=generate_chart_name(TabNames.WIND_DIRECTION, meta, units), @@ -410,16 +410,24 @@ def update_custom_wind_rose( if start_month <= end_month: df = df.loc[ - (df[ColNames.MONTH] >= start_month) & (df[ColNames.MONTH] <= end_month) + (df[Variables.MONTH.col_name] >= start_month) + & (df[Variables.MONTH.col_name] <= end_month) ] else: df = df.loc[ - (df[ColNames.MONTH] <= end_month) | (df[ColNames.MONTH] >= start_month) + (df[Variables.MONTH.col_name] <= end_month) + | (df[Variables.MONTH.col_name] >= start_month) ] if start_hour <= end_hour: - df = df.loc[(df[ColNames.HOUR] >= start_hour) & (df[ColNames.HOUR] <= end_hour)] + df = df.loc[ + (df[Variables.HOUR.col_name] >= start_hour) + & (df[Variables.HOUR.col_name] <= end_hour) + ] else: - df = df.loc[(df[ColNames.HOUR] <= end_hour) | (df[ColNames.HOUR] >= start_hour)] + df = df.loc[ + (df[Variables.HOUR.col_name] <= end_hour) + | (df[Variables.HOUR.col_name] >= start_hour) + ] custom = wind_rose( df, "", [start_month, end_month], [start_hour, end_hour], True, si_ip @@ -466,31 +474,32 @@ def update_seasonal_graphs(_, df, meta, si_ip): summer = wind_rose(df, "", summer_months, hours, False, si_ip) fall = wind_rose(df, "", fall_months, hours, False, si_ip) - query_calm_wind = f"{ColNames.WIND_SPEED} == 0" + query_calm_wind = f"{Variables.WIND_SPEED.col_name} == 0" winter_df = df.loc[ - (df[ColNames.MONTH] <= winter_months[1]) - | (df[ColNames.MONTH] >= winter_months[0]) + (df[Variables.MONTH.col_name] <= winter_months[1]) + | (df[Variables.MONTH.col_name] >= winter_months[0]) ] winter_total_count = winter_df.shape[0] winter_calm_count = winter_df.query(query_calm_wind).shape[0] spring_df = df.loc[ - (df[ColNames.MONTH] >= spring_months[0]) - & (df[ColNames.MONTH] <= spring_months[1]) + (df[Variables.MONTH.col_name] >= spring_months[0]) + & (df[Variables.MONTH.col_name] <= spring_months[1]) ] spring_total_count = spring_df.shape[0] spring_calm_count = spring_df.query(query_calm_wind).shape[0] summer_df = df.loc[ - (df[ColNames.MONTH] >= summer_months[0]) - & (df[ColNames.MONTH] <= summer_months[1]) + (df[Variables.MONTH.col_name] >= summer_months[0]) + & (df[Variables.MONTH.col_name] <= summer_months[1]) ] summer_total_count = summer_df.shape[0] summer_calm_count = summer_df.query(query_calm_wind).shape[0] fall_df = df.loc[ - (df[ColNames.MONTH] >= fall_months[0]) & (df[ColNames.MONTH] <= fall_months[1]) + (df[Variables.MONTH.col_name] >= fall_months[0]) + & (df[Variables.MONTH.col_name] <= fall_months[1]) ] fall_total_count = fall_df.shape[0] fall_calm_count = fall_df.query(query_calm_wind).shape[0] @@ -579,24 +588,25 @@ def update_daily_graphs(_, df, meta, si_ip): noon = wind_rose(df, "", months, noon_times, False, si_ip) night = wind_rose(df, "", months, night_times, True, si_ip) - query_calm_wind = f"{ColNames.WIND_SPEED} == 0" + query_calm_wind = f"{Variables.WIND_SPEED.col_name} == 0" morning_df = df.loc[ - (df[ColNames.HOUR] >= morning_times[0]) - & (df[ColNames.HOUR] <= morning_times[1]) + (df[Variables.HOUR.col_name] >= morning_times[0]) + & (df[Variables.HOUR.col_name] <= morning_times[1]) ] morning_total_count = morning_df.shape[0] morning_calm_count = morning_df.query(query_calm_wind).shape[0] noon_df = df.loc[ - (df[ColNames.HOUR] >= morning_times[0]) - & (df[ColNames.HOUR] <= morning_times[1]) + (df[Variables.HOUR.col_name] >= morning_times[0]) + & (df[Variables.HOUR.col_name] <= morning_times[1]) ] noon_total_count = noon_df.shape[0] noon_calm_count = noon_df.query(query_calm_wind).shape[0] night_df = df.loc[ - (df[ColNames.HOUR] <= night_times[1]) | (df[ColNames.HOUR] >= night_times[0]) + (df[Variables.HOUR.col_name] <= night_times[1]) + | (df[Variables.HOUR.col_name] >= night_times[0]) ] night_total_count = night_df.shape[0] night_calm_count = night_df.query(query_calm_wind).shape[0]