Skip to content

Commit e686932

Browse files
authored
Inline plotting methods to deprecate plotting.py (#508)
* Inline plotting methods to deprecate plotting.py * Fix test * Simplify Color Management * ColorType is now defined in color_processing.py and imported into statistics_accessor.py. * Fix ColorType typing * statistics_accessor.py - Heatmap colors type safety (lines 121-148, 820-853) - Changed _heatmap_figure() parameter type from colors: ColorType = None to colors: str | list[str] | None = None - Changed heatmap() method parameter type similarly - Updated docstrings to clarify that dicts are not supported for heatmaps since px.imshow's color_continuous_scale only accepts colorscale names or lists 2. statistics_accessor.py - Use configured qualitative colorscale (lines 284, 315) - Updated _create_stacked_bar() to use CONFIG.Plotting.default_qualitative_colorscale as the default colorscale - Updated _create_line() similarly - This ensures user-configured CONFIG.Plotting.default_qualitative_colorscale affects all bar/line plots consistently 3. topology_accessor.py - Path type alignment (lines 219-222) - Added normalization of path=False to None before calling _plot_network() - This resolves the type mismatch where TopologyAccessor.plot() accepts bool | str | Path but _plot_network() only accepts str | Path | None * fix usage if index name in aggregation plot
1 parent 5f7a710 commit e686932

6 files changed

Lines changed: 305 additions & 109 deletions

File tree

flixopt/clustering.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import copy
99
import logging
10-
import pathlib
1110
import timeit
1211
from typing import TYPE_CHECKING
1312

@@ -29,6 +28,8 @@
2928
)
3029

3130
if TYPE_CHECKING:
31+
import pathlib
32+
3233
import linopy
3334
import pandas as pd
3435
import plotly.graph_objects as go
@@ -145,7 +146,7 @@ def use_extreme_periods(self):
145146
return self.time_series_for_high_peaks or self.time_series_for_low_peaks
146147

147148
def plot(self, colormap: str | None = None, show: bool = True, save: pathlib.Path | None = None) -> go.Figure:
148-
from . import plotting
149+
import plotly.express as px
149150

150151
df_org = self.original_data.copy().rename(
151152
columns={col: f'Original - {col}' for col in self.original_data.columns}
@@ -156,10 +157,17 @@ def plot(self, colormap: str | None = None, show: bool = True, save: pathlib.Pat
156157
colors = list(
157158
process_colors(colormap or CONFIG.Plotting.default_qualitative_colorscale, list(df_org.columns)).values()
158159
)
159-
fig = plotting.with_plotly(df_org.to_xarray(), 'line', colors=colors, xlabel='Time in h')
160+
161+
# Create line plot for original data (dashed)
162+
index_name = df_org.index.name or 'index'
163+
df_org_long = df_org.reset_index().melt(id_vars=index_name, var_name='variable', value_name='value')
164+
fig = px.line(df_org_long, x=index_name, y='value', color='variable', color_discrete_sequence=colors)
160165
for trace in fig.data:
161-
trace.update(dict(line=dict(dash='dash')))
162-
fig2 = plotting.with_plotly(df_agg.to_xarray(), 'line', colors=colors, xlabel='Time in h')
166+
trace.update(line=dict(dash='dash'))
167+
168+
# Add aggregated data (solid lines)
169+
df_agg_long = df_agg.reset_index().melt(id_vars=index_name, var_name='variable', value_name='value')
170+
fig2 = px.line(df_agg_long, x=index_name, y='value', color='variable', color_discrete_sequence=colors)
163171
for trace in fig2.data:
164172
fig.add_trace(trace)
165173

@@ -169,14 +177,10 @@ def plot(self, colormap: str | None = None, show: bool = True, save: pathlib.Pat
169177
yaxis_title='Value',
170178
)
171179

172-
plotting.export_figure(
173-
figure_like=fig,
174-
default_path=pathlib.Path('aggregated data.html'),
175-
default_filetype='.html',
176-
user_path=save,
177-
show=show,
178-
save=save is not None,
179-
)
180+
if save is not None:
181+
fig.write_html(str(save))
182+
if show:
183+
fig.show()
180184

181185
return fig
182186

flixopt/color_processing.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,57 @@
1515

1616
logger = logging.getLogger('flixopt')
1717

18+
# Type alias for flexible color input
19+
ColorType = str | list[str] | dict[str, str]
20+
"""Flexible color specification type supporting multiple input formats for visualization.
21+
22+
Color specifications can take several forms to accommodate different use cases:
23+
24+
**Named colorscales** (str):
25+
- Standard colorscales: 'turbo', 'plasma', 'cividis', 'tab10', 'Set1'
26+
- Energy-focused: 'portland' (custom flixopt colorscale for energy systems)
27+
- Backend-specific maps available in Plotly and Matplotlib
28+
29+
**Color Lists** (list[str]):
30+
- Explicit color sequences: ['red', 'blue', 'green', 'orange']
31+
- HEX codes: ['#FF0000', '#0000FF', '#00FF00', '#FFA500']
32+
- Mixed formats: ['red', '#0000FF', 'green', 'orange']
33+
34+
**Label-to-Color Mapping** (dict[str, str]):
35+
- Explicit associations: {'Wind': 'skyblue', 'Solar': 'gold', 'Gas': 'brown'}
36+
- Ensures consistent colors across different plots and datasets
37+
- Ideal for energy system components with semantic meaning
38+
39+
Examples:
40+
```python
41+
# Named colorscale
42+
colors = 'turbo' # Automatic color generation
43+
44+
# Explicit color list
45+
colors = ['red', 'blue', 'green', '#FFD700']
46+
47+
# Component-specific mapping
48+
colors = {
49+
'Wind_Turbine': 'skyblue',
50+
'Solar_Panel': 'gold',
51+
'Natural_Gas': 'brown',
52+
'Battery': 'green',
53+
'Electric_Load': 'darkred'
54+
}
55+
```
56+
57+
Color Format Support:
58+
- **Named Colors**: 'red', 'blue', 'forestgreen', 'darkorange'
59+
- **HEX Codes**: '#FF0000', '#0000FF', '#228B22', '#FF8C00'
60+
- **RGB Tuples**: (255, 0, 0), (0, 0, 255) [Matplotlib only]
61+
- **RGBA**: 'rgba(255,0,0,0.8)' [Plotly only]
62+
63+
References:
64+
- HTML Color Names: https://htmlcolorcodes.com/color-names/
65+
- Matplotlib colorscales: https://matplotlib.org/stable/tutorials/colors/colorscales.html
66+
- Plotly Built-in Colorscales: https://plotly.com/python/builtin-colorscales/
67+
"""
68+
1869

1970
def _rgb_string_to_hex(color: str) -> str:
2071
"""Convert Plotly RGB/RGBA string format to hex.

flixopt/plotting.py

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
import plotly.offline
4040
import xarray as xr
4141

42-
from .color_processing import process_colors
42+
from .color_processing import ColorType, process_colors
4343
from .config import CONFIG
4444

4545
if TYPE_CHECKING:
@@ -66,56 +66,6 @@
6666
plt.register_cmap(name='portland', cmap=mcolors.LinearSegmentedColormap.from_list('portland', _portland_colors))
6767

6868

69-
ColorType = str | list[str] | dict[str, str]
70-
"""Flexible color specification type supporting multiple input formats for visualization.
71-
72-
Color specifications can take several forms to accommodate different use cases:
73-
74-
**Named colorscales** (str):
75-
- Standard colorscales: 'turbo', 'plasma', 'cividis', 'tab10', 'Set1'
76-
- Energy-focused: 'portland' (custom flixopt colorscale for energy systems)
77-
- Backend-specific maps available in Plotly and Matplotlib
78-
79-
**Color Lists** (list[str]):
80-
- Explicit color sequences: ['red', 'blue', 'green', 'orange']
81-
- HEX codes: ['#FF0000', '#0000FF', '#00FF00', '#FFA500']
82-
- Mixed formats: ['red', '#0000FF', 'green', 'orange']
83-
84-
**Label-to-Color Mapping** (dict[str, str]):
85-
- Explicit associations: {'Wind': 'skyblue', 'Solar': 'gold', 'Gas': 'brown'}
86-
- Ensures consistent colors across different plots and datasets
87-
- Ideal for energy system components with semantic meaning
88-
89-
Examples:
90-
```python
91-
# Named colorscale
92-
colors = 'turbo' # Automatic color generation
93-
94-
# Explicit color list
95-
colors = ['red', 'blue', 'green', '#FFD700']
96-
97-
# Component-specific mapping
98-
colors = {
99-
'Wind_Turbine': 'skyblue',
100-
'Solar_Panel': 'gold',
101-
'Natural_Gas': 'brown',
102-
'Battery': 'green',
103-
'Electric_Load': 'darkred'
104-
}
105-
```
106-
107-
Color Format Support:
108-
- **Named Colors**: 'red', 'blue', 'forestgreen', 'darkorange'
109-
- **HEX Codes**: '#FF0000', '#0000FF', '#228B22', '#FF8C00'
110-
- **RGB Tuples**: (255, 0, 0), (0, 0, 255) [Matplotlib only]
111-
- **RGBA**: 'rgba(255,0,0,0.8)' [Plotly only]
112-
113-
References:
114-
- HTML Color Names: https://htmlcolorcodes.com/color-names/
115-
- Matplotlib colorscales: https://matplotlib.org/stable/tutorials/colors/colorscales.html
116-
- Plotly Built-in Colorscales: https://plotly.com/python/builtin-colorscales/
117-
"""
118-
11969
PlottingEngine = Literal['plotly', 'matplotlib']
12070
"""Identifier for the plotting engine to use."""
12171

0 commit comments

Comments
 (0)