Plotting Results¶
After solving an optimization, flixOpt provides a plotting API to visualize and analyze your results. The API is designed to be intuitive and chainable, giving you quick access to common plots while still allowing customization.
Related Guides
- Color Management - Configure colors for components and carriers
- Plotly Customization - Advanced figure customization
- Plotting Custom Data - Plot arbitrary xarray data with the
.plotlyaccessor
Quick Start¶
All plotting is accessed through the statistics.plot accessor:
flow_system.optimize(fx.solvers.HighsSolver())
flow_system.statistics.plot.balance('ElectricityBus')
flow_system.statistics.plot.sankey.flows()
flow_system.statistics.plot.heatmap('Boiler(Q_th)|flow_rate')
PlotResult: Data + Figure¶
Every plot method returns a PlotResult containing:
data: An xarray Dataset with the prepared datafigure: A Plotly Figure object
result = flow_system.statistics.plot.balance('Bus')
# Access the data
result.data.to_dataframe()
result.data.to_netcdf('balance_data.nc')
# Access the figure
result.figure.update_layout(title='Custom Title')
result.figure.show()
Method Chaining¶
All PlotResult methods return self, enabling fluent chaining:
flow_system.statistics.plot.balance('Bus') \
.update(title='Custom Title', height=600) \
.to_html('plot.html') \
.show()
| Method | Description |
|---|---|
.show() | Display the figure |
.update(**kwargs) | Update figure layout |
.update_traces(**kwargs) | Update trace properties |
.to_html(path) | Save as interactive HTML |
.to_image(path) | Save as static image (png, svg, pdf) |
.to_csv(path) | Export data to CSV |
.to_netcdf(path) | Export data to netCDF |
Available Plot Methods¶
Balance Plot¶
Plot the energy/material balance at a Bus or Component:
flow_system.statistics.plot.balance('ElectricityBus')
flow_system.statistics.plot.balance('Boiler', mode='area')
| Parameter | Type | Description |
|---|---|---|
node | str | Label of the Bus or Component |
mode | 'bar', 'line', 'area' | Visual style (default: 'bar') |
unit | 'flow_rate', 'flow_hours' | Power (kW) or energy (kWh) |
include / exclude | str or list | Filter flows by exact label |
aggregate | 'sum', 'mean', 'max', 'min' | Aggregate over time |
select | dict | xarray-style data selection |
Carrier Balance¶
Plot the balance of a carrier across all buses of that type:
flow_system.statistics.plot.carrier_balance('heat')
flow_system.statistics.plot.carrier_balance('electricity', unit='flow_hours')
Data is aggregated by component. Components with both supply and demand (e.g., storage, transmission) show separate entries like Storage (supply) and Storage (demand).
Storage Plot¶
Visualize storage components with charge state and flow balance:
flow_system.statistics.plot.storage('Battery')
flow_system.statistics.plot.storage('ThermalStorage', mode='line')
Heatmap¶
Create heatmaps of time series data with automatic time reshaping:
flow_system.statistics.plot.heatmap('Boiler(Q_th)|flow_rate')
flow_system.statistics.plot.heatmap(['CHP|on', 'Boiler|on'], facet_col='variable')
| Parameter | Type | Description |
|---|---|---|
variables | str or list | Variable name(s) to plot |
reshape | tuple | Time pattern: ('D', 'h') days×hours, ('W', 'D') weeks×days |
colorscale | str | Plotly colorscale name |
Flows Plot¶
Plot flow rates filtered by nodes or components:
flow_system.statistics.plot.flows(component='Boiler')
flow_system.statistics.plot.flows(start='ElectricityBus')
flow_system.statistics.plot.flows(unit='flow_hours', aggregate='sum')
Compare Plot¶
Compare multiple elements side-by-side:
flow_system.statistics.plot.compare(['Boiler', 'CHP', 'HeatPump'], variable='flow_rate')
flow_system.statistics.plot.compare(['Battery1', 'Battery2'], variable='charge_state')
Sankey Diagram¶
Visualize energy/material flows as a Sankey diagram:
flow_system.statistics.plot.sankey.flows() # Energy amounts
flow_system.statistics.plot.sankey.sizes() # Investment sizes
flow_system.statistics.plot.sankey.peak_flow() # Maximum rates
flow_system.statistics.plot.sankey.effects() # Cost/emission breakdown
Filter with select:
flow_system.statistics.plot.sankey.flows(select={'bus': 'HeatBus'})
flow_system.statistics.plot.sankey.effects(select={'effect': 'costs'})
Effects Plot¶
Plot cost, emissions, or other effect breakdowns:
flow_system.statistics.plot.effects() # Total by component
flow_system.statistics.plot.effects(effect='costs') # Just costs
flow_system.statistics.plot.effects(by='contributor') # By individual flows
flow_system.statistics.plot.effects(aspect='temporal') # Over time
| Parameter | Type | Description |
|---|---|---|
aspect | 'total', 'temporal', 'periodic' | Which aspect to plot |
effect | str or None | Specific effect (e.g., 'costs') or all |
by | 'component', 'contributor', 'time' | Grouping dimension |
Variable Plot¶
Plot the same variable type across multiple elements:
flow_system.statistics.plot.variable('on') # All binary states
flow_system.statistics.plot.variable('flow_rate', include='Boiler')
flow_system.statistics.plot.variable('charge_state') # All storage states
Duration Curve¶
Plot load duration curves (sorted time series):
flow_system.statistics.plot.duration_curve('Boiler(Q_th)')
flow_system.statistics.plot.duration_curve(['CHP(Q_th)', 'HeatPump(Q_th)'])
flow_system.statistics.plot.duration_curve('Demand(in)', normalize=True)
Common Parameters¶
Data Selection¶
Use xarray-style selection to filter data:
# Single value
flow_system.statistics.plot.balance('Bus', select={'scenario': 'base'})
# Time slice
flow_system.statistics.plot.balance('Bus', select={'time': slice('2024-01', '2024-06')})
# Combined
flow_system.statistics.plot.balance('Bus', select={
'scenario': 'base',
'time': slice('2024-01-01', '2024-01-07')
})
Faceting and Animation¶
Control how multi-dimensional data is displayed:
flow_system.statistics.plot.balance('Bus', facet_col='scenario')
flow_system.statistics.plot.balance('Bus', animate_by='period')
Include/Exclude Filtering¶
Filter flows by exact label:
# Include only specific flows
flow_system.statistics.plot.balance('Bus', include=['Boiler(Q_th)', 'CHP(Q_th)'])
# Exclude specific flows
flow_system.statistics.plot.balance('Bus', exclude='GridImport(P_el)')
Colors¶
Override colors using a dictionary:
flow_system.statistics.plot.balance('Bus', colors={
'Boiler(Q_th)': '#ff6b6b',
'CHP(Q_th)': '#4ecdc4',
})
See Color Management for configuring colors system-wide.
Examples¶
Analyzing a Bus Balance¶
# Quick overview
flow_system.statistics.plot.balance('ElectricityBus')
# Detailed analysis with exports
result = flow_system.statistics.plot.balance(
'ElectricityBus',
mode='area',
unit='flow_hours',
select={'time': slice('2024-06-01', '2024-06-07')},
show=False
)
# Export data
result.to_netcdf('electricity_balance.nc')
result.to_csv('electricity_balance.csv')
# Customize and display
result.update(
title='Electricity Balance - First Week of June',
yaxis_title='Energy [kWh]'
).show()
Creating a Report¶
plots = {
'balance': flow_system.statistics.plot.balance('HeatBus', show=False),
'storage': flow_system.statistics.plot.storage('ThermalStorage', show=False),
'sankey': flow_system.statistics.plot.sankey.flows(show=False),
'costs': flow_system.statistics.plot.effects(effect='costs', show=False),
}
for name, plot in plots.items():
plot.to_html(f'report_{name}.html')