diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c7c80efa..151d9758a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,26 +6,46 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +### Changed + +### Deprecated + +### Removed + +### Fixed +- Fix color scheme selection in network_app; color pickers now update when a scheme is selected. + +### Known Issues + +### *Development* + ## [2.1.7] - 2025-09-13 This update is a maintenance release to improve Code Quality, CI and update the dependencies. @@ -34,7 +54,7 @@ There are no changes or new features. ### Added - Added __version__ to flixopt -### Development +### *Development* - ruff format the whole Codebase - Added renovate config - Added pre-commit diff --git a/flixopt/network_app.py b/flixopt/network_app.py index 957b9e4dd..cdec24898 100644 --- a/flixopt/network_app.py +++ b/flixopt/network_app.py @@ -535,10 +535,46 @@ def toggle_sidebar(n_clicks): return sidebar_style, main_style + # Combined callback to handle both color scheme changes and reset + @app.callback( + [ + Output('bus-color-picker', 'value'), + Output('source-color-picker', 'value'), + Output('sink-color-picker', 'value'), + Output('storage-color-picker', 'value'), + Output('converter-color-picker', 'value'), + ], + [Input('color-scheme-dropdown', 'value'), Input('reset-btn', 'n_clicks')], + ) + def update_color_pickers(color_scheme, reset_clicks): + """Update color pickers when color scheme changes or reset is clicked""" + ctx = callback_context + + # Determine which input triggered the callback + if ctx.triggered: + trigger_id = ctx.triggered[0]['prop_id'].split('.')[0] + if trigger_id == 'reset-btn' and reset_clicks and reset_clicks > 0: + # Reset was clicked, use default colors + colors = VisualizationConfig.DEFAULT_COLORS + else: + # Color scheme changed + colors = VisualizationConfig.COLOR_PRESETS.get(color_scheme, VisualizationConfig.DEFAULT_COLORS) + else: + # Initial load + colors = VisualizationConfig.COLOR_PRESETS.get(color_scheme, VisualizationConfig.DEFAULT_COLORS) + + return ( + {'hex': colors['Bus']}, + {'hex': colors['Source']}, + {'hex': colors['Sink']}, + {'hex': colors['Storage']}, + {'hex': colors['Converter']}, + ) + + # Updated main visualization callback - simplified logic @app.callback( [Output('cytoscape', 'elements'), Output('cytoscape', 'stylesheet')], [ - Input('color-scheme-dropdown', 'value'), Input('bus-color-picker', 'value'), Input('source-color-picker', 'value'), Input('sink-color-picker', 'value'), @@ -551,7 +587,6 @@ def toggle_sidebar(n_clicks): [State('elements-store', 'data')], ) def update_visualization( - color_scheme, bus_color, source_color, sink_color, @@ -562,23 +597,20 @@ def update_visualization( font_size, stored_elements, ): + """Update visualization based on current color picker values""" if not stored_elements: return no_update, no_update - # Determine colors to use - if any(picker for picker in [bus_color, source_color, sink_color, storage_color, converter_color, edge_color]): - # Use custom colors from pickers - colors = { - 'Bus': bus_color.get('hex') if bus_color else '#7F8C8D', - 'Source': source_color.get('hex') if source_color else '#F1C40F', - 'Sink': sink_color.get('hex') if sink_color else '#F1C40F', - 'Storage': storage_color.get('hex') if storage_color else '#2980B9', - 'Converter': converter_color.get('hex') if converter_color else '#D35400', - 'Other': '#27AE60', - } - else: - # Use preset scheme - colors = VisualizationConfig.COLOR_PRESETS.get(color_scheme, VisualizationConfig.DEFAULT_COLORS) + # Use colors from pickers (which are now synced with scheme selection) + default_colors = VisualizationConfig.DEFAULT_COLORS + colors = { + 'Bus': bus_color.get('hex') if bus_color else default_colors['Bus'], + 'Source': source_color.get('hex') if source_color else default_colors['Source'], + 'Sink': sink_color.get('hex') if sink_color else default_colors['Sink'], + 'Storage': storage_color.get('hex') if storage_color else default_colors['Storage'], + 'Converter': converter_color.get('hex') if converter_color else default_colors['Converter'], + 'Other': default_colors['Other'], + } # Update element colors updated_elements = [] @@ -681,15 +713,10 @@ def display_element_info(node_data, edge_data): def update_layout(selected_layout): return {'name': selected_layout} - # Reset callback + # Reset callback for non-color-picker controls @app.callback( [ Output('color-scheme-dropdown', 'value'), - Output('bus-color-picker', 'value'), - Output('source-color-picker', 'value'), - Output('sink-color-picker', 'value'), - Output('storage-color-picker', 'value'), - Output('converter-color-picker', 'value'), Output('edge-color-picker', 'value'), Output('node-size-slider', 'value'), Output('font-size-slider', 'value'), @@ -698,15 +725,11 @@ def update_layout(selected_layout): [Input('reset-btn', 'n_clicks')], ) def reset_controls(n_clicks): + """Reset all controls to defaults (color pickers handled separately)""" if n_clicks and n_clicks > 0: return ( - 'Default', # color scheme - {'hex': '#7F8C8D'}, # bus - {'hex': '#F1C40F'}, # source - {'hex': '#F1C40F'}, # sink - {'hex': '#2980B9'}, # storage - {'hex': '#D35400'}, # converter - {'hex': '#808080'}, # edge + 'Default', # color scheme (will trigger color picker updates) + {'hex': '#808080'}, # edge color 90, # node size 10, # font size 'klay', # layout