Skip to content

Conversation

@FedericoTartarini
Copy link
Contributor

@FedericoTartarini FedericoTartarini commented Nov 7, 2025

Summary by CodeRabbit

  • New Features

    • Unified global month/hour filter available across pages
    • Playwright-based test suites added (Cypress-based tests/workflow removed)
  • Improvements

    • UI migrated to Dash Mantine Components for consistent visual styling
    • Navigation moved to a left sidebar layout
    • Docker build and dependency flow optimized; project version bumped to 0.10.0
  • Documentation

    • Expanded contributing guide and updated changelog

LeoLuosifen and others added 30 commits August 19, 2025 16:52
Sallie00 and others added 25 commits November 4, 2025 14:48
# Conflicts:
#	Pipfile
#	Pipfile.lock
#	docs/contributing/contributing.md
Migrate end-to-end testing framework from Cypress to Playwright
- updated the Menu structure
- centred the Sun and cloud tab
- fixed the Outdoor Comfort / UTCI chart's bar chart
- made the  Apply filter button more visible
- made the dropdown for the filtering is open by default
optimize Playwright tests for faster execution
Fixed the issues of number 1, 3, 5, and 6
- fixed the yearly chart breaking
- fixed the legend color
- removed the grey fill in Cloud coverage, Psychrometric Chart, and the UTCI chart
- extracted the grey fill function
Add grey fill in most of the charts
@coderabbitai
Copy link

coderabbitai bot commented Nov 7, 2025

Walkthrough

Version bumped to 0.10.0. Cypress tests and config removed; Playwright tests and CI steps added. UI migrated from Dash Bootstrap to Dash Mantine Components. Centralized constants and metadata introduced (ElementIds, Variables, TabNames, IdButtons, VariableInfo). Global month/hour filter implemented and threaded through pages; many charts updated to show filtered vs unfiltered traces. Dockerfile switched to Pipenv; many CSS assets removed. Large refactor of data extraction, utilities, and plotting code.

Changes

Cohort / File(s) Summary
Version & Manifest
\.bumpversion.cfg, assets/manifest.json
Bumped version 0.9.0 → 0.10.0; manifest id updated.
Container & Build
Dockerfile, .dockerignore
Dockerfile rewritten to use Pipenv, PYTHONUNBUFFERED, optimized apt install; Pipfile/Pipfile.lock removed from .dockerignore (now copied into image).
CI & Testing infra
.github/workflows/cypress.yml, .github/workflows/python.yml, requirements.txt
Removed Cypress workflow; python.yml updated to install Playwright browsers and start app; requirements.txt removed in favor of Pipenv.
Dependencies
Pipfile
Upgraded Dash (2.15→3.2), dash-mantine-components, added pytest-playwright and pytest-xdist dev deps.
CSS / Assets Removal
assets/banner.css, assets/construction.css, assets/fonts.css, assets/footer.css, assets/layout.css, assets/tabs.css
Large deletions of styling and Google Fonts imports; many layout/tab styles removed.
Config / Minor text
config.py
PageInfo.SELECT_NAME string changed case ("Select Weather File" → "Select weather file").
Documentation
docs/*, docs/contributing/*, docs/version/changelog.md
Contributor list additions; expanded contributing guide (Pipenv, Playwright, gcloud/Docker deploy instructions); changelog/version notes and minor formatting edits.
Main app entry
main.py
Switched app.layout to MantineProvider + create_collapsible_layout; replaced app.run_server(...) with app.run(...); imports updated (ElementIds, create_collapsible_layout).
Global constants & metadata
pages/lib/global_element_ids.py, pages/lib/global_id_buttons.py, pages/lib/global_tab_names.py, pages/lib/global_variables.py
New centralized enums/classes: ElementIds (many UI IDs), IdButtons, TabNames, Variables and VariableInfo (column metadata, SI/IP handling, colors).
Layout & shared UI
pages/lib/layout.py, pages/lib/global_scheme.py
New modular layout builders (create_navbar/header/footer/stores/collapsible layout, NavBarIcons); new stepped colorscale builder and wind_speed_colorscale_rose; dynamic dropdowns populated from Variables/VariableInfo.
Utilities & helpers
pages/lib/utils.py
Many new utilities (get_max_min_value, separate_filtered_data, get_variable_info, get_variable_range, time_filtering, convert_df_units, global filter store helpers, etc.) and refactors to use Variables/VariableInfo.
Data extraction & UTCI
pages/lib/extract_df.py
Added utci_calc, add_utci_variants, add_utci_categories; unit conversion helpers; replaced many literal column names with Variables constants.
Chart libs (explorer/summary/sun/sun-charts)
pages/lib/charts_data_explorer.py, pages/lib/charts_summary.py, pages/lib/charts_sun.py, pages/lib/template_graphs.py
Refactored to use VariableInfo and Variables; introduced filtered vs unfiltered trace handling, get_max_min_value usage, monthly polar/cartesian solar refactors, and time_filtering integrations.
Page rewrites (Mantine + ElementIds + global filter)
pages/explorer.py, pages/natural_ventilation.py, pages/outdoor.py, pages/psy-chart.py, pages/select.py, pages/summary.py, pages/sun.py, pages/t_rh.py, pages/wind.py, pages/not_found_404.py
Migrated from dash_bootstrap_components/html to dash_mantine_components; replaced string IDs with ElementIds; updated many callback signatures to accept global_filter_data and integrated apply_global_month_hour_filter; replaced mapping_dictionary lookups with VariableInfo.
Tests: Cypress removal
tests/node/... (tests/node/cypress.config.js, tests/node/cypress/e2e/spec.cy.js, tests/node/package.json, tests/node/cypress/*)
Removed Cypress config, e2e spec, support files, fixtures, package.json and test EPW reference.
Tests: Playwright suite added
tests/conftest.py, tests/utils.py, tests/test_explorer.py, tests/test_filter.py, tests/test_natural_ventilation.py, tests/test_outdoor.py, tests/test_psy-chart.py, tests/test_select.py, tests/test_summary.py, tests/test_sun.py, tests/test_t_rh.py, tests/test_wind.py
Added Playwright-based tests and helpers (upload_epw_file, open_tab), autouse fixtures, and extensive cross-page UI/filter tests.
Removed Python tests
tests/python/test_utils.py, tests/python/test_utils.py (deleted)
Deleted legacy Python test module that fetched remote EPW and validated summary table.
Tests helper
tests/test_filter.py
New comprehensive Playwright test validating the global month/hour filter affects multiple pages.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Tools Menu (Page)
    participant Store as Tools Global Filter Store
    participant Callback as Page Callback
    participant Utils as Filtering Utils
    participant Chart as Chart Renderer

    UI->>Store: Click "Apply filter" (month/hour, invert flags)
    Store-->>Callback: global_filter_data (filter_active, month_range, hour_range, invert flags)
    Callback->>Utils: apply_global_month_hour_filter(df, global_filter_data)
    Utils-->>Callback: {df_unfiltered, df_filtered, _is_filtered flags}
    alt filtered present
        Callback->>Chart: Render Unfiltered (colored) + Filtered (gray) traces
    else no filtered
        Callback->>Chart: Render Unfiltered only
    end
    Chart-->>UI: Updated chart display
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • pages/lib/extract_df.py — UTCI pipeline, unit conversions, Variables renames and downstream effects.
  • pages/lib/template_graphs.py & pages/lib/charts_* — filtered vs unfiltered trace logic, range calculations, cross-chart consistency.
  • pages/* (explorer, sun, wind, t_rh, outdoor, natural_ventilation) — many callback signature changes and ElementIds wiring; verify Input/Output mapping and PreventUpdate/edge cases.
  • pages/lib/global_variables.py & global_scheme.py — correctness of VariableInfo entries (units, IP overrides, ranges, colors).
  • tests/* — Playwright fixtures rely on app being started and endpoints; ensure CI python.yml starts the app the same way locally/CI.

Possibly related PRs

Poem

🐰 I nibble code and tidy strings,

From Bootstrap nests to Mantine springs,
Filters hop in, months and hours align,
Tests now Playwright—CI feeling fine,
Version bumped, constants centralized—rejoice, little devs, it's rabbit time!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.28% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'filtering data grays out part of the chart' clearly and specifically describes the main visual behavior change—that filtered data sections are displayed in gray. This directly corresponds to the extensive changes implementing gray-colored traces for filtered data across multiple chart types throughout the codebase.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch development

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
pages/lib/template_graphs.py (2)

1267-1273: Do not pass None as the Plotly margin.

tight_margins.copy().update({"t": 55}) mutates in place and returns None, so update_layout(..., margin=None, ...) drops the layout margins entirely. Create a copy, update it, and pass the dict instead (e.g., margins = {**tight_margins, "t": 55}).


1503-1511: Fix the filter description string.

When appending the range summary you concatenate str(min_val) + " and " + str(min_val) + filter_unit, so the max bound and spacing are wrong in the rendered title. Use the real max_val and include a space before the unit.

pages/psy-chart.py (1)

213-218: Don't clobber _is_filtered during the local data filter step.

When a global month/hour filter is active, apply_global_month_hour_filter adds _is_filtered (and original-value columns) so separate_filtered_data can keep filtered points separate. The line df[mask] = None now wipes those helper columns to None, so _is_filtered becomes NA. Downstream we then hit separate_filtered_data(..., Variables.DBT.col_name), and the boolean mask with NA values causes pandas to raise ValueError: cannot mask with non-boolean array containing NA / NaN values (you can repro by enabling the global filter, applying the local min/max filter, and triggering the callback).

Preserve _is_filtered when nulling rows for the local value filter:

-        if min_val <= max_val:
-            mask = (df[data_filter_var] < min_val) | (df[data_filter_var] > max_val)
-            df[mask] = None
+        if min_val <= max_val:
+            mask = (df[data_filter_var] < min_val) | (df[data_filter_var] > max_val)
+            cols_to_clear = [col for col in df.columns if col != "_is_filtered"]
+            df.loc[mask, cols_to_clear] = None

That keeps _is_filtered boolean while still blanking the rows so the chart drops them.

🧹 Nitpick comments (11)
Pipfile (1)

27-28: Unpin test framework versions for reproducibility.

Test dependencies should be version-pinned rather than using wildcard (*). This ensures reproducible test runs across environments.

Apply this diff to pin test framework versions:

 [dev-packages]
 cleanpy = "*"
 pytest = "*"
 bump2version = "*"
 black = "*"
 ruff = "*"
 pre-commit = "*"
-pytest-playwright = "*"
-pytest-xdist = "*"
+pytest-playwright = "==0.50.1"
+pytest-xdist = "==3.6.1"

Note: Replace version numbers with the latest stable versions available at the time of commit.

.github/workflows/python.yml (1)

38-40: Consider capturing background process logs for debugging.

If main.py fails to start, the current setup will wait for the full 60-second timeout before reporting an error. Consider redirecting output to a log file that can be uploaded as an artifact on failure.

Example improvement:

       - name: Start Clima
         run: |-
-          pipenv run python main.py &
+          pipenv run python main.py > clima.log 2>&1 &
+          echo $! > clima.pid

Then add a cleanup step at the end:

       - name: Upload logs on failure
         if: failure()
         uses: actions/upload-artifact@v3
         with:
           name: clima-logs
           path: clima.log
docs/contributing/run-project-locally.md (1)

97-115: LGTM! Comprehensive local deployment workflow.

The manual deployment section provides clear steps for building, testing locally, and deploying. The explicit platform specification (--platform linux/amd64) is important for Apple Silicon compatibility.

Consider adding a brief note about the difference between the two docker run examples (lines 107 vs 109-110) to clarify when to use each approach.

Dockerfile (1)

13-15: Consider using pipenv sync --system for production containers.

Running pipenv inside a Docker container creates an unnecessary virtualenv. For production images, consider adding the --system flag to install packages directly into the system Python.

 # Install dependencies
-RUN pipenv sync
+RUN pipenv sync --system

Alternatively, generate requirements.txt during CI and use standard pip install for smaller image size and faster startup.

config.py (1)

57-57: Correct capitalization to match the title case convention used throughout PageInfo.

The inconsistency is confirmed. SELECT_NAME uses sentence case ("Select weather file"), while all other page names use title case ("Climate Summary", "Temperature and Humidity", etc.). Change line 57 to:

SELECT_NAME = "Select Weather File"
tests/test_select.py (1)

13-26: Consider using centralized ElementIds constants.

The test uses hardcoded strings and CSS selectors to locate UI elements. According to the PR summary, centralized public UI constants (ElementIds, IdButtons, TabNames) have been introduced. Using these constants would make tests more maintainable and resilient to UI changes.

For example, instead of:

expect(page.locator("#alert")).to_contain_text("upload an EPW file")
expect(page.locator("#upload-data-button")).to_be_visible()

Consider importing and using:

from pages.lib.global_element_ids import ElementIds
expect(page.locator(f"#{ElementIds.ALERT}")).to_contain_text("upload an EPW file")
tests/test_outdoor.py (1)

16-39: Consider using centralized ElementIds constants.

Similar to other test files, this test relies on hardcoded strings and CSS selectors. The PR introduces centralized public UI constants (ElementIds, IdButtons) that should be used to make tests more maintainable.

For example, instead of:

expect(page.locator("#image-selection")).to_be_visible()
expect(page.locator("#utci-heatmap")).to_be_visible()

Consider importing and using ElementIds constants to reference these UI elements consistently.

tests/utils.py (1)

28-32: XPath locator may be brittle.

The XPath expression xpath=ancestor::a[1] | ancestor::button[1] assumes a specific DOM structure. While this may be necessary for the Mantine NavLink structure, it could break if the component hierarchy changes.

Consider adding a comment explaining why this XPath traversal is necessary and what DOM structure it expects, to help future maintainers understand the dependency on Mantine's internal structure.

     # Find the navigation link container whose id starts with "nav-" and text matches
     nav_link = page.locator(f'[id^="nav-"] >> text="{tab_name}"').first

+    # Navigate up to the clickable ancestor (a or button) in Mantine NavLink structure
+    # This XPath is coupled to Mantine's internal DOM hierarchy
     # Go up to the clickable element (<a> or <button>)
     clickable = nav_link.locator("xpath=ancestor::a[1] | ancestor::button[1]")
tests/test_wind.py (1)

24-35: Consider using centralized ElementIds constants.

Like the other test files, this test uses hardcoded CSS selectors. The PR introduces centralized ElementIds constants that should be used for better maintainability.

tests/test_sun.py (1)

30-48: Consider using centralized ElementIds constants.

This test, like others in the suite, uses hardcoded CSS selectors. Adopting the centralized ElementIds constants introduced in the PR would improve maintainability and reduce the risk of tests breaking due to UI changes.

tests/test_t_rh.py (1)

16-40: Consider using centralized ElementIds constants.

Following the pattern across the test suite, this test should use the centralized ElementIds constants introduced in the PR rather than hardcoded CSS selectors.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5da6c96 and 514a2a2.

⛔ Files ignored due to path filters (2)
  • Pipfile.lock is excluded by !**/*.lock
  • tests/node/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (75)
  • .bumpversion.cfg (1 hunks)
  • .dockerignore (0 hunks)
  • .github/workflows/cypress.yml (0 hunks)
  • .github/workflows/python.yml (1 hunks)
  • Dockerfile (1 hunks)
  • Pipfile (2 hunks)
  • assets/banner.css (0 hunks)
  • assets/construction.css (0 hunks)
  • assets/fonts.css (0 hunks)
  • assets/footer.css (0 hunks)
  • assets/layout.css (0 hunks)
  • assets/manifest.json (1 hunks)
  • assets/tabs.css (0 hunks)
  • config.py (1 hunks)
  • docs/README.md (1 hunks)
  • docs/contributing/contributing.md (3 hunks)
  • docs/contributing/run-project-locally.md (1 hunks)
  • docs/documentation/tabs-explained/outdoor-comfort/utci-explained.md (1 hunks)
  • docs/documentation/tabs-explained/psychrometric-chart/README.md (1 hunks)
  • docs/documentation/tabs-explained/psychrometric-chart/psychrometric-chart-explained.md (1 hunks)
  • docs/documentation/tabs-explained/sun-and-cloud/README.md (0 hunks)
  • docs/documentation/tabs-explained/sun-and-cloud/cloud-coverage.md (1 hunks)
  • docs/documentation/tabs-explained/sun-and-cloud/customizable-daily-and-hourly-maps.md (0 hunks)
  • docs/documentation/tabs-explained/sun-and-cloud/global-and-diffuse-horizontal-solar-radiation/README.md (1 hunks)
  • docs/documentation/tabs-explained/sun-and-cloud/global-and-diffuse-horizontal-solar-radiation/global-diffuse-and-normal-solar-radiation-explained.md (1 hunks)
  • docs/documentation/tabs-explained/tab-summary/README.md (0 hunks)
  • docs/documentation/tabs-explained/tab-summary/clima-dataframe.md (1 hunks)
  • docs/documentation/tabs-explained/tab-summary/climate-profiles-explained.md (1 hunks)
  • docs/documentation/tabs-explained/tab-summary/degree-days-explained.md (1 hunks)
  • docs/version/changelog.md (1 hunks)
  • main.py (1 hunks)
  • pages/explorer.py (11 hunks)
  • pages/lib/charts_data_explorer.py (6 hunks)
  • pages/lib/charts_summary.py (1 hunks)
  • pages/lib/charts_sun.py (7 hunks)
  • pages/lib/extract_df.py (7 hunks)
  • pages/lib/global_element_ids.py (1 hunks)
  • pages/lib/global_id_buttons.py (1 hunks)
  • pages/lib/global_scheme.py (2 hunks)
  • pages/lib/global_tab_names.py (1 hunks)
  • pages/lib/global_variables.py (1 hunks)
  • pages/lib/layout.py (1 hunks)
  • pages/lib/template_graphs.py (18 hunks)
  • pages/lib/utils.py (10 hunks)
  • pages/natural_ventilation.py (9 hunks)
  • pages/not_found_404.py (2 hunks)
  • pages/outdoor.py (10 hunks)
  • pages/psy-chart.py (9 hunks)
  • pages/select.py (11 hunks)
  • pages/summary.py (6 hunks)
  • pages/sun.py (3 hunks)
  • pages/t_rh.py (2 hunks)
  • pages/wind.py (10 hunks)
  • requirements.txt (0 hunks)
  • tests/conftest.py (1 hunks)
  • tests/node/cypress.config.js (0 hunks)
  • tests/node/cypress/.gitignore (0 hunks)
  • tests/node/cypress/e2e/spec.cy.js (0 hunks)
  • tests/node/cypress/fixtures/example.json (0 hunks)
  • tests/node/cypress/support/commands.js (0 hunks)
  • tests/node/cypress/support/e2e.js (0 hunks)
  • tests/node/package.json (0 hunks)
  • tests/node/test.epw (0 hunks)
  • tests/python/test_utils.py (0 hunks)
  • tests/test_explorer.py (1 hunks)
  • tests/test_filter.py (1 hunks)
  • tests/test_natural_ventilation.py (1 hunks)
  • tests/test_outdoor.py (1 hunks)
  • tests/test_psy-chart.py (1 hunks)
  • tests/test_select.py (1 hunks)
  • tests/test_summary.py (1 hunks)
  • tests/test_sun.py (1 hunks)
  • tests/test_t_rh.py (1 hunks)
  • tests/test_wind.py (1 hunks)
  • tests/utils.py (1 hunks)
💤 Files with no reviewable changes (21)
  • tests/node/cypress/support/e2e.js
  • tests/node/cypress/.gitignore
  • tests/node/test.epw
  • .github/workflows/cypress.yml
  • assets/banner.css
  • tests/node/package.json
  • assets/footer.css
  • assets/construction.css
  • docs/documentation/tabs-explained/sun-and-cloud/customizable-daily-and-hourly-maps.md
  • docs/documentation/tabs-explained/sun-and-cloud/README.md
  • assets/tabs.css
  • tests/node/cypress/e2e/spec.cy.js
  • assets/layout.css
  • tests/node/cypress.config.js
  • tests/node/cypress/support/commands.js
  • tests/python/test_utils.py
  • assets/fonts.css
  • tests/node/cypress/fixtures/example.json
  • .dockerignore
  • requirements.txt
  • docs/documentation/tabs-explained/tab-summary/README.md
🧰 Additional context used
🧬 Code graph analysis (29)
tests/test_outdoor.py (2)
tests/utils.py (2)
  • upload_epw_file (5-20)
  • open_tab (23-37)
tests/conftest.py (1)
  • base_url (5-6)
tests/test_natural_ventilation.py (2)
tests/utils.py (2)
  • upload_epw_file (5-20)
  • open_tab (23-37)
tests/conftest.py (1)
  • base_url (5-6)
tests/test_select.py (2)
tests/utils.py (1)
  • upload_epw_file (5-20)
tests/conftest.py (1)
  • base_url (5-6)
main.py (2)
pages/lib/layout.py (1)
  • create_collapsible_layout (430-466)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
tests/test_summary.py (2)
tests/utils.py (2)
  • upload_epw_file (5-20)
  • open_tab (23-37)
tests/conftest.py (1)
  • base_url (5-6)
tests/test_psy-chart.py (2)
tests/utils.py (2)
  • upload_epw_file (5-20)
  • open_tab (23-37)
tests/conftest.py (1)
  • base_url (5-6)
tests/test_t_rh.py (2)
tests/utils.py (2)
  • upload_epw_file (5-20)
  • open_tab (23-37)
tests/conftest.py (1)
  • base_url (5-6)
tests/test_explorer.py (2)
tests/utils.py (2)
  • upload_epw_file (5-20)
  • open_tab (23-37)
tests/conftest.py (1)
  • base_url (5-6)
tests/test_sun.py (2)
tests/utils.py (2)
  • upload_epw_file (5-20)
  • open_tab (23-37)
tests/conftest.py (1)
  • base_url (5-6)
pages/lib/layout.py (5)
pages/lib/global_variables.py (2)
  • Variables (104-548)
  • IP (55-59)
config.py (2)
  • DocLinks (82-96)
  • UnitSystem (16-20)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/utils.py (3)
  • determine_month_and_hour_filter (300-308)
  • get_default_global_filter_store_data (348-359)
  • get_global_filter_state (362-379)
pages/lib/template_graphs.py (1)
  • time_filtering (1515-1535)
pages/lib/charts_data_explorer.py (2)
pages/lib/utils.py (1)
  • get_max_min_value (327-345)
pages/lib/global_variables.py (7)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_name (74-76)
  • get_unit (78-82)
  • get_range (84-88)
  • get_color (90-92)
pages/lib/extract_df.py (2)
config.py (1)
  • UnitSystem (16-20)
pages/lib/global_variables.py (3)
  • Variables (104-548)
  • VariableInfo (63-101)
  • IP (55-59)
pages/lib/charts_summary.py (1)
pages/lib/global_variables.py (1)
  • Variables (104-548)
tests/test_wind.py (2)
tests/utils.py (2)
  • upload_epw_file (5-20)
  • open_tab (23-37)
tests/conftest.py (1)
  • base_url (5-6)
tests/test_filter.py (3)
tests/utils.py (1)
  • upload_epw_file (5-20)
pages/wind.py (1)
  • sliders (28-64)
tests/conftest.py (1)
  • base_url (5-6)
pages/lib/global_variables.py (1)
config.py (1)
  • UnitSystem (16-20)
pages/lib/utils.py (2)
config.py (1)
  • UnitSystem (16-20)
pages/lib/global_variables.py (7)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_name (74-76)
  • get_unit (78-82)
  • get_range (84-88)
  • get_color (90-92)
pages/summary.py (8)
config.py (2)
  • DocLinks (82-96)
  • UnitSystem (16-20)
pages/lib/charts_summary.py (1)
  • world_map (6-37)
pages/lib/global_variables.py (4)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_unit (78-82)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (5)
  • title_with_tooltip (154-180)
  • title_with_link (183-211)
  • generate_chart_name (30-46)
  • generate_units_degree (57-58)
  • generate_units (49-54)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/lib/charts_sun.py (2)
pages/lib/utils.py (2)
  • get_max_min_value (327-345)
  • separate_filtered_data (399-428)
pages/lib/global_variables.py (7)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_unit (78-82)
  • get_range (84-88)
  • get_name (74-76)
  • get_color (90-92)
pages/select.py (4)
pages/lib/extract_df.py (1)
  • convert_df_units (507-521)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/utils.py (2)
  • generate_chart_name (30-46)
  • get_default_global_filter_store_data (348-359)
pages/outdoor.py (6)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (6)
  • get_time_filter_from_store (382-396)
  • dropdown (311-324)
  • title_with_link (183-211)
  • title_with_tooltip (154-180)
  • generate_units_degree (57-58)
  • generate_chart_name (30-46)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/psy-chart.py (7)
pages/lib/utils.py (7)
  • get_max_min_value (327-345)
  • separate_filtered_data (399-428)
  • dropdown (311-324)
  • title_with_link (183-211)
  • get_global_filter_state (362-379)
  • determine_month_and_hour_filter (300-308)
  • generate_chart_name (30-46)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/global_variables.py (7)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_unit (78-82)
  • get_name (74-76)
  • get_color (90-92)
  • get_range (84-88)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/lib/template_graphs.py (1)
  • filter_df_by_month_and_hour (1538-1565)
pages/lib/global_scheme.py (1)
pages/lib/global_variables.py (4)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_name (74-76)
pages/natural_ventilation.py (7)
pages/lib/global_variables.py (7)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_unit (78-82)
  • get_name (74-76)
  • get_color (90-92)
  • IP (55-59)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (7)
  • separate_filtered_data (399-428)
  • title_with_link (183-211)
  • title_with_tooltip (154-180)
  • get_global_filter_state (362-379)
  • determine_month_and_hour_filter (300-308)
  • generate_chart_name (30-46)
  • has_filtered_data (431-432)
config.py (2)
  • DocLinks (82-96)
  • UnitSystem (16-20)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/t_rh.py (7)
pages/lib/template_graphs.py (3)
  • heatmap (822-933)
  • yearly_profile (93-466)
  • daily_profile (470-643)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (7)
  • dropdown (311-324)
  • title_with_link (183-211)
  • title_with_tooltip (154-180)
  • generate_units_degree (57-58)
  • generate_chart_name (30-46)
  • generate_units (49-54)
  • summary_table_tmp_rh_tab (214-297)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/lib/template_graphs.py (2)
pages/lib/utils.py (10)
  • get_max_min_value (327-345)
  • has_filtered_data (431-432)
  • get_variable_info (435-442)
  • get_variable_range (451-464)
  • get_original_column_values (467-472)
  • calculate_daily_statistics (475-481)
  • unpack_variable_info (445-448)
  • code_timer (15-27)
  • determine_month_and_hour_filter (300-308)
  • separate_filtered_data (399-428)
pages/lib/global_variables.py (7)
  • Variables (104-548)
  • VariableInfo (63-101)
  • IP (55-59)
  • from_col_name (95-101)
  • get_color (90-92)
  • get_unit (78-82)
  • get_name (74-76)
pages/wind.py (7)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/template_graphs.py (2)
  • heatmap (822-933)
  • wind_rose (949-1080)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (3)
  • title_with_link (183-211)
  • generate_units (49-54)
  • generate_chart_name (30-46)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/sun.py (7)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/global_variables.py (2)
  • Variables (104-548)
  • IP (55-59)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (5)
  • title_with_link (183-211)
  • dropdown (311-324)
  • generate_units (49-54)
  • generate_chart_name (30-46)
  • generate_custom_inputs (61-68)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/lib/charts_sun.py (3)
  • monthly_solar (22-260)
  • polar_graph (263-600)
  • custom_cartesian_solar (603-908)
pages/explorer.py (7)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-241)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (9)
  • dropdown (311-324)
  • title_with_link (183-211)
  • title_with_tooltip (154-180)
  • generate_chart_name (30-46)
  • generate_custom_inputs (61-68)
  • generate_units (49-54)
  • get_global_filter_state (362-379)
  • determine_month_and_hour_filter (300-308)
  • summary_table_tmp_rh_tab (214-297)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/lib/template_graphs.py (4)
  • yearly_profile (93-466)
  • daily_profile (470-643)
  • heatmap (822-933)
  • filter_df_by_month_and_hour (1538-1565)
🪛 LanguageTool
docs/contributing/contributing.md

[uncategorized] ~15-~15: Use a comma before “but” if it connects two independent clauses (unless they are closely connected and short).
Context: ...our project, please do not open an issue but instead please fill in this [form](http...

(COMMA_COMPOUND_SENTENCE_3)


[typographical] ~15-~15: Consider adding a comma here.
Context: ... please do not open an issue but instead please fill in this [form](https://forms.gle/L...

(PLEASE_COMMA)


[uncategorized] ~19-~19: The official name of this software platform is spelled with a capital “H”.
Context: ... fork the origin repository to your own github repository, then clone the repository t...

(GITHUB)


[uncategorized] ~73-~73: Possible missing comma found.
Context: ...git checkout -b (your branch name) ``` Finally update and push to your repository bran...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~153-~153: Loose punctuation mark.
Context: ... Common Commit Types: - Main (Master): Stable branch, merge code that passes r...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~155-~155: Loose punctuation mark.
Context: ...th multiple collaborators. - Feature/*: feature development branch, cut out fro...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~156-~156: Loose punctuation mark.
Context: ... after completing the feature. - Fix/*: defect repair branch, the same process ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~158-~158: Loose punctuation mark.
Context: ...oing regressions and tagging. - docs/*, chore/*, refactor/*, test/*: docu...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~159-~159: Loose punctuation mark.
Context: ... refactor, test type branches. - Style: style modification (does not affect the...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~160-~160: Loose punctuation mark.
Context: ...stment, naming rules unity. - Refactor: Code Refactoring: Refactor existing cod...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~161-~161: Loose punctuation mark.
Context: ...ode to improve maintainability. - Test: Add or modify tests: add unit tests, in...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~162-~162: Loose punctuation mark.
Context: ...n tests, or modify test logic. - Chore: Build Configuration, Dependency Managem...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~163-~163: Loose punctuation mark.
Context: ...t, CI/CD Configuration Updates. - Perf: Performance Optimisation: Optimising co...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~164-~164: Loose punctuation mark.
Context: ...ution efficiency or memory usage. - Ci: CI Configuration Related: Changing Cont...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~164-~164: The official name of this software platform is spelled with a capital “H”.
Context: ...ntinuous Integration Configurations for Github Actions, Travis, Jenkins, etc. - `Build...

(GITHUB)


[uncategorized] ~166-~166: Loose punctuation mark.
Context: ...pts, packaging configuration. - Revert: Rollback Commit: Undoing a Previous Com...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~168-~168: Loose punctuation mark.
Context: ...ependencies to prevent attacks. - Deps: Dependency Management: Dependency Manag...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~175-~175: Do not mix variants of the same word (‘minimise’ and ‘minimize’) within a single text.
Context: ...s has been reached. - Changes have been minimised (small steps/phased submission) to avoi...

(EN_WORD_COHERENCY)

🪛 markdownlint-cli2 (0.18.1)
docs/contributing/contributing.md

55-55: Hard tabs
Column: 3

(MD010, no-hard-tabs)


56-56: Hard tabs
Column: 3

(MD010, no-hard-tabs)


57-57: Hard tabs
Column: 3

(MD010, no-hard-tabs)


82-82: Link text should be descriptive

(MD059, descriptive-link-text)

docs/documentation/tabs-explained/psychrometric-chart/README.md

25-25: Bare URL used

(MD034, no-bare-urls)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: pytest
🔇 Additional comments (26)
docs/documentation/tabs-explained/tab-summary/degree-days-explained.md (1)

15-15: Clarify the purpose of this no-op change.

Line 15 appears to be a no-op modification (removed and re-added identically per the AI summary), and this documentation file appears unrelated to the PR's stated objective about filtering data graying out part of the chart. Please confirm whether this change was intentional or if it was included by accident.

docs/documentation/tabs-explained/psychrometric-chart/README.md (1)

25-25: Static analysis warning appears to be a false positive.

The line contains a Gitbook embed tag ({% embed %}), not a bare URL in markdown syntax. Markdownlint's warning (MD034) is incorrectly flagging the URL inside the embed directive.

Since this is a formatting-only change (removing trailing whitespace) and the embed syntax is correct for Gitbook, this can be safely merged without modification.

docs/documentation/tabs-explained/sun-and-cloud/cloud-coverage.md (1)

21-21: Image asset verified; documentation change is valid.

The image asset at the referenced path exists and resolves correctly. The documentation change is properly formatted with a valid asset reference.

Note: While this is a valid documentation update, verify with the PR author whether including this file in a PR focused on chart filtering/graying is intentional.

docs/documentation/tabs-explained/sun-and-cloud/global-and-diffuse-horizontal-solar-radiation/README.md (1)

14-15: Documentation formatting only.

This change is a trailing newline addition with no semantic impact on documentation content.

docs/documentation/tabs-explained/psychrometric-chart/psychrometric-chart-explained.md (1)

30-31: Documentation formatting only.

This change is a trailing newline addition with no semantic impact on documentation content.

docs/documentation/tabs-explained/outdoor-comfort/utci-explained.md (1)

20-21: Documentation formatting only.

This change is a trailing newline addition with no semantic impact on documentation content.

docs/documentation/tabs-explained/tab-summary/climate-profiles-explained.md (1)

18-18: No-op image reference change.

The image reference line was removed and re-added identically; this appears to be a formatting or merge artifact with no semantic impact.

assets/manifest.json (1)

470-470: Version bump is consistent with release.

The manifest "id" field has been correctly updated to align with the 0.10.0 release.

Pipfile (1)

7-7: Verify Dash 3.2 and dash-mantine-components 2.2.1 compatibility.

The upgrade from Dash 2.15 to 3.2 and from dash-mantine-components 0.12.1 to 2.2.1 are major version changes. These upgrades likely introduce breaking changes that need to be validated in the application code (not provided in the current review context).

Confirm that:

  1. Application code properly handles Dash 3.2 breaking changes
  2. dash-mantine-components 2.2.1 API changes are reflected throughout the codebase
  3. No compatibility issues exist with other pinned dependencies (e.g., plotly==5.18.0, pandas==2.2.0)

Also applies to: 12-12

docs/README.md (1)

37-42: New contributors added with consistent formatting.

The six new contributors have been properly added to the contributions list with consistent formatting and roles. Note that some contributors lack associated URLs (GitHub or LinkedIn), which is consistent with pre-existing patterns in the contributor list (see line 32: Yunzhu Ji).

Please verify that:

  1. All contributor names and profiles are accurate
  2. Any missing profile URLs (for Wenshu lyu, Ziqi Liu, Tianchi Liu, Feng Wang) are intentional or should be added
docs/documentation/tabs-explained/tab-summary/clima-dataframe.md (1)

32-32: No-op variable reference change.

The "Saturation pressure" bullet was removed and re-added identically; this appears to be a merge or rebase artifact with no semantic impact.

.bumpversion.cfg (1)

2-2: LGTM! Version bump is consistent with PR scope.

The version increment to 0.10.0 aligns with the major changes in this PR (testing framework migration, UI library migration, global filters).

.github/workflows/python.yml (3)

34-36: LGTM! Efficient browser installation.

Installing only chromium keeps CI execution time minimal while providing adequate test coverage.


42-44: LGTM! Robust health check implementation.

The 60-second timeout with curl health checks is appropriate for ensuring the service is ready before running tests.


48-49: LGTM! Clean test execution setup.

The test command properly isolates the test directory and passes the base URL as a parameter.

pages/not_found_404.py (1)

16-16: LGTM! Proper Dash Mantine Components API usage.

The updates from className="mb-2" to mb="sm" and leftIcon to leftSection align with the Dash Mantine Components migration mentioned in the PR summary.

Also applies to: 30-30

docs/version/changelog.md (1)

3-16: LGTM! Comprehensive changelog entry.

The Version 0.9.0 entry appropriately documents the migration to Playwright, UI changes, and bug fixes. The date (2025-10-30) is consistent with this PR being prepared for the next version (0.10.0).

docs/contributing/run-project-locally.md (1)

119-119: LGTM! Better syntax highlighting.

Changing code blocks from text to bash improves readability and provides proper syntax highlighting.

Also applies to: 125-125

Dockerfile (4)

5-6: LGTM! Essential for containerized logging.

PYTHONUNBUFFERED=True ensures that Python logs appear immediately in Cloud Run/Docker logs without buffering.


8-11: LGTM! Efficient package installation.

The consolidated apt-get command with --no-install-recommends and cleanup in the same layer follows Docker best practices for minimal image size.


16-25: LGTM! Optimal layer caching strategy.

Copying Pipfile and Pipfile.lock before the application code ensures that dependency installation is cached and only re-runs when dependencies change. This significantly speeds up builds during development.


29-29: LGTM! Consistent with Pipenv workflow.

The CMD correctly uses pipenv run to execute within the Pipenv-managed environment. If you adopt the --system flag suggestion above, this should be updated to CMD ["python", "main.py"].

tests/conftest.py (1)

4-6: LGTM!

The session-scoped base_url fixture is correctly implemented and provides a clean way to access the application base URL across all tests.

pages/lib/charts_summary.py (1)

8-12: Excellent refactoring to centralized constants.

The migration from hardcoded dictionary keys to Variables constants improves maintainability and consistency across the codebase. This change aligns well with the PR's goal of introducing centralized global constants.

tests/test_wind.py (1)

38-46: The review comment is incorrect—"Sep and Dec" is the correct expected value.

The implementation in pages/wind.py (lines 350-353) explicitly defines fall_months = [9, 12], which correctly corresponds to September and December. The test expectations in tests/test_wind.py line 42 accurately reflect this. December appearing in both winter and fall (see winter_months = [12, 2] on line 350) is intentional and represents a valid meteorological/seasonal convention where months overlap or serve as boundary markers.

Likely an incorrect or invalid review comment.

pages/lib/global_element_ids.py (1)

229-241: Well-structured tools menu section.

This section demonstrates good practices with consistent prefixing (TOOLS_ for enum names, "tools-" for values) and clear delineation. All IDs are unique within this section, which contrasts with the duplicate issues found earlier in the file.

Comment on lines +631 to +637
if global_filter_data and global_filter_data.get("filter_active", False):
from pages.lib.layout import apply_global_month_hour_filter

df = apply_global_month_hour_filter(df, global_filter_data)
else:
# Use local filtering when global filter is not active
df = filter_df_by_month_and_hour(df, True, [1, 12], [0, 24], [], [], df.columns)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Global filter isn’t applied to the scatter inputs

apply_global_month_hour_filter defaults to filtering only DBT. Because we don’t pass var_x, var_y, color_by (or the optional data-filter variable), rows outside the global month/hour window still carry valid values for those fields, so the two-/three-variable charts continue to plot the unfiltered data.
Please forward the plotted columns into the filter call.

-        df = apply_global_month_hour_filter(df, global_filter_data)
+        target_cols = {
+            var_x,
+            var_y,
+            color_by,
+            data_filter_var,
+        }
+        target_cols.discard(None)
+        df = apply_global_month_hour_filter(
+            df,
+            global_filter_data,
+            list(target_cols),
+        )

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
tests/test_summary.py (1)

91-93: Call the Playwright assertion methods.

The assertions reference to_be_visible without calling it, so the expectations never run and the test passes even if the unit switch fails.

Apply this diff to invoke the assertion methods:

-    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
+    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()
pages/explorer.py (2)

631-636: Scatter plots ignore the global filter (still outstanding).

This is the same gap flagged earlier: calling apply_global_month_hour_filter without the plotted columns means only DBT gets masked. var_x, var_y, color_by, and the optional filter variable keep their values, so both scatter charts continue to render the unfiltered rows. Please forward every plotted column into the filter.

-        df = apply_global_month_hour_filter(df, global_filter_data)
+        target_cols = {var_x, var_y, color_by, data_filter_var}
+        target_cols.discard(None)
+        df = apply_global_month_hour_filter(
+            df,
+            global_filter_data,
+            list(target_cols),
+        )

449-453: Heatmap still shows unfiltered data.

Same issue here: without supplying the chosen var, the global month/hour filter only blanks DBT, leaving the actual heatmap variable untouched. Users therefore see gray overlay plus the full dataset, defeating the filter. Pass the selected variable into apply_global_month_hour_filter.

-        df = apply_global_month_hour_filter(df, global_filter_data)
+        df = apply_global_month_hour_filter(df, global_filter_data, var)
🧹 Nitpick comments (5)
docs/contributing/contributing.md (5)

54-58: Replace hard tabs with spaces for markdown consistency.

Lines 55–57 use hard tabs for indentation; markdown linters prefer spaces. This is a minor formatting fix but helps maintain consistency across the documentation.

Replace the hard tabs with spaces (typically 2–4 spaces per indent level) in the git output block.


19-19: Capitalize "GitHub" consistently.

Lines 19 and 164 refer to "github" and "Github" respectively; the official brand is "GitHub" (always capitalized). Apply this minor polish for consistency and brand respect.

- your own github repository
+ your own GitHub repository
- - `Ci`: CI Configuration Related: Changing Continuous Integration Configurations for Github Actions, Travis, Jenkins, etc.
+ - `Ci`: CI Configuration Related: Changing Continuous Integration Configurations for GitHub Actions, Travis, Jenkins, etc.

Also applies to: 164-164


82-82: Use descriptive link text for accessibility.

Link text "here" is not descriptive for screen readers. Consider a more informative label.

- Available [here](code_of_conduct.md)
+ Review our [Code of Conduct](code_of_conduct.md)

15-15: Minor grammar: Add comma before "but".

Consider adding a comma before "but" for clarity: "...do not open an issue, but instead please fill in this form..."

- If you have a general feedback about our project, please do not open an issue but instead please fill in this [form](https://forms.gle/LRUq3vsFnE1QCLiA6)
+ If you have a general feedback about our project, please do not open an issue, but instead please fill in this [form](https://forms.gle/LRUq3vsFnE1QCLiA6)

175-175: Standardize spelling to American English.

Line 175 uses "minimised" (British); the rest of the documentation uses American English. Consider standardizing to "minimized" for consistency.

- - Changes have been minimised (small steps/phased submission) to avoid "mega PRs".
+ - Changes have been minimized (small steps/phased submission) to avoid "mega PRs".
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 514a2a2 and bca6dbb.

📒 Files selected for processing (17)
  • docs/contributing/contributing.md (3 hunks)
  • docs/contributing/run-project-locally.md (1 hunks)
  • pages/explorer.py (11 hunks)
  • pages/lib/global_element_ids.py (1 hunks)
  • pages/lib/layout.py (1 hunks)
  • pages/natural_ventilation.py (9 hunks)
  • pages/outdoor.py (10 hunks)
  • pages/psy-chart.py (9 hunks)
  • pages/select.py (11 hunks)
  • pages/summary.py (6 hunks)
  • pages/sun.py (3 hunks)
  • pages/t_rh.py (2 hunks)
  • pages/wind.py (10 hunks)
  • tests/test_select.py (1 hunks)
  • tests/test_summary.py (1 hunks)
  • tests/test_t_rh.py (1 hunks)
  • tests/utils.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • docs/contributing/run-project-locally.md
  • tests/test_select.py
  • tests/utils.py
  • tests/test_t_rh.py
🧰 Additional context used
🧬 Code graph analysis (11)
pages/summary.py (5)
pages/lib/charts_summary.py (1)
  • world_map (6-37)
pages/lib/template_graphs.py (1)
  • violin (22-89)
pages/lib/global_variables.py (4)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_unit (78-82)
pages/lib/utils.py (3)
  • generate_chart_name (30-46)
  • generate_units_degree (57-58)
  • generate_units (49-54)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/psy-chart.py (7)
pages/lib/utils.py (7)
  • get_max_min_value (327-345)
  • separate_filtered_data (399-428)
  • dropdown (311-324)
  • title_with_link (183-211)
  • get_global_filter_state (362-379)
  • determine_month_and_hour_filter (300-308)
  • generate_chart_name (30-46)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-202)
pages/lib/global_variables.py (7)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_unit (78-82)
  • get_name (74-76)
  • get_color (90-92)
  • get_range (84-88)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/lib/template_graphs.py (1)
  • filter_df_by_month_and_hour (1538-1565)
pages/lib/layout.py (5)
pages/lib/global_variables.py (2)
  • Variables (104-548)
  • IP (55-59)
config.py (2)
  • DocLinks (82-96)
  • UnitSystem (16-20)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-202)
pages/lib/utils.py (3)
  • determine_month_and_hour_filter (300-308)
  • get_default_global_filter_store_data (348-359)
  • get_global_filter_state (362-379)
pages/lib/template_graphs.py (1)
  • time_filtering (1515-1535)
pages/wind.py (7)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-202)
pages/lib/template_graphs.py (2)
  • heatmap (822-933)
  • wind_rose (949-1080)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (3)
  • title_with_link (183-211)
  • generate_units (49-54)
  • generate_chart_name (30-46)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/t_rh.py (8)
pages/lib/template_graphs.py (3)
  • heatmap (822-933)
  • yearly_profile (93-466)
  • daily_profile (470-643)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-202)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (6)
  • dropdown (311-324)
  • title_with_link (183-211)
  • title_with_tooltip (154-180)
  • generate_chart_name (30-46)
  • generate_units (49-54)
  • summary_table_tmp_rh_tab (214-297)
pages/explorer.py (2)
  • layout (63-68)
  • update_table (697-726)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
tests/test_summary.py (2)
tests/utils.py (2)
  • upload_epw_file (5-23)
  • open_tab (26-40)
tests/conftest.py (1)
  • base_url (5-6)
pages/select.py (5)
pages/lib/extract_df.py (4)
  • convert_df_units (507-521)
  • create_df (145-440)
  • get_data (26-49)
  • get_location_info (53-77)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-202)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (2)
  • generate_chart_name (30-46)
  • get_default_global_filter_store_data (348-359)
pages/outdoor.py (7)
config.py (1)
  • DocLinks (82-96)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-202)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (6)
  • get_time_filter_from_store (382-396)
  • dropdown (311-324)
  • title_with_link (183-211)
  • title_with_tooltip (154-180)
  • generate_units_degree (57-58)
  • generate_chart_name (30-46)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/natural_ventilation.py (6)
pages/lib/global_variables.py (7)
  • Variables (104-548)
  • VariableInfo (63-101)
  • from_col_name (95-101)
  • get_unit (78-82)
  • get_name (74-76)
  • get_color (90-92)
  • IP (55-59)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-202)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (4)
  • separate_filtered_data (399-428)
  • get_global_filter_state (362-379)
  • determine_month_and_hour_filter (300-308)
  • generate_chart_name (30-46)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/sun.py (7)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-202)
pages/lib/global_variables.py (2)
  • Variables (104-548)
  • IP (55-59)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (4)
  • title_with_link (183-211)
  • dropdown (311-324)
  • generate_units (49-54)
  • generate_chart_name (30-46)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/lib/charts_sun.py (3)
  • monthly_solar (22-260)
  • polar_graph (263-600)
  • custom_cartesian_solar (603-908)
pages/explorer.py (7)
pages/lib/global_element_ids.py (1)
  • ElementIds (4-202)
pages/lib/global_variables.py (1)
  • Variables (104-548)
pages/lib/global_id_buttons.py (1)
  • IdButtons (1-29)
pages/lib/global_tab_names.py (1)
  • TabNames (1-47)
pages/lib/utils.py (9)
  • dropdown (311-324)
  • title_with_link (183-211)
  • title_with_tooltip (154-180)
  • generate_chart_name (30-46)
  • generate_custom_inputs (61-68)
  • generate_units (49-54)
  • get_global_filter_state (362-379)
  • determine_month_and_hour_filter (300-308)
  • summary_table_tmp_rh_tab (214-297)
pages/lib/layout.py (1)
  • apply_global_month_hour_filter (565-621)
pages/lib/template_graphs.py (4)
  • yearly_profile (93-466)
  • daily_profile (470-643)
  • heatmap (822-933)
  • filter_df_by_month_and_hour (1538-1565)
🪛 LanguageTool
docs/contributing/contributing.md

[uncategorized] ~15-~15: Use a comma before “but” if it connects two independent clauses (unless they are closely connected and short).
Context: ...our project, please do not open an issue but instead please fill in this [form](http...

(COMMA_COMPOUND_SENTENCE_3)


[typographical] ~15-~15: Consider adding a comma here.
Context: ... please do not open an issue but instead please fill in this [form](https://forms.gle/L...

(PLEASE_COMMA)


[uncategorized] ~19-~19: The official name of this software platform is spelled with a capital “H”.
Context: ... fork the origin repository to your own github repository, then clone the repository t...

(GITHUB)


[uncategorized] ~73-~73: Possible missing comma found.
Context: ...git checkout -b ``` Finally update and push to your repository bran...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~153-~153: Loose punctuation mark.
Context: ... Common Commit Types: - Main (Master): Stable branch, merge code that passes r...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~155-~155: Loose punctuation mark.
Context: ...th multiple collaborators. - Feature/*: feature development branch, cut out fro...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~156-~156: Loose punctuation mark.
Context: ... after completing the feature. - Fix/*: defect repair branch, the same process ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~158-~158: Loose punctuation mark.
Context: ...oing regressions and tagging. - docs/*, chore/*, refactor/*, test/*: docu...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~159-~159: Loose punctuation mark.
Context: ... refactor, test type branches. - Style: style modification (does not affect the...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~160-~160: Loose punctuation mark.
Context: ...stment, naming rules unity. - Refactor: Code Refactoring: Refactor existing cod...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~161-~161: Loose punctuation mark.
Context: ...ode to improve maintainability. - Test: Add or modify tests: add unit tests, in...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~162-~162: Loose punctuation mark.
Context: ...n tests, or modify test logic. - Chore: Build Configuration, Dependency Managem...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~163-~163: Loose punctuation mark.
Context: ...t, CI/CD Configuration Updates. - Perf: Performance Optimisation: Optimising co...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~164-~164: Loose punctuation mark.
Context: ...ution efficiency or memory usage. - Ci: CI Configuration Related: Changing Cont...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~164-~164: The official name of this software platform is spelled with a capital “H”.
Context: ...ntinuous Integration Configurations for Github Actions, Travis, Jenkins, etc. - `Build...

(GITHUB)


[uncategorized] ~166-~166: Loose punctuation mark.
Context: ...pts, packaging configuration. - Revert: Rollback Commit: Undoing a Previous Com...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~168-~168: Loose punctuation mark.
Context: ...ependencies to prevent attacks. - Deps: Dependency Management: Dependency Manag...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~175-~175: Do not mix variants of the same word (‘minimise’ and ‘minimize’) within a single text.
Context: ...s has been reached. - Changes have been minimised (small steps/phased submission) to avoi...

(EN_WORD_COHERENCY)

🪛 markdownlint-cli2 (0.18.1)
docs/contributing/contributing.md

55-55: Hard tabs
Column: 3

(MD010, no-hard-tabs)


56-56: Hard tabs
Column: 3

(MD010, no-hard-tabs)


57-57: Hard tabs
Column: 3

(MD010, no-hard-tabs)


82-82: Link text should be descriptive

(MD059, descriptive-link-text)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: pytest
🔇 Additional comments (3)
docs/contributing/contributing.md (1)

17-78: Previous issues have been resolved—LGTM!

The git commands and examples now use angle-bracket placeholders (<your-account-name>, <your-branch-name>) instead of spaces or parentheses, making them paste-friendly and correct. The typo in git checkout has been fixed. These changes align well with contributor usability.

pages/lib/global_element_ids.py (1)

1-202: LGTM: Centralized ID constants follow a clean pattern.

The consolidation of shared store IDs (SHARED_DF_STORE, SHARED_META_STORE, etc.) addresses the previous concern about duplicate values. The enum structure provides type safety and a single source of truth for element IDs across the application.

pages/wind.py (1)

500-505: Confirmed: Noon wind rose bug has been fixed.

The previous critical issue where noon_df incorrectly filtered on morning_times has been resolved. The code now correctly uses noon_times[0] and noon_times[1] to select hours 14-21 for the noon wind rose.

Comment on lines +415 to +419
if global_filter_data and global_filter_data.get("filter_active", False):
from pages.lib.layout import apply_global_month_hour_filter

df = apply_global_month_hour_filter(df, global_filter_data)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Global filter bypasses the daily chart variable.

apply_global_month_hour_filter defaults to masking only Variables.DBT. Because we don’t pass the selected var, any variable other than DBT (e.g. humidity, solar radiation) keeps its original data, so the daily profile continues to plot the unfiltered time range. Forward the dropdown selection into the filter call.

-        df = apply_global_month_hour_filter(df, global_filter_data)
+        df = apply_global_month_hour_filter(df, global_filter_data, var)
🤖 Prompt for AI Agents
In pages/explorer.py around lines 415–419 the global filter is applied without
passing the currently selected variable from the dropdown, so
apply_global_month_hour_filter only masks Variables.DBT by default and other
variables remain unfiltered; forward the selected variable (the dropdown value
used to pick the daily chart variable—e.g., var or selected_var in this file) as
an argument into apply_global_month_hour_filter when calling it, and update the
call site (and adjust the apply_global_month_hour_filter signature if necessary)
so the function uses that passed variable to build its mask instead of
defaulting to DBT.

Comment on lines +37 to +42
def _safe_get_column(df, column_name, default_value=0):
if column_name in df.columns:
return df[column_name]
else:
return [default_value] * len(df)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove unused helper function.

The _safe_get_column function is defined but never called anywhere in this file. Remove it to reduce clutter.

-def _safe_get_column(df, column_name, default_value=0):
-    if column_name in df.columns:
-        return df[column_name]
-    else:
-        return [default_value] * len(df)
-
-
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _safe_get_column(df, column_name, default_value=0):
if column_name in df.columns:
return df[column_name]
else:
return [default_value] * len(df)
🤖 Prompt for AI Agents
In pages/psy-chart.py around lines 37 to 42, the helper function
_safe_get_column is defined but never used; delete the entire function
definition (the def block) and any now-unnecessary surrounding blank lines to
remove clutter; run tests/lint to ensure no references remain and commit the
removal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants