diff --git a/NEWS.md b/NEWS.md index 39f3500..c48fa0b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,11 +1,16 @@ # Release notes -## Unversioned (2026-05-19) +## Version 0.7.2 (2026-05-20) ### Adjustments * If coordinates have not been saved to a design file for the nodes under an `Area`, they are now placed *symmetrically* around the circle (that is, accounting for one node being the `GeoAvailability` node to be placed at the center). * The default value for the radius of the circle for placing nodes without coordinates is now a third of the minimal distance between area coordinates defined in the `top_level` design file. +* Show investments into individual `TransmissionMode`s in the investment overview and in the information box appearing when hovering over an object. + +### Enhancements + +* Enabled the user to adjust the alpha value of EMGUI-objects not invested in. ## Version 0.7.1 (2026-04-24) diff --git a/Project.toml b/Project.toml index ffa3eda..2a3b8df 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "EnergyModelsGUI" uuid = "737a7361-d3b7-40e9-b1ac-59bee4c5ea2d" -version = "0.7.1" +version = "0.7.2" authors = ["Jon Vegard Venås ", "Dimitri Pinel ", "Magnus Askeland ", "Shweta Tiwari "] [deps] diff --git a/docs/generate_images.jl b/docs/generate_images.jl index 693041c..50235e5 100644 --- a/docs/generate_images.jl +++ b/docs/generate_images.jl @@ -89,6 +89,7 @@ function create_EMI_geography_images() coarse_coast_lines = false, scale_tot_opex = true, scale_tot_capex = false, + alpha = 0.5, ) # Create examples.png image diff --git a/docs/src/figures/EMI_geography.png b/docs/src/figures/EMI_geography.png index 1b14210..48088d7 100644 Binary files a/docs/src/figures/EMI_geography.png and b/docs/src/figures/EMI_geography.png differ diff --git a/docs/src/figures/EMI_geography_Oslo.png b/docs/src/figures/EMI_geography_Oslo.png index 5c4f2bf..1751ea1 100644 Binary files a/docs/src/figures/EMI_geography_Oslo.png and b/docs/src/figures/EMI_geography_Oslo.png differ diff --git a/docs/src/manual/simple-example.md b/docs/src/manual/simple-example.md index 0653adb..5d0d32a 100644 --- a/docs/src/manual/simple-example.md +++ b/docs/src/manual/simple-example.md @@ -58,6 +58,8 @@ You should then get the following GUI: The location of these files can be assigned through the `design_path` input parameter to the `GUI` function (this feature has the shortcut `ctrl+s`). 6. `reset view`: Reset the view to the optimal view based on the current system if the view has been altered (this feature has the shortcut `ctrl+r`). 7. `Expand all`: Toggle this to show/hide all components of all `Area`s. + 8. `Simplified`: Toggle this to use simplified connection plotting for the current level by default; it also applies to expanded sub-levels when `Expand all` is enabled, or when `simplify_all_levels` was enabled when constructing the GUI. + 9. `Alpha`: Adjust the transparency of the components not being invested in. !!! note "Top right text areas" The first text area (to the left) shows some tips of using the GUI by defult, but is temporarily changed upon a selection of an EMX object in which information of this object is shown. diff --git a/ext/EMGExt/EMGExt.jl b/ext/EMGExt/EMGExt.jl index e2b3403..03f89a9 100644 --- a/ext/EMGExt/EMGExt.jl +++ b/ext/EMGExt/EMGExt.jl @@ -5,6 +5,7 @@ using EnergyModelsBase using EnergyModelsInvestments using EnergyModelsGeography using EnergyModelsGUI +using GLMakie const TS = TimeStruct const EMG = EnergyModelsGeography @@ -83,6 +84,30 @@ function EMGUI.get_plotables(system::EMGUI.SystemGeo) ) end +""" + EMGUI.ProcInvData(element::TransmissionMode) + +Constructor for an `ProcInvData` object on a `TransmissionMode` `element`. +""" +function EMGUI.ProcInvData(element::TransmissionMode) + return EMGUI.ProcInvData( + EMGUI.get_element_label(element), + String[], + Float64[], + Observable(false), + ) +end + +""" + instantiate_inv_data(element::Transmission) + +Instantiate the `inv_data` field for a `Transmission` by creating a vector +of `ProcInvData` for each mode. +""" +function EMGUI.instantiate_inv_data(element::Transmission) + return [EMGUI.ProcInvData(mode) for mode ∈ modes(element)] +end + ############################################################################################ ## From structure_utils.jl """ @@ -193,9 +218,8 @@ EMGUI._type_to_header(::Type{<:TransmissionMode}) = :element EMGUI.get_inv_objs(obj::Transmission) Get the objects for which investment information should be stored for a given `Transmission`. -This includes obj itself but also its modes. """ -EMGUI.get_inv_objs(obj::Transmission) = [obj, modes(obj)...] +EMGUI.get_inv_objs(obj::Transmission) = modes(obj) ############################################################################################ ## From info_axis_utils.jl diff --git a/src/datastructures.jl b/src/datastructures.jl index 7302a9b..466a422 100644 --- a/src/datastructures.jl +++ b/src/datastructures.jl @@ -99,17 +99,31 @@ Type for storing processed investment data. # Fields +- **`id::String`** is the identifier for structures that have `TransmissionModes` + (default is thus an empty string). - **`inv_times::Vector{String}`** is a vector of formatted strings for added investments. -- **`capex::Vector{Number}`** contains the capex of all times with added investments. -- **`invested::Bool`** indicates if the element has been invested in. +- **`capex::Vector{Float64}`** contains the capex of all times with added investments. +- **`invested::Observable{Bool}`** indicates if the element has been invested in. """ -struct ProcInvData{T<:Number} +mutable struct ProcInvData + id::String inv_times::Vector{String} - capex::Vector{T} - invested::Bool + capex::Vector{Float64} + invested::Observable{Bool} end -function ProcInvData() - return ProcInvData(String[], Vector{Number}(), false) +function ProcInvData(::Any) + return ProcInvData("", String[], Float64[], Observable(false)) +end + +""" + instantiate_inv_data(element::AbstractElement) + +Instantiate the `inv_data` field for an `AbstractElement` by creating a vector of `ProcInvData`. +This function can be specialized for different types of `AbstractElement` to handle specific cases, +such as `Transmission` where multiple modes may require separate `ProcInvData` instances. +""" +function instantiate_inv_data(element::AbstractElement) + return [ProcInvData(element)] end """ @@ -136,11 +150,13 @@ energy system designs in Julia. for changes and represented as a Symbol. - **`file::String`** is the filename or path associated with the `EnergySystemDesign`. - **`visible::Observable{Bool}`** indicates whether the system is visible, observed for changes. -- **`inv_data::ProcInvData`** stores processed investment data. +- **`inv_data::Vector{ProcInvData}`** stores processed investment data. - **`plots::Vector{Makie.AbstractPlot}`** is a vector with all Makie object associated with this object. - **`simplified::Observable{Bool}`** indicates whether the system uses a simplified representation of its plotted connections, observed for changes. +- **`alpha::Observable{Float32}`** is the alpha value for the system's connections, observed for changes. + The alpha value is used to toggle the visibility of the nodes when investments have occurred. """ mutable struct EnergySystemDesign <: AbstractGUIObj system::AbstractSystem @@ -155,9 +171,10 @@ mutable struct EnergySystemDesign <: AbstractGUIObj wall::Observable{Symbol} file::String visible::Observable{Bool} - inv_data::ProcInvData + inv_data::Vector{ProcInvData} plots::Vector{Makie.AbstractPlot} simplified::Observable{Bool} + alpha::Observable{Float32} end function EnergySystemDesign( system::AbstractSystem, @@ -186,9 +203,10 @@ function EnergySystemDesign( wall, file, visible, - ProcInvData(), + instantiate_inv_data(get_element(system)), Makie.AbstractPlot[], Observable(false), + Observable(1.0f0), ) end @@ -207,11 +225,14 @@ Mutable type for providing a flexible data structure for connections between - **`connection::AbstractElement`** is the EMX connection structure. - **`parent::EnergySystemDesign`** is the parent EnergySystemDesign of the connection. - **`colors::Vector{RGBA{Float32}}`** is the associated colors of the connection. -- **`inv_data::ProcInvData`** stores processed investment data. +- **`inv_data::Vector{ProcInvData}`** stores processed investment data. - **`regular_plots::Vector{Makie.AbstractPlot}`** is a vector with all regular plots associated with the connection. - **`simplified_plots::Vector{Makie.AbstractPlot}`** is a vector with all simplified plots associated with the connection. +- **`alpha::Vector{Observable{Float32}}`** is the alpha value of the connection, observed for changes. + For each line it controls the alpha value, which is used to toggle the visibility of the line when + the connection has not been invested in. """ mutable struct Connection <: AbstractGUIObj from::EnergySystemDesign @@ -219,9 +240,10 @@ mutable struct Connection <: AbstractGUIObj connection::AbstractElement parent::EnergySystemDesign colors::Vector{RGBA{Float32}} - inv_data::ProcInvData + inv_data::Vector{ProcInvData} regular_plots::Vector{Makie.AbstractPlot} simplified_plots::Vector{Makie.AbstractPlot} + alpha::Vector{Observable{Float32}} end function Connection( from::EnergySystemDesign, @@ -237,9 +259,10 @@ function Connection( connection, parent, colors, - ProcInvData(), + instantiate_inv_data(connection), Makie.AbstractPlot[], Makie.AbstractPlot[], + [Observable(1.0f0) for _ ∈ 1:length(colors)], ) end @@ -280,6 +303,8 @@ The main type for the realization of the GUI. gui.axes[:results] object. - **`toggles::Dict{Symbol,Makie.Toggle}`** is a dictionary of the GLMakie toggles linked to the gui.axes[:results] object. +- **`sliders::Dict{Symbol,Makie.Slider}`** is a dictionary of the GLMakie sliders linked + to the gui.axes[:results] object. - **`root_design::EnergySystemDesign`** is the data structure used for the root topology. - **`design::EnergySystemDesign`** is the data structure used for visualizing the topology. - **`model::Union{Model, Dict}`** contains the optimization results. @@ -293,6 +318,7 @@ mutable struct GUI buttons::Dict{Symbol,Makie.Button} menus::Dict{Symbol,Makie.Menu} toggles::Dict{Symbol,Makie.Toggle} + sliders::Dict{Symbol,Makie.Slider} root_design::EnergySystemDesign design::EnergySystemDesign model::Union{Model,Dict} @@ -629,30 +655,26 @@ get_plots(conn::Connection, simplified::Bool) = """ get_inv_times(data::ProcInvData) - get_inv_times(design::AbstractGUIObj) -Returns the `inv_times` field of a `ProcInvData`/`AbstractGUIObj` object `data`. +Returns the `inv_times` field of a `ProcInvData` object `data`. """ get_inv_times(data::ProcInvData) = data.inv_times -get_inv_times(design::AbstractGUIObj) = get_inv_times(get_inv_data(design)) """ get_capex(data::ProcInvData) - get_capex(design::AbstractGUIObj) -Returns the `capex` of the investments of a `ProcInvData`/`AbstractGUIObj` object `data`. +Returns the `capex` of the investments of a `ProcInvData` object `data`. """ get_capex(data::ProcInvData) = data.capex -get_capex(design::AbstractGUIObj) = get_capex(get_inv_data(design)) """ has_invested(data::ProcInvData) - has_invested(data::AbstractGUIObj) + has_invested(data::EnergySystemDesign) -Returns a boolean indicator if investment has occured. +Returns an observable of the boolean indicator for if investment has occured. """ has_invested(data::ProcInvData) = data.invested -has_invested(design::AbstractGUIObj) = has_invested(get_inv_data(design)) +has_invested(design::EnergySystemDesign) = has_invested(get_inv_data(design)[1]) """ get_inv_data(obj::AbstractGUIObj) @@ -675,6 +697,13 @@ Returns the `parent` field of a `AbstractGUIObj` `obj`. """ get_parent(obj::AbstractGUIObj) = obj.parent +""" + get_alpha(obj::AbstractGUIObj) + +Returns the `alpha` field of a `AbstractGUIObj` `obj`. +""" +get_alpha(obj::AbstractGUIObj) = obj.alpha + """ get_fig(gui::GUI) @@ -745,6 +774,13 @@ Returns the `toggle` with name `toggle_name` of a `GUI` `gui`. """ get_toggle(gui::GUI, toggle_name::Symbol) = gui.toggles[toggle_name] +""" + get_slider(gui::GUI, slider_name::Symbol) + +Returns the `slider` with name `slider_name` of a `GUI` `gui`. +""" +get_slider(gui::GUI, slider_name::Symbol) = gui.sliders[slider_name] + """ get_root_design(gui::GUI) diff --git a/src/setup_GUI.jl b/src/setup_GUI.jl index 77a3c26..b73b943 100644 --- a/src/setup_GUI.jl +++ b/src/setup_GUI.jl @@ -53,6 +53,8 @@ to the old EnergyModelsX `case` dictionary. plotting for all hierarchical levels. - **`map_boundary_file::String=""`** is the path to a .geojson file containing geographical boundary data for plotting to be used instead of the default coastlines. +- **`alpha::Number=1.0`** is the alpha value for non-invested connections + and nodes in the topology design. !!! warning "Reading model results from CSV-files" Reading model results from a directory (*i.e.*, `model::String` implying that the results @@ -87,6 +89,7 @@ function GUI( simplified_connection_plotting::Bool = false, simplify_all_levels::Bool = false, map_boundary_file::String = "", + alpha::Number = 1.0, ) # Generate the system topology: @info raw"Setting up the topology design structure" @@ -134,6 +137,7 @@ function GUI( :simplify_all_levels => simplify_all_levels, :marker_to_box_ratio => 0.4, # Ratio between marker size and `Node` box size :map_boundary_file => map_boundary_file, + :alpha => Observable(Float32(alpha)), :autolimits => Dict( :results_op => true, :results_sc => true, @@ -148,7 +152,7 @@ function GUI( ), ) - # gobal variables for legends + # global variables for legends vars[:color_box_padding_px] = 25 # Padding around the legends vars[:color_boxes_width_px] = 20 # Width of the rectangles for the colors in legends vars[:color_boxes_height_px] = vars[:fontsize] # Height of the rectangles for the colors in legends @@ -213,7 +217,8 @@ function GUI( vars[:ctrl_is_pressed] = Ref(false) # Construct the makie figure and its objects - fig, buttons, menus, toggles, axes, legends = create_makie_objects(vars, root_design) + fig, buttons, menus, toggles, sliders, axes, legends = + create_makie_objects(vars, root_design) # Construct screen object manifest = Pkg.Operations.Context().env.manifest @@ -228,7 +233,8 @@ function GUI( ## Create the main structure for the EnergyModelsGUI gui::GUI = GUI( - fig, screen, axes, legends, buttons, menus, toggles, root_design, design, + fig, screen, axes, legends, buttons, menus, toggles, sliders, root_design, + design, transfer_model(model, get_system(root_design)), vars, ) @@ -529,9 +535,22 @@ function create_makie_objects(vars::Dict, design::EnergySystemDesign) gridlayout_taskbar[1, 10]; active = vars[:simplified_connection_plotting], ) + Makie.Label( + gridlayout_taskbar[1, 11], + "Alpha:"; + halign = :right, + fontsize = vars[:fontsize], + justification = :right, + ) + alpha_slider = Makie.Slider( + gridlayout_taskbar[1, 12]; + range = 0:0.01:1, + startvalue = vars[:alpha][], + width = 100 * vars[:fontsize] / 12, + ) # Add the following to add flexibility - Makie.Label(gridlayout_taskbar[1, 11], " "; tellwidth = false) + Makie.Label(gridlayout_taskbar[1, 13], " "; tellwidth = false) # Add buttons related to the ax_results object (where the optimization results are plotted) Makie.Label( @@ -695,6 +714,9 @@ function create_makie_objects(vars::Dict, design::EnergySystemDesign) toggles::Dict{Symbol,Makie.Toggle} = Dict(:expand_all => expand_all_toggle, :simplified => simplified_toggle) + # Collect all sliders into a dictionary + sliders::Dict{Symbol,Makie.Slider} = Dict(:alpha => alpha_slider) + # Collect all axes into a dictionary axes::Dict{Symbol,Makie.Block} = Dict( :topo => ax, :results => ax_results, :info => ax_info, :summary => ax_summary, @@ -710,5 +732,5 @@ function create_makie_objects(vars::Dict, design::EnergySystemDesign) depth_shift = -1.0f0, ) - return fig, buttons, menus, toggles, axes, legends + return fig, buttons, menus, toggles, sliders, axes, legends end diff --git a/src/utils_GUI/GUI_utils.jl b/src/utils_GUI/GUI_utils.jl index 56ed844..54e4344 100644 --- a/src/utils_GUI/GUI_utils.jl +++ b/src/utils_GUI/GUI_utils.jl @@ -358,17 +358,25 @@ function initialize_available_data!(gui) println(io, "Total investment cost: $(format_number(total_capex))\n") has_investments::Bool = false for obj ∈ design - inv_times = get_inv_times(obj) - if !isempty(inv_times) - if !has_investments - println(io, "Investment overview (CAPEX):") - has_investments = true - end - capex = get_capex(obj) - label = get_element_label(obj) - println(io, "\t", label, ":") - for (t, capex) ∈ zip(inv_times, capex) - println(io, "\t\t", t, ": ", format_number(capex)) + inv_data = get_inv_data(obj) + label = get_element_label(obj) + for d ∈ inv_data + tabs = "\t" + inv_times = get_inv_times(d) + if !isempty(inv_times) + if !has_investments + println(io, "Investment overview (CAPEX):") + has_investments = true + end + println(io, tabs, label, ":") + if !isempty(d.id) + tabs *= "\t" + println(io, tabs, d.id, ":") + end + capex = get_capex(d) + for (t, capex) ∈ zip(inv_times, capex) + println(io, tabs, "\t", t, ": ", format_number(capex)) + end end end end @@ -526,10 +534,12 @@ function get_investment_times(gui::GUI, max_inst::Float64) model = get_model(gui) for component ∈ get_root_design(gui) # Ensure to include both the component itself and its modes (in case of a transmission) when checking for investments + alpha = get_alpha(component) elements = get_inv_objs(get_element(component)) - investment_times = String[] - investment_capex = Float64[] - for element ∈ elements + for (e, element) ∈ enumerate(elements) + investment_times = String[] + investment_capex = Float64[] + has_inv::Bool = false for (i, t) ∈ enumerate(𝒯ᴵⁿᵛ) for investment_indicator ∈ investment_indicators # important not to use shorthand loop syntax here due to the break command (exiting both loops in that case) sym = Symbol(investment_indicator) @@ -537,6 +547,7 @@ function get_investment_times(gui::GUI, max_inst::Float64) !isempty(model[sym]) && element ∈ axes(model[sym])[1] val = value(model[sym][element, t]) + has_inv = true if val > get_var(gui, :tol) * max_inst capex::Float64 = 0.0 for capex_field ∈ capex_fields @@ -554,9 +565,27 @@ function get_investment_times(gui::GUI, max_inst::Float64) end end end - end - if !isempty(investment_times) - component.inv_data = ProcInvData(investment_times, investment_capex, true) + inv_data = component.inv_data[e] + if !isempty(investment_times) + inv_data.inv_times = investment_times + inv_data.capex = investment_capex + inv_data.invested[] = true + elseif has_inv + if isa(alpha, Vector) + alpha[e] = get_var(gui, :alpha) + else + component.alpha = get_var(gui, :alpha) + + # Set alpha also for all connections to/from the component + for connection ∈ get_connections(get_parent(component)) + if connection.to == component || connection.from == component + for e ∈ 1:length(get_alpha(connection)) + connection.alpha[e] = get_var(gui, :alpha) + end + end + end + end + end end end end diff --git a/src/utils_GUI/event_functions.jl b/src/utils_GUI/event_functions.jl index 1532c54..e885d0f 100644 --- a/src/utils_GUI/event_functions.jl +++ b/src/utils_GUI/event_functions.jl @@ -12,6 +12,7 @@ function define_event_functions(gui::GUI) expand_all_toggle = get_toggle(gui, :expand_all) expand_all = get_var(gui, :expand_all) simplified_toggle = get_toggle(gui, :simplified) + alpha_slider = get_slider(gui, :alpha) # On zooming, make sure all graphics are adjusted acordingly on(ax_topo.finallimits; priority = 10) do finallimits @@ -361,6 +362,13 @@ function define_event_functions(gui::GUI) return Consume(false) end + # Alpha slider: Handle change in alpha slider for non-investment connections + on(alpha_slider.value; priority = 10) do val + alpha = get_var(gui, :alpha) + alpha[] = convert(eltype(alpha), val) + return Consume(false) + end + # Save button: Handle click on the save button (save the altered coordinates) on(get_button(gui, :save).clicks; priority = 10) do _ save_design(get_design(gui)) diff --git a/src/utils_GUI/topo_axis_utils.jl b/src/utils_GUI/topo_axis_utils.jl index d6ac638..0166dac 100644 --- a/src/utils_GUI/topo_axis_utils.jl +++ b/src/utils_GUI/topo_axis_utils.jl @@ -315,29 +315,39 @@ function connect!(gui::GUI, connection::Connection, two_way::Bool) end # Extract observables from the tuple - xy_midpoints = @lift fill($triple[1], no_colors) - θs = @lift fill($triple[2], no_colors) + xy_midpoints = @lift $triple[1] + θs = @lift $triple[2] ax = get_ax(gui, :topo) visible = get_visible(parent) simplified_initial::Bool = simplified[] visible_plot = @lift $visible && ($simplified == simplified_initial) markersize = @lift data_to_pixel(gui, marker_to_box_ratio * $Δh) - sctr = scatter!( - ax, - xy_midpoints; - marker = arrow_parts, - markersize = markersize, - rotation = θs, - color = colors, - inspectable = false, - depth_shift = get_var(gui, :depth_shift_lines), - visible = visible_plot, - ) - sctr.kw[:EMGUI_obj] = connection - push!(get_plots(connection), sctr) + alphas = get_alpha(connection) + max_alpha = lift(alphas...) do a... + maximum(a) + end for j ∈ 1:no_colors + alpha = @lift $simplified ? $max_alpha : $(alphas[j]) + sctr = scatter!( + ax, + xy_midpoints; + marker = arrow_parts[j], + markersize = markersize, + rotation = θs, + color = colors[j], + inspectable = false, + depth_shift = get_var(gui, :depth_shift_lines), + visible = visible_plot, + alpha = alpha, + ) + sctr.kw[:EMGUI_obj] = connection + push!(get_plots(connection), sctr) + end + + for j ∈ 1:no_colors + alpha = @lift $simplified ? $max_alpha : $(alphas[j]) pts_lines = @lift $triple[3][j] lns = lines!( ax, @@ -349,6 +359,7 @@ function connect!(gui::GUI, connection::Connection, two_way::Bool) inspectable = true, depth_shift = get_var(gui, :depth_shift_lines), visible = visible_plot, + alpha = alpha, ) lns.kw[:EMGUI_obj] = connection push!(get_plots(connection), lns) @@ -447,6 +458,7 @@ function draw_box!(gui::GUI, design::EnergySystemDesign) depth_shift = get_var(gui, :depth_shift_components), stroke_depth_shift = get_var(gui, :depth_shift_components) - 1.0f-5, visible = get_visible(get_parent(design)), + alpha = get_alpha(design), ) # Create a white background rectangle to hide lines from connections add_inspector_to_poly!(white_rect2, (self, i, p) -> get_hover_string(design)) @@ -464,11 +476,12 @@ function draw_box!(gui::GUI, design::EnergySystemDesign) color = WHITE, inspectable = true, strokewidth = get_var(gui, :linewidth), - strokecolor = design.color, + strokecolor = get_color(design), linestyle = linestyle, depth_shift = get_var(gui, :depth_shift_components), stroke_depth_shift = get_var(gui, :depth_shift_components) - 1.0f-5, visible = get_visible(get_parent(design)), + alpha = get_alpha(design), ) # Create a white background rectangle to hide lines from connections add_inspector_to_poly!(white_rect, (self, i, p) -> get_hover_string(design)) @@ -552,6 +565,7 @@ function draw_icon!(gui::GUI, design::EnergySystemDesign) depth_shift = get_var(gui, :depth_shift_components), stroke_depth_shift = get_var(gui, :depth_shift_components) - 1.0f-5, visible = get_visible(get_parent(design)), + alpha = get_alpha(design), ) add_inspector_to_poly!(polys, (self, i, p) -> get_hover_string(design)) polys.kw[:EMGUI_obj] = design @@ -575,6 +589,7 @@ function draw_icon!(gui::GUI, design::EnergySystemDesign) depth_shift = get_var(gui, :depth_shift_components), stroke_depth_shift = get_var(gui, :depth_shift_components) - 1.0f-5, visible = get_visible(get_parent(design)), + alpha = get_alpha(design), ) add_inspector_to_poly!( @@ -599,6 +614,7 @@ function draw_icon!(gui::GUI, design::EnergySystemDesign) inspector_label = (self, i, p) -> get_hover_string(design), depth_shift = get_var(gui, :depth_shift_components), visible = get_visible(get_parent(design)), + alpha = get_alpha(design), ) icon_image.kw[:EMGUI_obj] = design push!(get_plots(design), icon_image) @@ -677,9 +693,10 @@ function draw_label!(gui::GUI, component::EnergySystemDesign) align = alignment_obs, fontsize = get_var(gui, :fontsize), inspectable = false, - color = has_invested(component) ? RED : BLACK, + color = has_invested(component)[] ? RED : BLACK, depth_shift = get_var(gui, :depth_shift_components), visible = get_visible(get_parent(component)), + alpha = get_alpha(component), ) label_text.kw[:EMGUI_obj] = component push!(get_plots(component), label_text) @@ -766,13 +783,22 @@ Return the string for a EMB.Node/Area/Link/Transmission to be shown on hovering. function get_hover_string(obj::AbstractGUIObj) element = get_element(obj) label = get_element_label(element) - inv_times = get_inv_times(obj) + inv_data = get_inv_data(obj) io = IOBuffer() print(io, "$label ($(nameof(typeof(element))))") - if !isempty(inv_times) - capex = get_capex(obj) - for (t, c) ∈ zip(inv_times, capex) - print(io, "\n\t", t, ": ", format_number(c)) + for d ∈ inv_data + inv_times = get_inv_times(d) + tabs = "" + if !isempty(inv_times) + if !isempty(d.id) + tabs *= "\t" + print(io, "\n", tabs, d.id, ":") + end + capex = get_capex(d) + tabs *= "\t" + for (t, c) ∈ zip(inv_times, capex) + print(io, "\n", tabs, t, ": ", format_number(c)) + end end end return String(take!(io)) diff --git a/test/test_interactivity.jl b/test/test_interactivity.jl index 3e6b991..3466a25 100644 --- a/test/test_interactivity.jl +++ b/test/test_interactivity.jl @@ -22,6 +22,8 @@ pin_plot_button = get_button(gui, :pin_plot) expand_all_toggle = get_toggle(gui, :expand_all) simplified_toggle = get_toggle(gui, :simplified) +alpha_slider = get_slider(gui, :alpha) + # Test specific GUI functionalities @testset "Test interactivity" verbose = true begin op_cost = [3371970.00359, 5382390.00598, 2010420.00219] @@ -179,6 +181,32 @@ simplified_toggle = get_toggle(gui, :simplified) end end end + + @testset "Test changing alpha value" begin + alpha_slider_2 = get_slider(gui_2, :alpha) + Bergen_Trondheim = connections_2[2] + + pick_component!(gui_2, Bergen_Trondheim, :topo) + update!(gui_2) + + new_alpha = 0.5f0 + alpha_slider_2.value[] = new_alpha + + # Test that a TransmissionMode has updated its value + @test all(plot.alpha[] == new_alpha for plot ∈ get_plots(Bergen_Trondheim)) + + # Test that a node in the Oslo area has updated its value + Oslo = components_2[1] + node1 = get_component(Oslo, 7) # fetch node n_7 + @test all(plot.alpha[] == new_alpha for plot ∈ get_plots(node1)) + + # Test that links to the n_7 node also have the updated alpha value + for connection ∈ get_connections(Oslo) + if node1 == connection.from || node1 == connection.to + @test all(plot.alpha[] == new_alpha for plot ∈ get_plots(connection)) + end + end + end EMGUI.close(gui_2) # Test the open button functionality diff --git a/test/utils.jl b/test/utils.jl index 7f68a06..861014d 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -23,6 +23,7 @@ import EnergyModelsGUI: get_var, get_xy, get_toggle, + get_slider, get_ax, update_info_box!, update_available_data_menu!,