Skip to content

Conversation

@FBumann
Copy link
Member

@FBumann FBumann commented Jan 22, 2026

Description

Brief description of the changes in this PR.

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Code refactoring

Related Issues

Closes #(issue number)

Testing

  • I have tested my changes
  • Existing tests still pass

Checklist

  • My code follows the project style
  • I have updated documentation if needed
  • I have added tests for new functionality (if applicable)

Summary by CodeRabbit

  • New Features

    • Unified hover formatting across statistical visualizations with consistent unit display and improved label presentation.
  • Performance

    • Faster rendering for balance, carrier balance, and storage flow charts via an optimized plotting approach; storage charts include a clearer line overlay for state visualization.
  • Chores

    • Updated plotting dependency to a newer compatible version for improved plotting capabilities.

✏️ Tip: You can customize this high-level summary in your review settings.

  - Classifies traces by analyzing y-values: positive, negative, mixed, zero
  - Sets stackgroup='positive' or stackgroup='negative' for proper separate stacking
  - Mixed values shown as dashed lines (no fill)
  - Opaque fills, no line borders, hv line shape

  Performance:
  ┌────────────────────────┬───────┐
  │         Method         │ Time  │
  ├────────────────────────┼───────┤
  │ .plotly.bar() + update │ 0.14s │
  ├────────────────────────┼───────┤
  │ .plotly.area() + style │ 0.10s │
  ├────────────────────────┼───────┤
  │ Speedup                │ ~1.4x │
  └────────────────────────┴───────┘
  # Iterate over all traces (main + animation frames)
  def _iter_all_traces(fig: go.Figure):
      yield from fig.data
      for frame in getattr(fig, 'frames', []) or []:
          yield from frame.data

  # Apply unified hover styling (works with any plot type)
  def _apply_unified_hover(fig: go.Figure, unit: str = '', decimals: int = 1):
      # Sets: <b>name</b>: value unit
      # + hovermode='x unified' + spike lines

  Updated Methods
  ┌───────────────────┬──────────────────────────────────────────────┐
  │      Method       │                   Changes                    │
  ├───────────────────┼──────────────────────────────────────────────┤
  │ balance()         │ + _apply_unified_hover(fig, unit=unit_label) │
  ├───────────────────┼──────────────────────────────────────────────┤
  │ carrier_balance() │ + _apply_unified_hover(fig, unit=unit_label) │
  ├───────────────────┼──────────────────────────────────────────────┤
  │ storage()         │ + _apply_unified_hover(fig, unit=unit_label) │
  └───────────────────┴──────────────────────────────────────────────┘
  Result

  - Hover format: <b>Solar</b>: 45.3 kW
  - Hovermode: x unified (single tooltip for all traces)
  - Spikes: Gray vertical line at cursor
… aggregating sign info across all traces returned by _iter_all_traces(fig), including animation frames.

   The color_map is still derived from fig.data. The implementation uses a sign_flags dictionary to incrementally update has_pos/has_neg flags for each trace.name, then
  computes class_map from those aggregated flags.
  2. _apply_unified_hover (lines 271-274): Replaced the fig.update_layout(xaxis_showspikes=..., ...) with a single fig.update_xaxes(showspikes=True, spikecolor='gray',
  spikethickness=1) call so spike settings apply to all x-axes (xaxis, xaxis2, xaxis3, ...) in faceted plots.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Replaces legacy trace-iteration and area-styling helpers with a centralized _apply_unified_hover() using update_traces, switches area plots to fast_bar for balance/carrier/storage flows, and updates xarray_plotly dependency to >= 0.0.10, < 1.

Changes

Cohort / File(s) Summary
Statistics Accessor
flixopt/statistics_accessor.py
Removes _iter_all_traces and _style_area_as_bar; centralizes hover formatting via _apply_unified_hover() that uses update_traces; replaces area plotting and per-trace hover tweaks with fast_bar for balance, carrier_balance, and storage flow plots; keeps hovermode='x unified' and axis spikes; retains line overlay for charge_state.
Dependency Update
pyproject.toml
Bumps xarray_plotly constraint from >= 0.0.3, < 1 to >= 0.0.10, < 1.
Changelog
CHANGELOG.md
Notes internal plotting change: statistics.plot.balance(), carrier_balance(), and storage() now use xarray_plotly.fast_bar() (user-facing behavior unchanged).

Sequence Diagram(s)

(Section intentionally omitted — changes are internal plotting substitutions and do not introduce a new multi-component sequential control flow that requires visualization.)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through traces, tidy and bright,
I stitched one hover to bind them tight,
Waves turned to bars with cheerful cheer,
Fewer helpers, clarity near,
A nibble of code — plots feel light! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description uses only the template structure without filling in actual implementation details such as what was changed, why changes were made, which issues are closed, or testing results. Complete the description by: (1) adding specific details of changes made, (2) selecting the appropriate type of change, (3) referencing related issues, (4) documenting testing performed, and (5) checking testing completion checkboxes.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feature/speed up plotting' is directly related to the main objective of the PR, which optimizes plotting performance by replacing area styling with fast_bar and centralizing hover formatting.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@FBumann FBumann marked this pull request as ready for review January 22, 2026 15:20
…ting

# Conflicts:
#	flixopt/statistics_accessor.py
Copy link
Contributor

@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: 1

🤖 Fix all issues with AI agents
In `@flixopt/statistics_accessor.py`:
- Around line 1551-1556: The ds.plotly.fast_bar calls are passing an unsupported
parameter line_shape='hv'; remove the line_shape argument from each
ds.plotly.fast_bar invocation (the ones that assign to fig) so the call becomes
fig = ds.plotly.fast_bar(title=..., **color_kwargs, **plotly_kwargs), relying on
plotly_kwargs (e.g., barmode) for stacking/behavior instead.

Comment on lines 1551 to 1556
fig = ds.plotly.fast_bar(
title=f'{node} [{unit_label}]' if unit_label else node,
line_shape='hv',
**color_kwargs,
**plotly_kwargs,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's find the fast_bar function definition
find . -type f -name "*.py" | head -20

Repository: flixOpt/flixopt

Length of output: 174


🏁 Script executed:

# Search for fast_bar definition in the codebase
rg -n "def fast_bar" --type py

Repository: flixOpt/flixopt

Length of output: 41


🏁 Script executed:

# Check the context of the lines mentioned in the review
sed -n '1545,1560p' flixopt/statistics_accessor.py

Repository: flixOpt/flixopt

Length of output: 596


🏁 Script executed:

# Also check the other locations mentioned
sed -n '1670,1685p' flixopt/statistics_accessor.py
sed -n '2275,2290p' flixopt/statistics_accessor.py

Repository: flixOpt/flixopt

Length of output: 1359


🏁 Script executed:

# Search for previous implementation using area and _style_area_as_bar
rg -n "_style_area_as_bar|\.area\(" flixopt/statistics_accessor.py -B 3 -A 3

Repository: flixOpt/flixopt

Length of output: 41


🏁 Script executed:

# Check where fast_bar comes from - look for imports
rg -n "fast_bar|import.*plotly" flixopt/statistics_accessor.py | head -30

Repository: flixOpt/flixopt

Length of output: 217


🏁 Script executed:

# Try to find fast_bar in xarray-plotly or plotly packages
rg -n "def fast_bar" . --type py 2>/dev/null | head -20

Repository: flixOpt/flixopt

Length of output: 41


🌐 Web query:

xarray-plotly fast_bar function parameters documentation

💡 Result:

I couldn’t find any official function named fast_bar in xarray or Plotly docs. Xarray’s plotting API wraps Matplotlib (DataArray.plot and friends) and Plotly’s bar function is plotly.express.bar (see its full parameter list). If you meant a third‑party helper, there’s an independent xarray_plotly project that wraps plotly.express for xarray (GitHub). Sources:

  • xarray plotting documentation (DataArray.plot / plotting guide). [1]
  • plotly.express.bar parameter reference. [2]
  • xarray_plotly (third‑party accessor on GitHub). [3]

If you want, tell me which behavior/parameters you need and I’ll map those to plotly.express.bar arguments or inspect the xarray_plotly code.


🏁 Script executed:

# Check if there's a plotly accessor module in the repo
find . -type f -name "*plotly*" | grep -v __pycache__

Repository: flixOpt/flixopt

Length of output: 95


🏁 Script executed:

# Look for the plotly accessor and its methods
fd -e py "plotly" | head -20

Repository: flixOpt/flixopt

Length of output: 41


🏁 Script executed:

# Search for xarray accessor registration or plotly accessor definition
rg -n "@.*accessor|register_.*accessor" . --type py

Repository: flixOpt/flixopt

Length of output: 129


🏁 Script executed:

# Look for plotly accessor import or definition
rg -n "plotly" flixopt/*.py | grep -i "import\|from\|accessor"

Repository: flixOpt/flixopt

Length of output: 8584


🏁 Script executed:

# Check requirements files for xarray_plotly dependency
find . -type f \( -name "requirements*.txt" -o -name "setup.py" -o -name "setup.cfg" -o -name "pyproject.toml" \) -exec grep -l "xarray" {} \;

Repository: flixOpt/flixopt

Length of output: 75


🏁 Script executed:

# Check if there's a local plotly accessor module or definition
find . -type f -name "*.py" -exec grep -l "plotly.*accessor\|fast_bar" {} \;

Repository: flixOpt/flixopt

Length of output: 91


🏁 Script executed:

# Look for the specific accessor setup or where plotly methods might be defined
rg -n "class.*Plotly|def fast_bar" . --type py

Repository: flixOpt/flixopt

Length of output: 41


🏁 Script executed:

# Check pyproject.toml for xarray_plotly version
cat pyproject.toml | grep -A 5 -B 5 "xarray_plotly"

Repository: flixOpt/flixopt

Length of output: 339


🌐 Web query:

xarray_plotly fast_bar function source code github

💡 Result:

I couldn't find a public GitHub function named fast_bar in an xarray_plotly repository. Do you have a link, package name, or example (repo owner) I should search for?


🌐 Web query:

xarray-plotly fast_bar barmode line_shape parameter

💡 Result:

Short answer: xarray's Plotly-based bar plotting ultimately calls Plotly Express' bar routine, so you can pass barmode (e.g. "group", "overlay", "relative"/"stack") via kwargs to control stacking/grouping. The line_shape parameter is for line plots (px.line / line-type traces) — it does not apply to bar/fast_bar.

Sources:

  • px.bar docs (barmode parameter). [1]
  • px.line / line_shape docs (line_shape applies to lines, not bars). [2]
  • Plotly Express overview (PX is the backend used by high-level calls and accepts xarray inputs). [3]

References:
[1] plotly.express.bar documentation.
[2] plotly.express.line / line_shape documentation.
[3] Plotly Express overview (PX accepts xarray/numpy/pandas inputs).


🌐 Web query:

xarray_plotly pypi package repository github

💡 Result:

  • PyPI / package: xarray-plotly (install via pip as xarray-plotly). [1]
  • Source / repository: GitHub — FBumann/xarray_plotly. [2]

Sources:
[1] piwheels / xarray-plotly (package listing).
[2] Plotly community post linking the GitHub repo (FBumann/xarray_plotly).


🌐 Web query:

plotly express bar line_shape parameter invalid

💡 Result:

Cause: px.bar creates Bar traces (no line_shape) and Plotly Express may auto-create Scatter/Scattergl traces when drawing lines; the line_shape option applies to Scatter (plotly.graph_objects.Scatter) and only 'scatter' (SVG) supports 'spline' — Scattergl does not. See the px/Scatter docs and community discussion. [1][2]

Fixes:

  • If you want a curved/step line, add a separate Scatter trace (go.Scatter) and set its line.shape (or mode/line dict) instead of passing line_shape to px.bar. Example: add_traces(go.Scatter(x=..., y=..., mode='lines', line=dict(shape='spline'))). [1]
  • If using px.line or px.scatter and you need 'spline' with many points, force SVG rendering so spline is allowed: set render_mode='svg' (default may switch to 'scattergl' for performance). [1][2]
  • For a horizontal/constant line on a bar chart, simpler: fig.add_hline(y=...) or fig.add_shape(...). [3]

Sources:

  1. Plotly Express / Scatter doc (line_shape options). [1]
  2. Plotly community thread explaining Scattergl lacks 'spline' and render_mode='svg' workaround. [2]
  3. StackOverflow examples for adding lines to bar charts (add_hline / go.Scatter). [3]

🏁 Script executed:

# Check if xarray_plotly is vendored or can be searched in pip
python3 << 'EOF'
import subprocess
result = subprocess.run(['pip', 'show', 'xarray_plotly'], capture_output=True, text=True)
print(result.stdout)
print(result.stderr)
EOF

Repository: flixOpt/flixopt

Length of output: 145


🌐 Web query:

"xarray_plotly" "fast_bar" documentation api

💡 Result:

Do you want the xarray_plotly fast_bar docs/usage (link + examples) or the API reference (function signature and parameters)? Which one should I fetch?


🌐 Web query:

site:github.com FBumann xarray_plotly fast_bar

💡 Result:

I found the GitHub repository "FBumann/xarray_plotly" (interactive Plotly Express plotting for xarray) — latest release v0.0.10 (Jan 22, 2026) and docs. [1][2]

I did not find any public GitHub results for "fast_bar" in that repo or tied to FBumann.

Sources:

  • FBumann/xarray_plotly GitHub repo. [1]
  • Plotly community post announcing the package. [2]

🌐 Web query:

xarray_plotly fast_bar method signature parameters source

💡 Result:

Do you mean the fast_bar method in the xarray-plotly package (the xarray_plotly accessor)? I can fetch the exact method signature and source — confirm and I’ll look it up.


🌐 Web query:

FBumann xarray_plotly figures.py fast_bar source code

💡 Result:

Do you want me to (a) fetch and show the contents of figures.py (fast_bar) from FBumann/xarray_plotly, or (b) provide the repository link and instructions to view it yourself?


🌐 Web query:

xarray_plotly plotly accessor bar method line_shape

💡 Result:

Short answer: plotly.express.bar (and the underlying Bar trace) does not accept a line_shape argument. line_shape is a parameter for line/area/line-like Plotly Express functions (px.line, px.area, etc.) and accepts 'linear', 'spline', 'hv', 'vh', 'hvh', or 'vhv'. See the px.bar signature (no line_shape) and the px docs describing line_shape. [1][2]

Sources:

  • px.bar signature (no line_shape). [1]
  • px docs showing line_shape and allowed values for line/area-like functions. [2]

🏁 Script executed:

# Try to check the xarray_plotly package directly via pip
python3 << 'EOF'
try:
    import xarray_plotly
    import inspect
    # Try to find fast_bar
    if hasattr(xarray_plotly, 'fast_bar'):
        print("Found fast_bar in xarray_plotly")
        print(inspect.signature(xarray_plotly.fast_bar))
    else:
        print("fast_bar not found in xarray_plotly module directly")
        print("Available attributes:", dir(xarray_plotly))
except Exception as e:
    print(f"Error: {e}")
    print("Trying to import and check xarray_plotly.figures...")
    try:
        from xarray_plotly import figures
        print("xarray_plotly.figures available")
        print("Available in figures:", [x for x in dir(figures) if not x.startswith('_')])
    except Exception as e2:
        print(f"Error with figures: {e2}")
EOF

Repository: flixOpt/flixopt

Length of output: 201


🌐 Web query:

xarray_plotly wraps plotly.express bar function documentation

💡 Result:

Yes — the xarray_plotly package provides a plotting accessor that wraps most plotly.express functions (including px.bar). See the package announcement on the Plotly community and the Plotly Express px.bar reference for the underlying API it wraps. [1][2]

Sources:

  • Package announcement / GitHub link (xarray_plotly). [1]
  • plotly.express.bar documentation. [2]

Remove line_shape='hv' from fast_bar calls — not supported for bar charts.

The fast_bar method wraps plotly.express.bar, which does not accept the line_shape parameter. This parameter is only valid for line and area plots. Passing it to a bar chart will be silently ignored or cause an error.

Stacking behavior for mixed positive/negative values via barmode='relative' is already supported and will work correctly through **plotly_kwargs.

Remove line_shape='hv' from all three locations: 1551–1556, 1675–1680, and 2279–2283.

🤖 Prompt for AI Agents
In `@flixopt/statistics_accessor.py` around lines 1551 - 1556, The
ds.plotly.fast_bar calls are passing an unsupported parameter line_shape='hv';
remove the line_shape argument from each ds.plotly.fast_bar invocation (the ones
that assign to fig) so the call becomes fig = ds.plotly.fast_bar(title=...,
**color_kwargs, **plotly_kwargs), relying on plotly_kwargs (e.g., barmode) for
stacking/behavior instead.

@FBumann FBumann merged commit 4f31aaf into main Jan 22, 2026
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.

2 participants