From 22268d3439f0e76ce7ed564f2aaa5a772257930c Mon Sep 17 00:00:00 2001
From: Daniel Vedder <daniel.vedder@idiv.de>
Date: Fri, 6 Oct 2023 14:56:29 +0200
Subject: [PATCH] Activated Makie plotting

Compile time still increased to 50s (from 15s), but at the moment I
can just about live with that.
---
 Manifest.toml                | 14 +++++++++++++-
 Project.toml                 |  1 +
 src/Persefone.jl             | 10 +++++-----
 src/analysis/makieplots.jl   | 11 ++++++++---
 src/core/output.jl           | 30 +++++++++++++++---------------
 src/core/simulation.jl       |  2 +-
 src/nature/ecologicaldata.jl |  4 ++--
 src/world/landscape.jl       | 14 +++++++-------
 8 files changed, 52 insertions(+), 34 deletions(-)

diff --git a/Manifest.toml b/Manifest.toml
index 72340ca..77e1ea9 100644
--- a/Manifest.toml
+++ b/Manifest.toml
@@ -2,7 +2,7 @@
 
 julia_version = "1.9.3"
 manifest_format = "2.0"
-project_hash = "37a066281d4eb014f2c662ec23deb18c4d89d4e2"
+project_hash = "ce171af7d57f8fcad6d5ea123349f467345ec803"
 
 [[deps.AbstractFFTs]]
 deps = ["LinearAlgebra"]
@@ -165,6 +165,12 @@ git-tree-sha1 = "4435559dc39793d53a9e3d278e185e920b4619ef"
 uuid = "0e736298-9ec6-45e8-9647-e4fc86a2fe38"
 version = "0.2.8"
 
+[[deps.BinaryProvider]]
+deps = ["Libdl", "Logging", "SHA"]
+git-tree-sha1 = "ecdec412a9abc8db54c0efc5548c64dfce072058"
+uuid = "b99e7846-7c00-51b0-8f62-c81ae34c0232"
+version = "0.5.10"
+
 [[deps.BitFlags]]
 git-tree-sha1 = "43b1a4a8f797c1cddadf60499a8a077d4af2cd2d"
 uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35"
@@ -822,6 +828,12 @@ git-tree-sha1 = "bca20b2f5d00c4fbc192c3212da8fa79f4688009"
 uuid = "82e4d734-157c-48bb-816b-45c225c6df19"
 version = "0.6.7"
 
+[[deps.ImageMagick]]
+deps = ["BinaryProvider", "FileIO", "ImageCore", "InteractiveUtils", "Libdl", "Pkg", "Random"]
+git-tree-sha1 = "54dfa264804aefc44630c96619474e683a522d78"
+uuid = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
+version = "0.7.9"
+
 [[deps.ImageMetadata]]
 deps = ["AxisArrays", "ImageAxes", "ImageBase", "ImageCore"]
 git-tree-sha1 = "355e2b974f2e3212a75dfb60519de21361ad3cb7"
diff --git a/Project.toml b/Project.toml
index 463fe12..d98f001 100644
--- a/Project.toml
+++ b/Project.toml
@@ -14,6 +14,7 @@ Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
 Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
 FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
 GeoArrays = "2fb1d81b-e6a0-5fc5-82e6-8e06903437ab"
+ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
 Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
 LoggingExtras = "e6f89c97-d47a-5376-807f-9c37f3926c36"
 Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
diff --git a/src/Persefone.jl b/src/Persefone.jl
index 165f399..a3550f2 100644
--- a/src/Persefone.jl
+++ b/src/Persefone.jl
@@ -25,7 +25,7 @@ using
     GeoArrays, #XXX this is a big dependency - can we get rid of it?
     Logging,
     LoggingExtras,
-    #CairoMakie,
+    CairoMakie,
     Random,
     Serialization,
     StableRNGs,
@@ -80,9 +80,9 @@ export
     stepsimulation!,
     createevent!,
     finalise!,
-    #visualisemap,
-    #populationtrends,
-    #visualiseoutput,
+    visualisemap,
+    populationtrends,
+    visualiseoutput,
     savemodelobject,
     loadmodelobject
 
@@ -90,7 +90,7 @@ export
 ## b references something from file a, it must be included later)
 include("core/input.jl")
 include("core/output.jl")
-#include("analysis/makieplots.jl")
+include("analysis/makieplots.jl")
 
 include("world/landscape.jl")
 include("world/weather.jl")
diff --git a/src/analysis/makieplots.jl b/src/analysis/makieplots.jl
index 00e871d..3422917 100644
--- a/src/analysis/makieplots.jl
+++ b/src/analysis/makieplots.jl
@@ -22,6 +22,8 @@ function visualisemap(model::AgentBasedModel, date::Union{Date,Nothing}=nothing)
     image!(f[1,1], rotr90(landcover))
     ax.aspect = DataAspect()
     # plot individuals
+    #FIXME this function displays the individuals in a different location than the
+    # R script does - somewhere, I'm confusing coordinates...
     for s in unique(inds.Species)
         points = @select!(@subset(inds, :Species .== s, :Date .== date), :X, :Y)
         scatter!(f[1,1], Matrix{Float32}(points), markersize=10)
@@ -38,8 +40,11 @@ Returns a Makie figure object.
 function populationtrends(model::AgentBasedModel)
     pops = model.datatables["populations"]
     f = Figure()
-    for s in unique(inds.Species)
-        points = @select!(@subset(pops, :Species .== s), :X, :Y)
-        lines!(f[1,1], Matrix{Float32}(points), markersize=10)
+    ax = Axis(f[1,1])
+    for s in unique(pops.Species)
+        points = @select!(@subset(pops, :Species .== s), :Abundance)
+        lines!(f[1,1], Vector{Float32}(points.Abundance))
     end
+    #TODO prettify, add legend & labels
+    f
 end
diff --git a/src/core/output.jl b/src/core/output.jl
index 0ce93ea..f9366bb 100644
--- a/src/core/output.jl
+++ b/src/core/output.jl
@@ -208,21 +208,21 @@ function outputdata(model::AgentBasedModel)
     end
 end
 
-# """
-#     visualiseoutput(model)
-
-# Cycle through all data outputs and call their respective plot functions,
-# saving each figure as a PDF.
-# """
-# function visualiseoutput(model::AgentBasedModel)
-#     #TODO write tests
-#     @debug "Visualising output."
-#     for output in model.dataoutputs
-#         isnothing(output.plotfunction) && continue
-#         figure = output.plotfunction(model)
-#         save(joinpath(@param(core.outdir), output.name*".pdf"), figure)
-#     end
-# end
+"""
+    visualiseoutput(model)
+
+Cycle through all data outputs and call their respective plot functions,
+saving each figure as a PDF.
+"""
+function visualiseoutput(model::AgentBasedModel)
+    #TODO write tests
+    @debug "Visualising output."
+    for output in model.dataoutputs
+        isnothing(output.plotfunction) && continue
+        figure = output.plotfunction(model)
+        save(joinpath(@param(core.outdir), output.name*".pdf"), figure)
+    end
+end
 
 """
     savemodelobject(model, filename)
diff --git a/src/core/simulation.jl b/src/core/simulation.jl
index 21bff1a..51dfdbf 100644
--- a/src/core/simulation.jl
+++ b/src/core/simulation.jl
@@ -152,7 +152,7 @@ function finalise!(model::AgentBasedModel)
     with_logger(model.logger) do
         @info "Simulated $(model.date-@param(core.startdate))."
         @info "Simulation run completed at $(Dates.now()),\nwrote output to $(@param(core.outdir))."
-        #visualiseoutput(model) #TODO
+        visualiseoutput(model)
         model
     end
 end
diff --git a/src/nature/ecologicaldata.jl b/src/nature/ecologicaldata.jl
index 5f65954..99bb68d 100644
--- a/src/nature/ecologicaldata.jl
+++ b/src/nature/ecologicaldata.jl
@@ -14,9 +14,9 @@ Create output files for each data group collected by the nature model.
 """
 function initecologicaldata(model::AgentBasedModel)
     newdataoutput!(model, "populations", ["Date", "Species", "Abundance"],
-                   savepopulationdata, @param(nature.popoutfreq), visualisemap)
+                   savepopulationdata, @param(nature.popoutfreq), populationtrends)
     newdataoutput!(model, "individuals", ["Date","ID","X","Y","Species","Sex","Age"],
-                   saveindividualdata, @param(nature.indoutfreq), populationtrends)
+                   saveindividualdata, @param(nature.indoutfreq), visualisemap)
 end
 
 """
diff --git a/src/world/landscape.jl b/src/world/landscape.jl
index d97a91c..4d8e283 100644
--- a/src/world/landscape.jl
+++ b/src/world/landscape.jl
@@ -46,19 +46,19 @@ function initlandscape(landcovermap::String, farmfieldsmap::String)
     #TODO replace errors with exception
     !(isfile(landcovermap)) && Base.error("Landcover map $(landcovermap) doesn't exist.")
     !(isfile(farmfieldsmap)) && Base.error("Field map $(farmfieldsmap) doesn't exist.")
-    landcover = GeoArrays.read(landcovermap)
-    farmfields = GeoArrays.read(farmfieldsmap)
+    #XXX can I read the files in using FileIO, to avoid the GeoArrays dependency?
+    # read in TIFFs, replacing missing values with 0
+    landcover = coalesce(GeoArrays.read(landcovermap), 0)
+    farmfields = coalesce(GeoArrays.read(farmfieldsmap), 0)
     (size(landcover) != size(farmfields)) && Base.error("Input map sizes don't match.")
     width, height = size(landcover)[1:2]
     landscape = Matrix{Pixel}(undef, width, height)
     for x in 1:width
         for y in 1:height
             # convert the numeric landcover value to LandCover, then create the Pixel object
-            lc = landcover[x,y][1]
-            (ismissing(lc)) && (lc = 0)
-            lcv = LandCover(Int(lc/10))
-            ff = farmfields[x,y][1]
-            !(ismissing(ff)) && (ff = Int64(ff))
+            lcv = LandCover(Int(landcover[x,y][1]/10))
+            ff = Int64(farmfields[x,y][1])
+            (iszero(ff)) && (ff = missing)
             landscape[x,y] = Pixel(lcv, ff, Vector{Symbol}())
         end
     end
-- 
GitLab