-
Notifications
You must be signed in to change notification settings - Fork 9
Feature: fxplot Plotting Accessor #548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: fxplot Plotting Accessor #548
Conversation
…ation, reducing code duplication while maintaining the same functionality (data preparation, color resolution from components, PlotResult wrapping).
… area(), and duration_curve() methods in both DatasetPlotAccessor and DataArrayPlotAccessor
2. scatter() method - Plots two variables against each other with x and y parameters
3. pie() method - Creates pie charts from aggregated (scalar) dataset values, e.g. ds.sum('time').fxplot.pie()
4. duration_curve() method - Sorts values along the time dimension in descending order, with optional normalize parameter for percentage x-axis
5. CONFIG.Plotting.default_line_shape - New config option (default 'hv') that controls the default line shape for line(), area(), and duration_curve() methods
1. X-axis is now determined first using CONFIG.Plotting.x_dim_priority
2. Facets are resolved from remaining dimensions (x-axis excluded)
x_dim_priority expanded:
x_dim_priority = ('time', 'duration', 'duration_pct', 'period', 'scenario', 'cluster')
- Time-like dims first, then common grouping dims as fallback
- variable stays excluded (it's used for color, not x-axis)
_get_x_dim() refactored:
- Now takes dims: list[str] instead of a DataFrame
- More versatile - works with any list of dimension names
- Add `x` parameter to bar/stacked_bar/line/area for explicit x-axis control - Add CONFIG.Plotting.x_dim_priority for auto x-axis selection order - X-axis determined first, facets from remaining dimensions - Refactor _get_x_column -> _get_x_dim (takes dim list, not DataFrame) - Support scalar data (no dims) by using 'variable' as x-axis
- Add `x` parameter to bar/stacked_bar/line/area for explicit x-axis control
- Add CONFIG.Plotting.x_dim_priority for auto x-axis selection
Default: ('time', 'duration', 'duration_pct', 'period', 'scenario', 'cluster')
- X-axis determined first, facets resolved from remaining dimensions
- Refactor _get_x_column -> _get_x_dim (takes dim list, more versatile)
- Support scalar data (no dims) by using 'variable' as x-axis
- Skip color='variable' when x='variable' to avoid double encoding
- Fix _dataset_to_long_df to use dims (not just coords) as id_vars
- Add `x` parameter to bar/stacked_bar/line/area for explicit x-axis control
- Add CONFIG.Plotting.x_dim_priority for auto x-axis selection
Default: ('time', 'duration', 'duration_pct', 'period', 'scenario', 'cluster')
- X-axis determined first, facets resolved from remaining dimensions
- Refactor _get_x_column -> _get_x_dim (takes dim list, more versatile)
- Support scalar data (no dims) by using 'variable' as x-axis
- Skip color='variable' when x='variable' to avoid double encoding
- Fix _dataset_to_long_df to use dims (not just coords) as id_vars
- Ensure px_kwargs properly overrides all defaults (color, facets, etc.)
…wargs} so user can override 2. scatter unused colors - Removed the unused parameter 3. to_duration_curve sorting - Changed [::-1] to np.flip(..., axis=time_axis) for correct multi-dimensional handling 4. DataArrayPlotAccessor.heatmap - Same kwarg merge fix
📝 WalkthroughWalkthroughThis pull request introduces a comprehensive XArray accessor-based plotting API ( Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Accessor as fxplot Accessor
participant Helpers as Internal Helpers
participant PX as Plotly Express
participant Figure as go.Figure
User->>Accessor: ds.fxplot.line(x='auto', colors=...)
Accessor->>Helpers: _get_x_dim(dims, 'auto')
Helpers-->>Accessor: x_dim (from priority list)
rect rgba(200, 220, 255, 0.3)
note over Accessor,Helpers: Dimension Resolution
Accessor->>Helpers: _resolve_auto_facets(facet_col='auto', ...)
Helpers-->>Accessor: facet_col, facet_row, animation_frame
end
Accessor->>Helpers: _dataset_to_long_df(ds, value_name, var_name)
Helpers-->>Accessor: long_form_df
rect rgba(200, 240, 200, 0.3)
note over Accessor: Color & Layout Processing
Accessor->>Accessor: process_colors(colors, ...)
Accessor->>Accessor: apply CONFIG defaults
end
Accessor->>PX: px.line(data=df, x=x_dim, ..., facet_col, animation_frame)
PX-->>Figure: Figure (with facets/animation)
Figure-->>User: Figure
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
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. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
docs/notebooks/fxplot_accessor_demo.ipynb (1)
29-37: Document or configure the Plotly renderer for offline environments.The
'notebook_connected'renderer hardcoded in this cell requires internet access for CDN-based Plotly.js loading. While the docs build succeeds in CI because it setsPLOTLY_RENDERER=jsonas an environment variable (which overridespio.renderers.default), this creates a fragile, implicit dependency. Local documentation builds or other CI contexts without this environment variable would attempt CDN access.Consider either:
- Configuring
pio.renderers.defaultbased on the execution environment (e.g., usingPLOTLY_RENDERERor another environment variable)- Using
'notebook'(self-contained) instead for better portability- Documenting that
PLOTLY_RENDERER=jsonmust be set for offline buildsflixopt/dataset_plot_accessor.py (1)
30-68: Consider consolidating_resolve_auto_facetsto reduce duplication.This function is nearly identical to the one in
statistics_accessor.py(lines 183-234), with the addition ofexclude_dims. Consider:
- Moving the more complete version (this one with
exclude_dims) to a shared module- Having
statistics_accessor.pyimport from here or the shared moduleThis would reduce maintenance burden and ensure consistent behavior.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
docs/notebooks/fxplot_accessor_demo.ipynbdocs/user-guide/recipes/plotting-custom-data.mdflixopt/__init__.pyflixopt/config.pyflixopt/dataset_plot_accessor.pyflixopt/statistics_accessor.pymkdocs.yml
🧰 Additional context used
🧬 Code graph analysis (2)
flixopt/statistics_accessor.py (2)
flixopt/dataset_plot_accessor.py (6)
stacked_bar(192-268)stacked_bar(754-780)heatmap(423-486)heatmap(842-891)line(270-346)line(782-810)flixopt/clustering/base.py (1)
heatmap(660-794)
flixopt/dataset_plot_accessor.py (3)
flixopt/color_processing.py (1)
process_colors(165-233)flixopt/config.py (2)
CONFIG(185-916)Plotting(551-595)flixopt/statistics_accessor.py (6)
_resolve_auto_facets(183-234)sizes(464-468)sizes(1035-1078)sizes(1766-1830)_dataset_to_long_df(250-260)heatmap(1539-1669)
⏰ 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). (5)
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
- GitHub Check: test (3.14)
- GitHub Check: test (3.13)
- GitHub Check: Build documentation
🔇 Additional comments (31)
mkdocs.yml (1)
76-76: LGTM!The navigation entry for the new fxplot accessor demo notebook is correctly placed and follows the existing navigation structure.
flixopt/__init__.py (1)
17-19: LGTM!The side-effect import correctly registers the xarray accessors (.fxplot and .fxstats) at package initialization time. The comment clearly explains the purpose, and the noqa directive appropriately suppresses the unused import warning.
flixopt/config.py (4)
166-166: LGTM!The default line shape of
'hv'(horizontal-then-vertical step) is appropriate for time-series energy data where values typically represent constant rates or states over each time period.
169-169: LGTM!The x_dim_priority default provides a sensible hierarchy for automatic x-axis selection, prioritizing temporal dimensions (time, duration) followed by organizational dimensions (period, scenario, cluster).
592-595: LGTM!The new plotting configuration attributes are correctly defined with appropriate type hints and default values from the _DEFAULTS mapping.
696-699: LGTM!Both new plotting configuration parameters are correctly included in the to_dict() serialization method, maintaining consistency with the class attributes.
docs/notebooks/fxplot_accessor_demo.ipynb (3)
1-27: LGTM!Clear introduction and setup that imports necessary dependencies and displays the flixopt version for reproducibility.
39-68: LGTM!Clear section introducing sample data creation with a simple time-series dataset. The use of
np.random.seed(42)ensures reproducibility.
70-541: LGTM!Excellent comprehensive demonstration of the fxplot accessor functionality. The examples progress logically from basic plots to advanced features including:
- All major plot types (line, bar, stacked_bar, area, heatmap, scatter, pie, duration_curve)
- Automatic faceting and animation with clear explanations
- Customization options (colors, axis labels, facet control)
- Integration with xarray operations (filtering, selection)
- DataArray accessor usage
- Chaining with Plotly methods
The narrative structure and comments make it easy for users to understand and adapt the examples.
docs/user-guide/recipes/plotting-custom-data.md (3)
3-3: LGTM!The introduction correctly describes the purpose of the .fxplot accessor and its relationship to the optimization results plot accessor.
5-19: LGTM!The quick example is concise and clearly demonstrates the key advantage of the fxplot accessor - direct plotting without DataFrame conversion. The progression from creating a dataset to plotting it is intuitive.
21-29: Notebook link is correct and accessible.The relative path
../../notebooks/fxplot_accessor_demo.ipynbresolves correctly to the existing notebook filedocs/notebooks/fxplot_accessor_demo.ipynb.flixopt/statistics_accessor.py (6)
1399-1406: LGTM - Clean delegation to fxplot API.The
balancemethod correctly delegates tods.fxplot.stacked_bar()with pre-resolved facet dimensions. The title, colors, and facet parameters are properly passed through.
1523-1530: LGTM - Consistent pattern for carrier_balance.Same clean delegation pattern as
balance(). Pre-resolved facets and colors are correctly forwarded.
1656-1661: LGTM - Heatmap delegation via DataArray accessor.Correctly uses
da.fxplot.heatmap()on the DataArray with pre-resolved facet and animation dimensions.
1750-1757: LGTM - flows() method delegation.Correctly delegates to
ds.fxplot.line()for flow visualization.
1926-1933: LGTM - duration_curve() delegation.Correctly uses
result_ds.fxplot.line()for the duration curve visualization.
2145-2152: LGTM - charge_states() delegation.Correctly delegates to
ds.fxplot.line()for charge state visualization.flixopt/dataset_plot_accessor.py (13)
16-28: LGTM - Clean x-dimension selection helper.The
_get_x_dimfunction correctly implements priority-based dimension selection with a sensible fallback to'variable'for scalar data.
71-81: Slight duplication withstatistics_accessor.py, but implementation differs appropriately.This version correctly uses
ds.dimsforid_vars(line 80), whilestatistics_accessor.pyusesds.coords.keys()(line 259). The comment explains the reasoning well. If consolidating, this version's approach is more robust for handling dimensions without explicit coordinates.
119-191: LGTM - Grouped bar chart implementation.The
barmethod correctly implements dimension resolution, color processing, and faceting. The check on line 173 to avoid coloring by variable when it's on the x-axis is a good edge case handling.
192-268: LGTM - Stacked bar with relative barmode.The
stacked_barmethod correctly setsbarmode='relative'for proper positive/negative stacking. Layout updates for gap removal are appropriate for continuous stacked bars.
270-346: LGTM - Line chart with configurable shape.The
linemethod correctly appliesCONFIG.Plotting.default_line_shapewhen no explicit shape is provided.
348-421: LGTM - Area chart implementation.Consistent with line chart pattern, correctly uses
px.areafor stacked areas.
423-486: LGTM - Heatmap with auto variable selection.Good UX: auto-selects the variable if only one exists, provides clear error message otherwise. Using
px.imshowdirectly with xarray DataArray is the correct approach.
488-554: LGTM - Scatter plot between two variables.Clean implementation requiring explicit x and y variable names. Good validation with informative error messages.
556-636: LGTM - Pie chart with scalar and multi-dimensional support.Good handling of both scalar (single pie) and multi-dimensional (faceted pies) cases. The scalar case detection via
max_ndim == 0is elegant.
639-696: LGTM - Duration curve transformation accessor.The
to_duration_curvemethod correctly:
- Sorts values descending along the time axis
- Handles multi-dimensional arrays properly via
axis=time_axis- Renames the time dimension to
duration_pctordurationbased on normalization
698-752: LGTM - DataArray accessor with delegation pattern.Clean implementation that converts DataArray to Dataset for plotting. The
_to_datasethelper correctly handles unnamed DataArrays by defaulting to'value'.
754-840: LGTM - Delegating methods for DataArray.The
stacked_bar,line, andareamethods correctly forward all parameters to the Dataset accessor.
842-891: LGTM - DataArray-native heatmap implementation.Good design choice to implement heatmap directly rather than delegating, since
px.imshowworks optimally with DataArray. The implementation is consistent withDatasetPlotAccessor.heatmap.
flixopt/config.py
Outdated
| x_dim_priority: Order of dimensions to prefer for x-axis when 'auto'. | ||
| Default: ('time', 'duration', 'duration_pct'). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct the docstring to match the actual default value.
The docstring states the default is ('time', 'duration', 'duration_pct'), but the actual default at line 169 includes six dimensions: ('time', 'duration', 'duration_pct', 'period', 'scenario', 'cluster').
🔎 Proposed fix
- x_dim_priority: Order of dimensions to prefer for x-axis when 'auto'.
- Default: ('time', 'duration', 'duration_pct').
+ x_dim_priority: Order of dimensions to prefer for x-axis when 'auto'.
+ Default: ('time', 'duration', 'duration_pct', 'period', 'scenario', 'cluster').📝 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.
| x_dim_priority: Order of dimensions to prefer for x-axis when 'auto'. | |
| Default: ('time', 'duration', 'duration_pct'). | |
| x_dim_priority: Order of dimensions to prefer for x-axis when 'auto'. | |
| Default: ('time', 'duration', 'duration_pct', 'period', 'scenario', 'cluster'). |
🤖 Prompt for AI Agents
In flixopt/config.py around lines 569-570 (actual default tuple defined at line
169), the docstring incorrectly lists x_dim_priority default as ('time',
'duration', 'duration_pct') while the true default is ('time', 'duration',
'duration_pct', 'period', 'scenario', 'cluster'); update the docstring to
exactly match the actual default tuple at line 169 by replacing the shorter
tuple with the full six-element tuple so the docs and code stay consistent.
…ork-v2+plotting # Conflicts: # docs/notebooks/08a-aggregation.ipynb # docs/notebooks/08b-rolling-horizon.ipynb # docs/notebooks/08c-clustering.ipynb # docs/notebooks/08c2-clustering-storage-modes.ipynb # docs/notebooks/08d-clustering-multiperiod.ipynb # docs/notebooks/08e-clustering-internals.ipynb
… it, causing the NetCDF write failure in CI
Add new dataset plotting accessor for enhanced visualization: - fxplot accessor for xarray datasets - Improved plotting defaults and styling - Animation frame handling improvements 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
New .fxplot accessor for convenient plotting of any xr.Dataset with automatic dimension handling, faceting, and animation support.
✨ Added
New DatasetPlotAccessor (ds.fxplot.*)
Smart Dimension Handling
New Config Options
♻️ Changed
🐛 Fixed
📚 Documentation