Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Assets:
class PageInfo:
"""Stores page names and orders for registration."""

SELECT_NAME = "Select Weather File"
SELECT_NAME = "Select weather file"
SELECT_ORDER = 0
SUMMARY_NAME = "Climate Summary"
SUMMARY_ORDER = 1
Expand Down
81 changes: 48 additions & 33 deletions pages/lib/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

class NavBarIcons:
_ICON_MAP = {
"Select Weather File": "tabler:upload",
"Climate Summary": "tabler:chart-bar",
"Temperature and Humidity": "tabler:temperature",
"Sun and Clouds": "tabler:sun",
Expand All @@ -26,7 +25,6 @@ class NavBarIcons:
"Changelog": "tabler:history",
}

SELECT_WEATHER_FILE = _ICON_MAP["Select Weather File"]
CLIMATE_SUMMARY = _ICON_MAP["Climate Summary"]
TEMPERATURE_AND_HUMIDITY = _ICON_MAP["Temperature and Humidity"]
SUN_AND_CLOUDS = _ICON_MAP["Sun and Clouds"]
Expand All @@ -49,14 +47,7 @@ def create_tools_filter_components():
return dmc.Stack(
id=ElementIds.TOOLS_MONTH_HOUR_SECTION,
children=[
dmc.Divider(label="Filter function", size="xs", color="blue"),
dmc.Button(
"Apply month and hour filter",
id=ElementIds.TOOLS_APPLY_MONTH_HOUR_FILTER,
color="blue",
variant="light",
size="xs",
),
dmc.Divider(label="Filters", size="xs", color="blue"),
# Month controls
dmc.Text("Month Range:", size="xs", c="dimmed"),
dcc.RangeSlider(
Expand Down Expand Up @@ -113,6 +104,13 @@ def create_tools_filter_components():
],
justify="flex-end",
),
dmc.Button(
"Apply month and hour filter",
id=ElementIds.TOOLS_APPLY_MONTH_HOUR_FILTER,
color="blue",
variant="filled",
size="xs",
),
],
gap="xs",
p="xs",
Expand All @@ -137,7 +135,28 @@ def create_navbar():
}
}

# Secondary Menu
# Select weather file - top-level menu item
select_weather_file_page = next(
(
page
for page in dash.page_registry.values()
if page[Variables.NAME.col_name] == "Select weather file"
),
None,
)
select_weather_file_link = (
dmc.NavLink(
label=select_weather_file_page[Variables.NAME.col_name],
href=select_weather_file_page[Variables.PATH.col_name],
id=f"nav-{select_weather_file_page[Variables.PATH.col_name].replace('/', '')}",
active=False,
styles=nav_link_styles,
)
if select_weather_file_page
else None
)

# Secondary Menu - exclude "Select weather file" as it will be a top-level menu
sub_links = [
dmc.NavLink(
label=page[Variables.NAME.col_name],
Expand All @@ -150,11 +169,12 @@ def create_navbar():
styles=nav_link_styles,
)
for page in dash.page_registry.values()
if page[Variables.NAME.col_name] not in ["404", "Changelog"]
if page[Variables.NAME.col_name]
not in ["404", "Changelog", "Select weather file"]
]

parent_group = dmc.NavLink(
label="Pages Menu",
label="Visualize weather file",
children=sub_links,
id=ElementIds.NAV_GROUP_MAIN,
variant="light",
Expand All @@ -168,17 +188,11 @@ def create_navbar():

controls_stack = dmc.Stack(
gap="xs",
py="xs",
p="xs",
children=[
dmc.Divider(label="Units and Ranges", size="xs", color="blue"),
dmc.Tooltip(
label=dmc.Stack(
gap="xs",
children=[
dmc.Text(
"You can choose value ranges between Global and Local"
),
],
),
label=dmc.Text("You can choose value ranges between Global and Local"),
position="right",
withArrow=True,
children=dmc.SegmentedControl(
Expand All @@ -189,18 +203,13 @@ def create_navbar():
{"label": "Global", "value": "global"},
{"label": "Local", "value": "local"},
],
w=220,
w=210,
size="sm",
styles=segmented_control_styles,
),
),
dmc.Tooltip(
label=dmc.Stack(
gap="xs",
children=[
dmc.Text("You can choose units between SI and IP"),
],
),
label=dmc.Text("You can choose units between SI and IP"),
position="right",
withArrow=True,
children=dmc.SegmentedControl(
Expand All @@ -211,7 +220,7 @@ def create_navbar():
{"label": "SI", "value": UnitSystem.SI},
{"label": "IP", "value": UnitSystem.IP},
],
w=220,
w=210,
size="sm",
styles=segmented_control_styles,
),
Expand All @@ -223,11 +232,12 @@ def create_navbar():

# Tools
controls_group = dmc.NavLink(
label="Tools Menu",
children=[controls_stack, filter_components],
label="Filters and units",
children=[filter_components, controls_stack],
id=ElementIds.NAV_GROUP_CONTROLS,
variant="light",
childrenOffset=0,
opened=True,
)

# Documentation
Expand All @@ -240,7 +250,12 @@ def create_navbar():
)

return dmc.ScrollArea(
children=[parent_group, controls_group, doc_link],
children=[
select_weather_file_link,
parent_group,
controls_group,
doc_link,
],
)


Expand Down
24 changes: 17 additions & 7 deletions pages/lib/template_graphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,9 @@ def heatmap_with_filter(
),
)

if global_local == "global":
# For category variables (e.g., UTCI categories), always use global range
# to ensure consistent color mapping regardless of data range
if "_categories" in var or global_local == "global":
# Set Global values for Max and minimum
range_z = var_range
else:
Expand Down Expand Up @@ -712,7 +714,9 @@ def wind_rose(df, title, month, hour, labels, si_ip, skip_time_filter=False):

spd_colors = wind_speed_variable.get_color()
spd_unit = wind_speed_variable.get_unit(si_ip)
spd_bins = WIND_ROSE_BINS
spd_bins = list(
WIND_ROSE_BINS
) # Create a copy to avoid modifying the global constant
if si_ip == UnitSystem.IP:
spd_bins = convert_bins(spd_bins)

Expand Down Expand Up @@ -810,12 +814,18 @@ def wind_rose(df, title, month, hour, labels, si_ip, skip_time_filter=False):


def convert_bins(sbins):
i = 0
"""Convert wind speed bins from m/s to fpm (feet per minute).

Returns a new list without modifying the input list.
"""
result = []
for x in sbins:
x = x * 196.85039370078738
sbins[i] = round(x, 1)
i = i + 1
return sbins
if np.isfinite(x):
converted = round(x * 196.85039370078738, 1)
result.append(converted)
else:
result.append(x) # Preserve np.inf
return result


def thermal_stress_stacked_barchart(
Expand Down
3 changes: 0 additions & 3 deletions pages/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,6 @@ def switch_si_ip(_, si_ip_input, url_store, lines):

@callback(
[
Output(ElementIds.NAV, "disabled"),
Output(ElementIds.NAV_SUMMARY, "disabled"),
Output(ElementIds.NAV_T_RH, "disabled"),
Output(ElementIds.NAV_SUN, "disabled"),
Expand Down Expand Up @@ -277,7 +276,6 @@ def enable_tabs_when_data_is_loaded(meta, data):
True,
True,
True,
True,
default,
)
else:
Expand All @@ -290,7 +288,6 @@ def enable_tabs_when_data_is_loaded(meta, data):
False,
False,
False,
False,
"Current Location: "
+ meta[Variables.CITY.col_name]
+ ", "
Expand Down
4 changes: 2 additions & 2 deletions pages/sun.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,15 +286,15 @@ def sun_path_chart(_, view, var, global_local, global_filter_data, df, meta, si_
units = "" if var == "None" else generate_units(si_ip)
if view == "polar":
return dcc.Graph(
style={"width": "100%", "height": "520px"},
style={"maxWidth": "50em", "height": "520px"},
config=generate_chart_name(
TabNames.SPHERICAL_SUNPATH, meta, custom_inputs, units
),
figure=polar_graph(df, meta, global_local, var, si_ip),
)
else:
return dcc.Graph(
style={"width": "100%", "height": "520px"},
style={"maxWidth": "50em", "height": "520px"},
config=generate_chart_name(
TabNames.CARTESIAN_SUNPATH, meta, custom_inputs, units
),
Expand Down
15 changes: 2 additions & 13 deletions tests/test_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,8 @@ def ensure_local_mode_and_invert_off(page: Page):


def open_tools_menu_and_filter_section(page: Page):
"""Open Tools Menu → Filter function, using the simplest reliable click."""
header = page.get_by_text("Tools Menu", exact=False).first
header.scroll_into_view_if_needed()
header.click()

try:
page.get_by_text("Filter function", exact=False).first.click()
except Exception:
pass

expect(
page.get_by_text("Apply month and hour filter", exact=False).first
).to_be_visible()
apply_btn = page.get_by_text("Apply month and hour filter", exact=False)
expect(apply_btn.first).to_be_visible()
ensure_local_mode_and_invert_off(page)


Expand Down
7 changes: 4 additions & 3 deletions tests/test_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,12 @@ def test_unit_switch(page: Page):

# Click the "IP" option
ip_button = page.get_by_text("IP", exact=True)
expect(ip_button).to_be_visible()
ip_button.scroll_into_view_if_needed()
ip_button.wait_for(state="visible")
ip_button.click(force=True)

info_section = page.locator("#location-info")
expect(info_section).to_contain_text("°F")
expect(info_section).to_contain_text("ft")
expect(info_section).to_contain_text("kBtu/ft2")
expect(info_section.get_by_text("°F")).to_be_visible
expect(info_section.get_by_text("ft")).to_be_visible
expect(info_section.get_by_text("kBtu/ft2")).to_be_visible
Loading