Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
e8d04d2
Add planning doc
FBumann Nov 28, 2025
27b1f50
Finalize planning
FBumann Nov 28, 2025
b71a1c5
Add plotting acessor
FBumann Nov 28, 2025
977e9c4
Add plotting acessor
FBumann Nov 28, 2025
efc53d1
Add tests
FBumann Nov 28, 2025
01a92c6
Improve
FBumann Nov 28, 2025
01d8830
Improve
FBumann Nov 28, 2025
1b808a8
Update docs
FBumann Nov 28, 2025
d50e908
Updated the plotting API so that .data always returns xarray DataArra…
FBumann Nov 28, 2025
3234b93
All .data now returns xr.Dataset consistently.
FBumann Nov 28, 2025
93e5a4d
Fixed Inconsistencies and Unused Parameters
FBumann Nov 28, 2025
f3d5310
New Plot Accessors
FBumann Nov 28, 2025
d4cf175
Fix duration curve
FBumann Nov 28, 2025
fa1345f
Fix duration curve
FBumann Nov 28, 2025
c80dd2e
Fix duration curve
FBumann Nov 28, 2025
5517d23
Fix duration curve
FBumann Nov 28, 2025
cf61c50
xr.apply_ufunc to sort along the time axis while preserving all othe…
FBumann Nov 28, 2025
0f88aec
⏺ The example runs successfully. Now let me summarize the fixes:
FBumann Nov 28, 2025
d6ffe57
make variable names public in results
FBumann Nov 29, 2025
bf4d5ac
Fix sankey
FBumann Nov 29, 2025
360ff58
Fix effects()
FBumann Nov 29, 2025
67b4cf0
Fix effects
FBumann Nov 29, 2025
de4eecb
Remove bargaps
FBumann Nov 29, 2025
8b03112
made faceting consistent across all plot methods:
FBumann Nov 29, 2025
fc72976
Update storage method
FBumann Nov 29, 2025
0bdc45c
Remove mode parameter for simpli
FBumann Nov 29, 2025
5e9cb98
Make plotting_accessors.py more self contained
FBumann Nov 29, 2025
c088726
Use faster to_long()
FBumann Nov 29, 2025
4e43077
Add 0-dim case
FBumann Nov 29, 2025
ad34d05
sankey diagram now properly handles scenarios and periods:
FBumann Nov 29, 2025
b98b8ea
Add colors to sankey
FBumann Nov 29, 2025
628adea
Add sizes
FBumann Nov 29, 2025
aaf832b
Add size filtering
FBumann Nov 29, 2025
be31f69
Include storage sizes
FBumann Nov 29, 2025
71444de
Remove storage sizes
FBumann Nov 29, 2025
ecd441b
Merge branch 'feature/v5' into feature/plotting-acessors
FBumann Dec 3, 2025
ae8a793
Add charge state and status accessor
FBumann Dec 3, 2025
a7ac398
Summary of Changes
FBumann Dec 3, 2025
e5a4da1
1. New methods added to PlotAccessor
FBumann Dec 3, 2025
6d992d4
Move deprectated functionality into results.py instead of porting to …
FBumann Dec 3, 2025
193b2ff
Revert to simply deprectae old methods without forwarding to new code
FBumann Dec 3, 2025
ae74e81
Remove planning file
FBumann Dec 3, 2025
eb0aebf
Update plotting methods for new datasets
FBumann Dec 3, 2025
404df2b
1. Renamed data properties in PlotAccessor to use all_ prefix:
FBumann Dec 3, 2025
e7eb5ca
Update deprecations messages
FBumann Dec 3, 2025
8f11795
Update deprecations messages
FBumann Dec 3, 2025
bd5014c
Thsi seems much better.
FBumann Dec 3, 2025
60d84a2
Updaet docstrings and variable name generation in plotting acessor
FBumann Dec 3, 2025
0d762a5
Change __ to _ in private dataset caching
FBumann Dec 3, 2025
3542920
Revert breaking io changes
FBumann Dec 3, 2025
8e41c56
New solution storing interface
FBumann Dec 3, 2025
759b18c
Merge branch 'feature/solution-storage-change' into feature/solution-…
FBumann Dec 4, 2025
fc09bf1
Add new focused statistics and plot accessors
FBumann Dec 4, 2025
9446806
Renamed all properties:
FBumann Dec 4, 2025
1de29cc
Cache Statistics
FBumann Dec 4, 2025
19d5f55
Invalidate caches
FBumann Dec 4, 2025
f0601b4
Add effect related statistics
FBumann Dec 4, 2025
9d2cb51
Simplify statistics accessor to rely on flow_system directly instead …
FBumann Dec 4, 2025
691fe84
Fix heatma fallback for 1D Data
FBumann Dec 4, 2025
6a66be3
Merge remote-tracking branch 'origin/feature/solution-storage-change'…
FBumann Dec 4, 2025
0c952a9
Add topology accessor
FBumann Dec 4, 2025
d1472c0
Merge remote-tracking branch 'origin/feature/solution-storage-change'…
FBumann Dec 4, 2025
793b3a2
All deprecation warnings in the codebase now consistently use the for…
FBumann Dec 4, 2025
3d7142f
Update tests
FBumann Dec 4, 2025
7547522
created comprehensive documentation for all FlowSystem accessors
FBumann Dec 4, 2025
234b39d
Update results documentation
FBumann Dec 4, 2025
db2fc43
Update results documentation
FBumann Dec 4, 2025
76e9776
Update effect statistics
FBumann Dec 4, 2025
12d1917
Update effect statistics
FBumann Dec 4, 2025
d29fbd2
Update effect statistics
FBumann Dec 4, 2025
5a40e97
Add mkdocs plotly plugin
FBumann Dec 4, 2025
52ca80d
Add section about custom constraints
FBumann Dec 4, 2025
558bc58
documentation updates:
FBumann Dec 4, 2025
603e9e0
implemented the effects() method in StatisticsPlotAccessor at flixopt…
FBumann Dec 4, 2025
173ed3a
Remove intermediate plot accessor
FBumann Dec 4, 2025
a648974
1. pyproject.toml: Removed duplicate mkdocs-plotly-plugin>=0.1.3 en…
FBumann Dec 5, 2025
c149268
_create_effects_dataset method in statistics_accessor.py was simplified:
FBumann Dec 5, 2025
ab8ee9c
Update docs
FBumann Dec 5, 2025
4ae33d0
Improve to_netcdf method
FBumann Dec 5, 2025
af1557d
Update examples
FBumann Dec 5, 2025
33e04e3
Fix IIS computaion flag
FBumann Dec 5, 2025
0a0ceea
Fix examples
FBumann Dec 5, 2025
5f7a710
Fix faceting in heatmap and use period as facet col everywhere
FBumann Dec 6, 2025
98a269d
Inline plotting methods to deprecate plotting.py
FBumann Dec 7, 2025
c41b212
Fix test
FBumann Dec 7, 2025
d08dc52
Simplify Color Management
FBumann Dec 7, 2025
435ecd9
ColorType is now defined in color_processing.py and imported into st…
FBumann Dec 7, 2025
2c8eb4e
Fix ColorType typing
FBumann Dec 7, 2025
b064e6d
Add color accessor
FBumann Dec 7, 2025
4196bdd
Ensure io
FBumann Dec 7, 2025
83d64fa
Add carrier class
FBumann Dec 7, 2025
6375a44
implemented Carrier as a proper Interface subclass with container sup…
FBumann Dec 7, 2025
e686932
Inline plotting methods to deprecate plotting.py (#508)
FBumann Dec 7, 2025
a2437a1
Add to docs
FBumann Dec 7, 2025
3244f8d
Improve carrier colors and defaults
FBumann Dec 7, 2025
d9c1528
Update default carriers and colors
FBumann Dec 7, 2025
ba3d9d0
Update config
FBumann Dec 7, 2025
60f618c
Update config
FBumann Dec 7, 2025
568eff5
Move default carriers to config.py
FBumann Dec 7, 2025
8e7ebe9
Change default carrier handling
FBumann Dec 7, 2025
24ec987
Merge branch 'feature/solution-storage-change+plotting-acessors' into…
FBumann Dec 7, 2025
dfc8142
Add color handling
FBumann Dec 7, 2025
dd22ad7
Rmeove meta_data color handling
FBumann Dec 7, 2025
d19cafa
Add carrierst to examples
FBumann Dec 7, 2025
6e4b4fa
Improve plotting acessor
FBumann Dec 7, 2025
d8cf499
Improve _resolve_variable_names
FBumann Dec 7, 2025
dcc2a18
Improve _resolve_variable_names
FBumann Dec 7, 2025
012271b
Simplify coloring and remove color accessor
FBumann Dec 7, 2025
97cb560
Add connected_and_transformed handling
FBumann Dec 7, 2025
7c7965d
Improve error message in container
FBumann Dec 7, 2025
002a178
BUGFIX: Carrier from dataset
FBumann Dec 8, 2025
ae2b513
Merge branch 'feature/solution-storage-change' into feature/solution-…
FBumann Dec 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/stylesheets/extra.css
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,26 @@ button:focus-visible {
scrollbar-color: var(--md-default-fg-color--lighter) var(--md-default-bg-color);
}

/* ============================================================================
Color Swatches for Carrier Documentation
========================================================================= */

/* Inline color swatch - a small colored square */
.color-swatch {
display: inline-block;
width: 1em;
height: 1em;
border-radius: 3px;
vertical-align: middle;
margin-right: 0.3em;
border: 1px solid rgba(0, 0, 0, 0.15);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

[data-md-color-scheme="slate"] .color-swatch {
border-color: rgba(255, 255, 255, 0.2);
}

/* ============================================================================
Footer Alignment Fix
========================================================================= */
Expand Down
11 changes: 11 additions & 0 deletions docs/user-guide/core-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ $$\sum inputs = \sum outputs$$

This balance constraint is what makes your model physically meaningful — energy can't appear or disappear.

### Carriers

Buses can be assigned a **carrier** — a type of energy or material (electricity, heat, gas, etc.). Carriers enable automatic coloring in plots and help organize your system semantically:

```python
heat_bus = fx.Bus('HeatNetwork', carrier='heat') # Uses default heat color
elec_bus = fx.Bus('Grid', carrier='electricity')
```

See [Color Management](results-plotting.md#color-management) for details.

## Flows: What Moves Between Elements

A [`Flow`][flixopt.elements.Flow] represents the movement of energy or material. Every flow connects a component to a bus, with a defined direction.
Expand Down
23 changes: 23 additions & 0 deletions docs/user-guide/mathematical-notation/elements/Bus.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

A Bus is where flows meet and must balance — inputs equal outputs at every timestep.

## Carriers

Buses can optionally be assigned a **carrier** — a type of energy or material (e.g., electricity, heat, gas). Carriers enable:

- **Automatic coloring** in plots based on energy type
- **Unit tracking** for better result visualization
- **Semantic grouping** of buses by type

```python
# Assign a carrier by name (uses CONFIG.Carriers defaults)
heat_bus = fx.Bus('HeatNetwork', carrier='heat')
elec_bus = fx.Bus('Grid', carrier='electricity')

# Or register custom carriers on the FlowSystem
biogas = fx.Carrier('biogas', color='#228B22', unit='kW', description='Biogas fuel')
flow_system.add_carrier(biogas)
gas_bus = fx.Bus('BiogasNetwork', carrier='biogas')
```

See [Color Management](../../../user-guide/results-plotting.md#color-management) for more on how carriers affect visualization.

---

## Basic: Balance Equation

$$
Expand Down
107 changes: 107 additions & 0 deletions docs/user-guide/results-plotting.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,113 @@ flow_system.statistics.plot.balance('Bus', colors={
})
```

## Color Management

flixOpt provides centralized color management through the `flow_system.colors` accessor and carriers. This ensures consistent colors across all visualizations.

### Carriers

[`Carriers`][flixopt.carrier.Carrier] define energy or material types with associated colors. Built-in carriers are available in `CONFIG.Carriers`:

| Carrier | Color | Description |
|---------|-------|-------------|
| `electricity` | <span class="color-swatch" style="background:#FECB52"></span>`#FECB52` | Yellow - lightning/energy |
| `heat` | <span class="color-swatch" style="background:#D62728"></span>`#D62728` | Red - warmth/fire |
| `gas` | <span class="color-swatch" style="background:#1F77B4"></span>`#1F77B4` | Blue - natural gas |
| `hydrogen` | <span class="color-swatch" style="background:#9467BD"></span>`#9467BD` | Purple - clean/future |
| `fuel` | <span class="color-swatch" style="background:#8C564B"></span>`#8C564B` | Brown - fossil/oil |
| `biomass` | <span class="color-swatch" style="background:#2CA02C"></span>`#2CA02C` | Green - organic/renewable |

Colors are from the D3/Plotly palettes for professional consistency.

Assign carriers to buses for automatic coloring:

```python
# Buses use carrier colors automatically
heat_bus = fx.Bus('HeatNetwork', carrier='heat')
elec_bus = fx.Bus('Grid', carrier='electricity')

# Plots automatically use carrier colors for bus-related elements
flow_system.statistics.plot.sankey() # Buses colored by carrier
```

### Custom Carriers

Register custom carriers on your FlowSystem:

```python
# Create a custom carrier
biogas = fx.Carrier('biogas', color='#228B22', unit='kW', description='Biogas fuel')
hydrogen = fx.Carrier('hydrogen', color='#00CED1', unit='kg/h')

# Register with FlowSystem (overrides CONFIG.Carriers defaults)
flow_system.add_carrier(biogas)
flow_system.add_carrier(hydrogen)

# Access registered carriers
flow_system.carriers # CarrierContainer with locally registered carriers
flow_system.get_carrier('biogas') # Returns Carrier object
```

### Color Accessor

The `flow_system.colors` accessor provides centralized color configuration:

```python
# Configure colors for components
flow_system.colors.setup({
'Boiler': '#D35400',
'CHP': '#8E44AD',
'HeatPump': '#27AE60',
})

# Or set individual colors
flow_system.colors.set_component_color('Boiler', '#D35400')
flow_system.colors.set_carrier_color('biogas', '#228B22')

# Load from file
flow_system.colors.setup('colors.json') # or .yaml
```

### Context-Aware Coloring

Plot colors are automatically resolved based on context:

- **Bus balance plots**: Colors based on the connected component
- **Component balance plots**: Colors based on the connected bus/carrier
- **Sankey diagrams**: Buses use carrier colors, components use configured colors

```python
# Plotting a bus balance → flows colored by their parent component
flow_system.statistics.plot.balance('ElectricityBus')

# Plotting a component balance → flows colored by their connected bus/carrier
flow_system.statistics.plot.balance('CHP')
```

### Color Resolution Priority

Colors are resolved in this order:

1. **Explicit colors** passed to plot methods (always override)
2. **Component/bus colors** set via `flow_system.colors.setup()`
3. **Element `meta_data['color']`** if present
4. **Carrier colors** from FlowSystem or CONFIG.Carriers
5. **Default colorscale** (controlled by `CONFIG.Plotting.default_qualitative_colorscale`)

### Persistence

Color configurations are automatically saved with the FlowSystem:

```python
# Colors are persisted
flow_system.to_netcdf('my_system.nc')

# And restored
loaded = fx.FlowSystem.from_netcdf('my_system.nc')
loaded.colors # Configuration restored
```

### Display Control

Control whether plots are shown automatically:
Expand Down
14 changes: 10 additions & 4 deletions examples/01_Simple/simple_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@

# --- Define Energy Buses ---
# These represent nodes, where the used medias are balanced (electricity, heat, and gas)
flow_system.add_elements(fx.Bus(label='Strom'), fx.Bus(label='Fernwärme'), fx.Bus(label='Gas'))
# Carriers provide automatic color assignment in plots (yellow for electricity, red for heat, etc.)
flow_system.add_elements(
fx.Bus(label='Strom', carrier='electricity'),
fx.Bus(label='Fernwärme', carrier='heat'),
fx.Bus(label='Gas', carrier='gas'),
)

# --- Define Effects (Objective and CO2 Emissions) ---
# Cost effect: used as the optimization objective --> minimizing costs
Expand Down Expand Up @@ -109,13 +114,14 @@
# Plotting through statistics accessor - returns PlotResult with .data and .figure
flow_system.statistics.plot.balance('Fernwärme')
flow_system.statistics.plot.balance('Storage')
flow_system.statistics.plot.heatmap('CHP(Q_th)|flow_rate')
flow_system.statistics.plot.heatmap('Storage|charge_state')
flow_system.statistics.plot.heatmap('CHP(Q_th)')
flow_system.statistics.plot.heatmap('Storage')
flow_system.statistics.plot.heatmap('Storage')

# Access data as xarray Datasets
print(flow_system.statistics.flow_rates)
print(flow_system.statistics.charge_states)

# Duration curve and effects analysis
flow_system.statistics.plot.duration_curve('Boiler(Q_th)|flow_rate')
flow_system.statistics.plot.duration_curve('Boiler(Q_th)')
print(flow_system.statistics.temporal_effects)
11 changes: 6 additions & 5 deletions examples/02_Complex/complex_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@

# --- Define Energy Buses ---
# Represent node balances (inputs=outputs) for the different energy carriers (electricity, heat, gas) in the system
# Carriers provide automatic color assignment in plots (yellow for electricity, red for heat, blue for gas)
flow_system.add_elements(
fx.Bus('Strom', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Fernwärme', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Gas', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Strom', carrier='electricity', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Fernwärme', carrier='heat', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Gas', carrier='gas', imbalance_penalty_per_flow_hour=imbalance_penalty),
)

# --- Define Effects ---
Expand Down Expand Up @@ -200,7 +201,7 @@
flow_system.to_netcdf('results/complex_example.nc')

# Plot results using the statistics accessor
flow_system.statistics.plot.heatmap('BHKW2(Q_th)|flow_rate')
flow_system.statistics.plot.heatmap('BHKW2(Q_th)') # Flow label - auto-resolves to flow_rate
flow_system.statistics.plot.balance('BHKW2')
flow_system.statistics.plot.heatmap('Speicher|charge_state')
flow_system.statistics.plot.heatmap('Speicher') # Storage label - auto-resolves to charge_state
flow_system.statistics.plot.balance('Fernwärme')
8 changes: 4 additions & 4 deletions examples/03_Optimization_modes/example_optimization_modes.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ def get_solutions(optimizations: list, variable: str) -> xr.Dataset:

flow_system = fx.FlowSystem(timesteps)
flow_system.add_elements(
fx.Bus('Strom', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Fernwärme', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Gas', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Kohle', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Strom', carrier='electricity', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Fernwärme', carrier='heat', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Gas', carrier='gas', imbalance_penalty_per_flow_hour=imbalance_penalty),
fx.Bus('Kohle', carrier='fuel', imbalance_penalty_per_flow_hour=imbalance_penalty),
)

# Effects
Expand Down
11 changes: 8 additions & 3 deletions examples/04_Scenarios/scenario_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,12 @@

# --- Define Energy Buses ---
# These represent nodes, where the used medias are balanced (electricity, heat, and gas)
flow_system.add_elements(fx.Bus(label='Strom'), fx.Bus(label='Fernwärme'), fx.Bus(label='Gas'))
# Carriers provide automatic color assignment in plots (yellow for electricity, red for heat, blue for gas)
flow_system.add_elements(
fx.Bus(label='Strom', carrier='electricity'),
fx.Bus(label='Fernwärme', carrier='heat'),
fx.Bus(label='Gas', carrier='gas'),
)

# --- Define Effects (Objective and CO2 Emissions) ---
# Cost effect: used as the optimization objective --> minimizing costs
Expand Down Expand Up @@ -199,10 +204,10 @@

# --- Analyze Results ---
# Plotting through statistics accessor - returns PlotResult with .data and .figure
flow_system.statistics.plot.heatmap('CHP(Q_th)|flow_rate')
flow_system.statistics.plot.heatmap('CHP(Q_th)') # Flow label - auto-resolves to flow_rate
flow_system.statistics.plot.balance('Fernwärme')
flow_system.statistics.plot.balance('Storage')
flow_system.statistics.plot.heatmap('Storage|charge_state')
flow_system.statistics.plot.heatmap('Storage') # Storage label - auto-resolves to charge_state

# Access data as xarray Datasets
print(flow_system.statistics.flow_rates)
Expand Down
9 changes: 5 additions & 4 deletions examples/05_Two-stage-optimization/two_stage_optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@
gas_price = filtered_data['Gaspr.€/MWh'].to_numpy()

flow_system = fx.FlowSystem(timesteps)
# Carriers provide automatic color assignment in plots
flow_system.add_elements(
fx.Bus('Strom'),
fx.Bus('Fernwärme'),
fx.Bus('Gas'),
fx.Bus('Kohle'),
fx.Bus('Strom', carrier='electricity'),
fx.Bus('Fernwärme', carrier='heat'),
fx.Bus('Gas', carrier='gas'),
fx.Bus('Kohle', carrier='fuel'),
fx.Effect('costs', '€', 'Kosten', is_standard=True, is_objective=True),
fx.Effect('CO2', 'kg', 'CO2_e-Emissionen'),
fx.Effect('PE', 'kWh_PE', 'Primärenergie'),
Expand Down
3 changes: 3 additions & 0 deletions flixopt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

# Import commonly used classes and functions
from . import linear_converters, plotting, results, solvers
from .carrier import Carrier, CarrierContainer
from .clustering import ClusteringParameters
from .components import (
LinearConverter,
Expand All @@ -34,6 +35,8 @@
__all__ = [
'TimeSeriesData',
'CONFIG',
'Carrier',
'CarrierContainer',
'Flow',
'Bus',
'Effect',
Expand Down
Loading