Add conditions_plot module for survey condition visualization#43
Conversation
Co-authored-by: SBFRF <8375832+SBFRF@users.noreply.github.com>
Co-authored-by: SBFRF <8375832+SBFRF@users.noreply.github.com>
Co-authored-by: SBFRF <8375832+SBFRF@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds a new plotting module to visualize environmental conditions during surveys or operations, based on operational needs from the ASV conditions plotting work. The implementation provides a flexible two-panel plot showing time series and scatter distributions with climatological context.
Changes:
- New
plottingmodule withconditions_plot()andbin_data()functions - Support for flexible variable selection (default: wave height vs peak period)
- Multiple survey groups with customizable styling (colors, markers, labels)
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| murgtools/plotting/conditions_plot.py | Core implementation of conditions plotting with 295 lines of code |
| murgtools/plotting/init.py | Module initialization exporting main functions |
| murgtools/plotting/README.md | Comprehensive documentation with usage examples |
| murgtools/init.py | Updated to expose new plotting functions at package level |
| tests/test_conditions_plot.py | 11 unit tests covering basic functionality, edge cases, and error handling |
| examples/example_conditions_plot.py | Demonstration script with 6 usage examples |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| all_dates = [dt.datetime(2023, 6, 15), dt.datetime(2023, 6, 20), | ||
| dt.datetime(2023, 7, 10), dt.datetime(2023, 7, 15)] | ||
|
|
||
| # fig, axes = conditions_plot( |
There was a problem hiding this comment.
Fixed in commit 838caed. Refactored the entire example file to use clean, importable functions instead of commented-out code. The examples are now properly structured and can be run individually.
| # ) | ||
|
|
||
| # Example 6: Color by scalar value (if available in data) | ||
| print("\nExample 6: Color by scalar value") |
There was a problem hiding this comment.
Most of these examples are commented out. I don't think it's good practice to do this right?
There was a problem hiding this comment.
Fixed in commit 838caed. Removed all commented code and restructured as individual example functions that can be imported and run. Much cleaner approach.
There was a problem hiding this comment.
Link this file to the overall readme
There was a problem hiding this comment.
Fixed in commit 838caed. Added link to murgtools/plotting/README.md in the Package Structure section and included a quick start example for conditions_plot.
Co-authored-by: SBFRF <8375832+SBFRF@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| else: | ||
| # Process dates in each group | ||
| for group in date_groups: | ||
| processed_dates = [] | ||
| for d in group['dates']: | ||
| if isinstance(d, str): | ||
| processed_dates.append(dt.datetime.strptime(d, '%Y%m%d')) | ||
| elif isinstance(d, dt.datetime): | ||
| processed_dates.append(d) | ||
| else: | ||
| raise ValueError(f"Unsupported date format: {type(d)}") | ||
| group['dates'] = processed_dates | ||
| # Set default marker if not provided | ||
| if 'marker' not in group: | ||
| group['marker'] = 'o' |
There was a problem hiding this comment.
When date_groups is provided, the code doesn't validate that each group dictionary contains the required keys ('dates', 'label', 'color'). Missing keys will cause KeyError exceptions later (e.g., at lines 225, 227). Consider adding validation after line 196 to check for required keys and provide helpful error messages if they're missing.
There was a problem hiding this comment.
Implemented in commit 70ae4fd. Added _validate_date_groups() function that checks for required keys ('dates', 'label', 'color') and validates that 'dates' is a list. The function provides clear error messages indicating which keys are missing.
| np.ceil(np.nanmax(data_to_be_binned)) + bin_size, | ||
| bin_size) | ||
| # np.digitize returns 1-based indices, convert to 0-based for Python consistency | ||
| bin_indices = np.digitize(data_to_be_binned, bins=bins, right=False) - 1 |
There was a problem hiding this comment.
The bin_data function has a potential bug with values exactly equal to np.nanmin(data_to_be_binned). Since bins start at np.nanmin(data_to_be_binned), the minimum value in the data will fall exactly on the first bin edge. With right=False in np.digitize, this value gets index 0, which becomes -1 after subtracting 1. This negative index will cause issues in the binning loop (lines 167-174 of conditions_plot.py) where it's used as 'idx_bins == ii'. Consider starting bins slightly below the minimum value, e.g., 'np.nanmin(data_to_be_binned) - bin_size/2' or handling the edge case explicitly.
| bin_indices = np.digitize(data_to_be_binned, bins=bins, right=False) - 1 | |
| bin_indices = np.digitize(data_to_be_binned, bins=bins, right=False) - 1 | |
| # Guard against values equal to the minimum falling below the first bin (index -1) | |
| bin_indices[bin_indices < 0] = 0 |
There was a problem hiding this comment.
Fixed in commit 70ae4fd. Added guard to prevent negative indices: bin_indices[bin_indices < 0] = 0 after the digitize operation. This ensures values equal to the minimum bin edge are correctly assigned to index 0.
| if len(date_groups) == 1: # Only add colorbar if single group | ||
| cbar = plt.colorbar(scatter, ax=ax2) | ||
| cbar.set_label(color_var) |
There was a problem hiding this comment.
When using color_var with multiple date groups, no colorbar is created (line 272 condition is False). This means users cannot see what the color values represent. Consider either: (1) adding a single colorbar for all groups combined, (2) documenting this limitation in the docstring, or (3) raising a warning when color_var is used with multiple groups.
There was a problem hiding this comment.
lets do a single colorbar for all groups combined
There was a problem hiding this comment.
Implemented in commit 70ae4fd. Changed the colorbar logic to create a single colorbar for all groups when color_var is used. The colorbar now uses the first scatter collection and displays outside the loop, showing the color scale for all groups combined.
| start_date = dt.datetime(2023, 6, 1) | ||
| end_date = dt.datetime(2023, 6, 30) | ||
|
|
||
| fig, axes = conditions_plot(time_list, start_date, end_date, ofname='test_output.png') |
There was a problem hiding this comment.
Variable fig is not used.
| fig, axes = conditions_plot(time_list, start_date, end_date, ofname='test_output.png') | |
| conditions_plot(time_list, start_date, end_date, ofname='test_output.png') |
There was a problem hiding this comment.
Fixed in commit 70ae4fd. Changed to _, _ = conditions_plot(...) pattern to explicitly indicate both return values are intentionally unused.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| if len(date_groups) == 1: # Only add colorbar if single group | ||
| cbar = plt.colorbar(scatter, ax=ax2) | ||
| cbar.set_label(color_var) |
There was a problem hiding this comment.
lets do a single colorbar for all groups combined
| start_date = dt.datetime(2023, 6, 1) | ||
| end_date = dt.datetime(2023, 6, 30) | ||
|
|
||
| fig, axes = conditions_plot(time_list, start_date, end_date, ofname='test_output.png') |
…olorbar Co-authored-by: SBFRF <8375832+SBFRF@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
this was not meant to be part of this PR or branch
…onditions_plot.py
The tests were failing on Python 3.9 and 3.10 due to a naming collision: the module `conditions_plot.py` exports a function also named `conditions_plot`, causing mock.patch to find the function instead of the module when resolving the patch path. Fix by using sys.modules to get the actual module object for patching, and add real test implementations for bin_data tests. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Example script demonstrating conditions_plot with real ASV survey dates from https://github.com/kkoetje/asv_conditions_plot Includes examples for: - Individual platform analysis (Jaiabot, Yellowfin) - Combined platform comparison with different markers/colors - Coloring by wave direction - Full multi-year record analysis Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
✅ Implementation Complete: Conditions Plot Module
Summary
Successfully implemented a flexible conditions plotting module for murgtools that creates comprehensive visualizations of environmental conditions during surveys or operations.
Latest Changes (this commit):
_validate_date_groups()function to validate required keys in date_groups_, _pattern instead of unused variables📁 Files Modified
murgtools/plotting/conditions_plot.py- Added validation, fixed edge cases, improved colorbartests/test_conditions_plot.py- Fixed unused variable patternFEATURE_ISSUE_CONTINUOUS_SAMPLING.md- Feature request document with 3 implementation options🧪 Testing & Quality
📚 Documentation
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.