How to change parmaters for solver in GLMakie?

Hello,
I am trying to make an interactive figure of a SIV system.
I have implemented a parameter vector with Parsers so that each parameter is accessed by name. But how can I change such a vector with lift from GLMakie?
The script below works until the sliders are not used (and the values not changed). Afterards I get the error:

Error in callback:
MethodError: no method matching setindex!(::@NamedTuple{μ::Float64, κ::Float64, ω::Float64, δ::Float64, η::Float64, β::Int64, λ::Int64}, ::Float64, ::Int64)
Stacktrace:
  [1] (::var"#5#6")(val::Float64)
    @ Main ~/Documents/Model/MkBact_1.jl:109
  [2] #invokelatest#2
    @ ./essentials.jl:892 [inlined]
  [3] invokelatest
    @ ./essentials.jl:889 [inlined]
  [4] notify
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:206 [inlined]
  [5] setindex!(observable::Observable, val::Any)
    @ Observables ~/.julia/packages/Observables/YdEbO/src/Observables.jl:123
  [6] (::Makie.var"#1890#1905"{Slider, Observable{Any}})(i::Int64)
    @ Makie ~/.julia/packages/Makie/VRavR/src/makielayout/blocks/slider.jl:63
  [7] #invokelatest#2
    @ ./essentials.jl:892 [inlined]
  [8] invokelatest
    @ ./essentials.jl:889 [inlined]
  [9] notify
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:206 [inlined]
 [10] setindex!(observable::Observable, val::Any)
    @ Observables ~/.julia/packages/Observables/YdEbO/src/Observables.jl:123
 [11] (::Makie.var"#1896#1911"{Slider, Observable{Int64}, Observable{Vector{Point{2, Float32}}}, Observable{Any}})(event::MouseEvent)
    @ Makie ~/.julia/packages/Makie/VRavR/src/makielayout/blocks/slider.jl:128
 [12] (::Makie.var"#1371#1372"{Makie.var"#1896#1911"{Slider, Observable{Int64}, Observable{Vector{Point{2, Float32}}}, Observable{Any}}})(event::MouseEvent)
    @ Makie ~/.julia/packages/Makie/VRavR/src/makielayout/mousestatemachine.jl:94
 [13] #invokelatest#2
    @ ./essentials.jl:892 [inlined]
 [14] invokelatest
    @ ./essentials.jl:889 [inlined]
 [15] notify
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:206 [inlined]
 [16] setindex!
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:123 [inlined]
 [17] (::Makie.var"#1441#1443"{Scene, Base.RefValue{Bool}, Base.RefValue{Union{Nothing, Makie.Mouse.Button}}, Base.RefValue{Float64}, Base.RefValue{Float64}, Base.RefValue{Bool}, Base.RefValue{Bool}, Base.RefValue{Union{Nothing, Makie.Mouse.Button}}, Base.RefValue{Bool}, Base.RefValue{Point{2, Float32}}, Base.RefValue{Point{2, Float32}}, Base.RefValue{Makie.Mouse.Action}, Observable{MouseEvent}, Float64, Module})(event::Makie.MouseButtonEvent)
    @ Makie ~/.julia/packages/Makie/VRavR/src/makielayout/mousestatemachine.jl:299
 [18] #invokelatest#2
    @ ./essentials.jl:892 [inlined]
 [19] invokelatest
    @ ./essentials.jl:889 [inlined]
 [20] notify
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:206 [inlined]
 [21] setindex!
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:123 [inlined]
 [22] (::GLMakie.var"#mousebuttons#168"{Observable{Makie.MouseButtonEvent}})(window::GLFW.Window, button::GLFW.MouseButton, action::GLFW.Action, mods::Int32)
    @ GLMakie ~/.julia/packages/GLMakie/QyIWu/src/events.jl:102
 [23] _MouseButtonCallbackWrapper(window::GLFW.Window, button::GLFW.MouseButton, action::GLFW.Action, mods::Int32)
    @ GLFW ~/.julia/packages/GLFW/BWxfF/src/callback.jl:43
 [24] PollEvents
    @ ~/.julia/packages/GLFW/BWxfF/src/glfw3.jl:620 [inlined]
 [25] pollevents(screen::GLMakie.Screen{GLFW.Window})
    @ GLMakie ~/.julia/packages/GLMakie/QyIWu/src/screen.jl:449
 [26] on_demand_renderloop(screen::GLMakie.Screen{GLFW.Window})
    @ GLMakie ~/.julia/packages/GLMakie/QyIWu/src/screen.jl:937
 [27] renderloop(screen::GLMakie.Screen{GLFW.Window})
    @ GLMakie ~/.julia/packages/GLMakie/QyIWu/src/screen.jl:963
 [28] (::GLMakie.var"#69#70"{GLMakie.Screen{GLFW.Window}})()
    @ GLMakie ~/.julia/packages/GLMakie/QyIWu/src/screen.jl:824

How can I properly change the parameters for the solver by name?

Here is the code I have written (courtesy Steffen Plunder):

using GLMakie, DifferentialEquations, Parsers
function odeSolver!(du, u, p, t) 
    μ = p.μ     # bacterial growth rate
    κ = p.κ     # bacterial carrying capacity
    ω = p.ω     # system wash-out rate
    δ = p.δ     # phagial infection rate
    η = p.η     # phagial lysis rate (inverse latency)
    β = p.β     # phagial burst size
    λ = p.λ     # phagial decay rate
                # du[1] = S; du[2] = I; du[3] = V
    ρ = 1 - (u[1] + u[2])/κ     # rho: logistic factor
    ϡ = (δ*u[1]*u[3])           # upsampi : infected bacteria
    du[1] = (μ*u[1]*ρ) - ϡ             - (ω*u[1])
    du[2] =              ϡ - (η*u[2])  - (ω*u[2])
    du[3] = (β*η*u[2]) - ϡ - (λ*u[3])  - (ω*u[3])
end

## initial parameters
begin
    mu = 0.16       # μ: default growth rate
    kappa = 2.2e7   # κ: default carrying capacity
    omega = 0.05    # ω: default outflow
    eta = 0.025     # η: default τ reciprocal    
    delta = 1e-9    # δ: default adsorption rate 
    beta = 50       # β: default burst size 
    lambda = 0      # λ: default decay rate
    s0 = 1e5        # default starting amount of naive bacteria
    i0 = 0          # default starting amount of infected bacteria
    v0 = 1e5        # default starting amount of phages
    tm = 2000.0     # default time span 
end

## set ODE
begin
    u0 = [s0, i0, v0]
    tspan = [0.0, tm] 
    parms = (μ=mu, κ=kappa, ω=omega, δ=delta, η=eta, β=beta, λ=lambda)
end

## run ODE
begin
    prob = ODEProblem(odeSolver!, u0, tspan, parms)
    soln = solve(prob, Rosenbrock23())
end

## set obervables
p_mod = Observable(parms)
u_mod = Observable("")
lab_str = Observable("")  

## plot
# sliders
S_values = LinRange(0.0, 1.0e7, 100) 
I_values = LinRange(0.0, 1.0e7, 100)
V_values = LinRange(0.0, 1.0e7, 100)
mu_values = LinRange(0.0, 1.0, 100) 
kappa_values = LinRange(0.0, 1.0e9, 100)
omega_values = LinRange(0.0, 1.0, 100)
# instantiate figure
fig = Figure()
# set axis
ax = Axis(fig[1, 1:2], title = title_str)
# add sliders
Label(fig[2,1], "Growth rate")
mu_sld = Slider(fig[2, 2], range = mu_values, startvalue = mu)
Label(fig[3,1], "Carrying capacity")
k_sld = Slider(fig[3, 2], range = kappa_values, startvalue = kappa)
Label(fig[4,1], "Outflow rate")
o_sld = Slider(fig[4, 2], range = omega_values, startvalue = omega)
# update initial concentration
T = LinRange(tspan[1], tspan[2], 500)
# update parameters
on(mu_sld.value) do val 
    p_mod.val[1] = val 
    p_mod[] = p_mod[]  
end
on(k_sld.value) do val 
    p_mod.val[2] = val 
    p_mod[] = p_mod[]  
end
on(o_sld.value) do val 
    p_mod.val[3] = val 
    p_mod[] = p_mod[]  
end
data = lift(p_mod) do p_new
    # this code is called each time the slider value changes, the new value is 'p_val':
    title_str[] = "Growth rate = $(round(p_new[1], digits = 2)), 
        Carrying capacity = $(round(p_new[2], digits = 2)),
        Outflow rate = $(round(p_new[3], digits = 2))"
    return solve(prob, Rosenbrock23(), p = p_new, saveat = T)
end
# draw
X = @lift $data[1,:]
Y = @lift $data[2,:]

lines!(ax, T, X)
lines!(ax, T, Y)
fig 

I also tried with:

julia> data = lift(p_mod) do p_new
           new_parms = (μ=p_new, κ=kappa, ω=omega, δ=delta, η=eta, β=beta, λ=lambda)
           return solve(prob, Rosenbrock23(), p = new_parms, saveat = T)
       end
ERROR: MethodError: no method matching *(::@NamedTuple{μ::Float64, κ::Float64, ω::Float64, δ::Float64, η::Float64, β::Int64, λ::Int64}, ::Float64)

Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...)
   @ Base operators.jl:587
  *(::Polynomials.AbstractPolynomial, ::Union{Number, Matrix})
   @ Polynomials ~/.julia/packages/Polynomials/5ZhzG/src/common.jl:1041
  *(::ChainRulesCore.ZeroTangent, ::Any)
   @ ChainRulesCore ~/.julia/packages/ChainRulesCore/zgT0R/src/tangent_arithmetic.jl:104
  ...

Stacktrace:
  [1] *
    @ ./operators.jl:587 [inlined]
  [2] odeSolver!(du::Vector{…}, u::Vector{…}, p::@NamedTuple{…}, t::Float64)
    @ Main ~/Documents/Model/MkBact_1.jl:17
  [3] (::SciMLBase.Void{typeof(odeSolver!)})(::Vector{Float64}, ::Vararg{Any})
    @ SciMLBase ~/.julia/packages/SciMLBase/Dwomw/src/utils.jl:482
  [4] (::FunctionWrappers.CallWrapper{…})(f::SciMLBase.Void{…}, arg1::Vector{…}, arg2::Vector{…}, arg3::@NamedTuple{…}, arg4::Float64)
    @ FunctionWrappers ~/.julia/packages/FunctionWrappers/Q5cBx/src/FunctionWrappers.jl:65
  [5] macro expansion
    @ ~/.julia/packages/FunctionWrappers/Q5cBx/src/FunctionWrappers.jl:137 [inlined]
  [6] do_ccall
    @ ~/.julia/packages/FunctionWrappers/Q5cBx/src/FunctionWrappers.jl:125 [inlined]
  [7] FunctionWrapper
    @ ~/.julia/packages/FunctionWrappers/Q5cBx/src/FunctionWrappers.jl:144 [inlined]
  [8] _call
    @ ~/.julia/packages/FunctionWrappersWrappers/9XR0m/src/FunctionWrappersWrappers.jl:12 [inlined]
  [9] FunctionWrappersWrapper
    @ ~/.julia/packages/FunctionWrappersWrappers/9XR0m/src/FunctionWrappersWrappers.jl:10 [inlined]
 [10] ODEFunction
    @ ~/.julia/packages/SciMLBase/Dwomw/src/scimlfunctions.jl:2168 [inlined]
 [11] initialize!(integrator::OrdinaryDiffEq.ODEIntegrator{…}, cache::OrdinaryDiffEq.Rosenbrock23Cache{…})
    @ OrdinaryDiffEq ~/.julia/packages/OrdinaryDiffEq/DmspS/src/perform_step/rosenbrock_perform_step.jl:10
 [12] __init(prob::ODEProblem{…}, alg::Rosenbrock23{…}, timeseries_init::Tuple{}, ts_init::Tuple{}, ks_init::Tuple{}, recompile::Type{…}; saveat::LinRange{…}, tstops::Tuple{}, d_discontinuities::Tuple{}, save_idxs::Nothing, save_everystep::Bool, save_on::Bool, save_start::Bool, save_end::Nothing, callback::Nothing, dense::Bool, calck::Bool, dt::Float64, dtmin::Float64, dtmax::Float64, force_dtmin::Bool, adaptive::Bool, gamma::Rational{…}, abstol::Nothing, reltol::Nothing, qmin::Rational{…}, qmax::Int64, qsteady_min::Int64, qsteady_max::Rational{…}, beta1::Nothing, beta2::Nothing, qoldinit::Rational{…}, controller::Nothing, fullnormalize::Bool, failfactor::Int64, maxiters::Int64, internalnorm::typeof(DiffEqBase.ODE_DEFAULT_NORM), internalopnorm::typeof(LinearAlgebra.opnorm), isoutofdomain::typeof(DiffEqBase.ODE_DEFAULT_ISOUTOFDOMAIN), unstable_check::typeof(DiffEqBase.ODE_DEFAULT_UNSTABLE_CHECK), verbose::Bool, timeseries_errors::Bool, dense_errors::Bool, advance_to_tstop::Bool, stop_at_next_tstop::Bool, initialize_save::Bool, progress::Bool, progress_steps::Int64, progress_name::String, progress_message::typeof(DiffEqBase.ODE_DEFAULT_PROG_MESSAGE), progress_id::Symbol, userdata::Nothing, allow_extrapolation::Bool, initialize_integrator::Bool, alias_u0::Bool, alias_du0::Bool, initializealg::OrdinaryDiffEq.DefaultInit, kwargs::@Kwargs{})
    @ OrdinaryDiffEq ~/.julia/packages/OrdinaryDiffEq/DmspS/src/solve.jl:518
 [13] __init (repeats 5 times)
    @ ~/.julia/packages/OrdinaryDiffEq/DmspS/src/solve.jl:11 [inlined]
 [14] #__solve#761
    @ ~/.julia/packages/OrdinaryDiffEq/DmspS/src/solve.jl:6 [inlined]
 [15] __solve
    @ ~/.julia/packages/OrdinaryDiffEq/DmspS/src/solve.jl:1 [inlined]
 [16] #solve_call#34
    @ ~/.julia/packages/DiffEqBase/z0BFe/src/solve.jl:612 [inlined]
 [17] solve_up(prob::ODEProblem{…}, sensealg::Nothing, u0::Vector{…}, p::@NamedTuple{…}, args::Rosenbrock23{…}; kwargs::@Kwargs{…})
    @ DiffEqBase ~/.julia/packages/DiffEqBase/z0BFe/src/solve.jl:1081
 [18] solve_up
    @ ~/.julia/packages/DiffEqBase/z0BFe/src/solve.jl:1067 [inlined]
 [19] solve(prob::ODEProblem{…}, args::Rosenbrock23{…}; sensealg::Nothing, u0::Nothing, p::@NamedTuple{…}, wrap::Val{…}, kwargs::@Kwargs{…})
    @ DiffEqBase ~/.julia/packages/DiffEqBase/z0BFe/src/solve.jl:1004
 [20] (::var"#21#22")(p_new::@NamedTuple{μ::Float64, κ::Float64, ω::Float64, δ::Float64, η::Float64, β::Int64, λ::Int64})
    @ Main ~/Documents/Model/MkBact_1.jl:123
 [21] #map#13
    @ ~/.julia/packages/Observables/YdEbO/src/Observables.jl:570 [inlined]
 [22] map(::var"#21#22", ::Observable{@NamedTuple{…}})
    @ Observables ~/.julia/packages/Observables/YdEbO/src/Observables.jl:568
 [23] top-level scope
    @ ~/Documents/Model/MkBact_1.jl:120
Some type information was truncated. Use `show(err)` to see complete types.

Note that the error message says no method matching setindex!(::@NamedTuple.... You’re trying to mutate a named tuple, but named tuples are immutable.

Look at this line:

p_mod = Observable(parms)

Here parms is a named tuple. Later you do

p_mod.val[1] = val

This tries to change a value in the named tuple. You can’t do that. Either change this line to replace the whole named tuple, or use another data structure that’s mutable…