From 498dc494f8f08d04ea6eaea0f73f20936766146f Mon Sep 17 00:00:00 2001 From: Daniel Vedder <daniel.vedder@idiv.de> Date: Thu, 26 Oct 2023 12:04:17 +0200 Subject: [PATCH] Fixed the memory leak!! :D closes #12 --- src/GUI.jl | 66 +++++++++++++++++++++++------------------------- src/main.qml | 2 +- src/variables.jl | 10 ++++---- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/GUI.jl b/src/GUI.jl index 9f03a22..4cab0ca 100644 --- a/src/GUI.jl +++ b/src/GUI.jl @@ -50,44 +50,42 @@ function saveoutput() end function render_map(screen) - global model, mapimage, landcovermap + global model, mapimage launching[] && return display(screen, Figure().scene) # blank screen at launch println("Updating map") - #FIXME repeatedly calling `visualisemap` causes the memory leak - # (regardless of whether individuals are plotted or just the map) - #mapimage[] = visualisemap(model, date[]-Day(1), landcovermap) - empty!(mapimage[]) - mapimage[] = vismap(model, date[]-Day(1), landcovermap) - display(screen, mapimage[]) -end - -function vismap(model::AgentBasedModel,date=nothing,landcover=nothing) - # load and plot the map - # Note: if the landcover map is supplied, it needs to be rotr90'ed - isnothing(landcover) && (landcover = rotr90(load(@param(world.landcovermap)))) - f = Figure() - ax = Axis(f[1,1]) - hidedecorations!(ax) - image!(f[1,1], landcover) - ax.aspect = DataAspect() - # check if there are individuals and plot them - inds = model.datatables["individuals"] - if iszero(size(inds)[1]) - @debug "No individual data to map" - return f.scene - end - isnothing(date) && (date = inds.Date[end]) - for s in unique(inds.Species) - points = @select!(@subset(inds, :Species .== s, :Date .== date), - :X, :Y) - # The origin in Makie is in the bottom-left rather than in the top-left as - # on the model map, so we have to invert the Y coordinates - @transform!(points, :Y = size(model.landscape)[2] .- :Y) - scatter!(f[1,1], Matrix{Float32}(points), markersize=8) + if isnothing(mapimage) + # I'm reimplementing `visualisemap()` here, because I need to use Observables + # to keep the figure updated (if I use multiple plots, I get a memory leak, + # see here: https://github.com/MakieOrg/Makie.jl/issues/795) + landcover = rotr90(load(@param(world.landcovermap))) + mapimage = Figure() + ax = Axis(mapimage[1,1]) + hidedecorations!(ax) + image!(mapimage[1,1], landcover) + ax.aspect = DataAspect() + inds = @lift(@transform!(@subset(model.datatables["individuals"], + :Date .== $date-Day(1)), + :Y = size(landcover)[2] .- :Y)) + on(inds) do i + println("Updated `inds`, length $(size(inds[])[1])") + end + if size(inds[])[1] > 0 + update_theme!(palette=(color=cgrad(:seaborn_bright, + length(@param(nature.targetspecies))),), + cycle=[:color]) + for s in @param(nature.targetspecies) + points = @lift(Matrix{Float32}( + @select!(@subset($inds, :Species .== s), :X, :Y))) + on(points) do i + println("Updated `points` of species $s") + end + scatter!(mapimage[1,1], points, markersize=8) + end + end end - f.scene + display(screen, mapimage.scene) end - + function render_plot(screen) #FIXME Y axis is too small -> lines not shown? global model diff --git a/src/main.qml b/src/main.qml index 06f179e..6ce7279 100644 --- a/src/main.qml +++ b/src/main.qml @@ -204,7 +204,7 @@ Distributed under the MIT license." onUpdateMakie: { dateText.text = Julia.datestring(); mapviewport.update(); - //plotviewport.update(); + plotviewport.update(); } signal showSplash() onShowSplash: { diff --git a/src/variables.jl b/src/variables.jl index 01a87ef..baa4e42 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -1,16 +1,17 @@ ### PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems ### -### This file contains all globals and Observables. +### This file contains all global variables and Observables. ### -## GUI parameters +## GUI variables global model = nothing -global landcovermap = nothing global runsimulation = () -> nothing -#global newsimulation = () -> nothing +global newsimulation = () -> nothing global timer = nothing +global mapimage = nothing +global plotimage = nothing const configfile = Observable("guiparams.toml") const launching = Observable(false) @@ -21,7 +22,6 @@ const progress = Observable(0.0) const delay = Observable(0.5) const runbuttontext = Observable(">>") const runbuttontip = Observable("Run") -const mapimage = Observable(Figure().scene) ## configuration parameters -- GitLab