Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spatial visualisations for decision matrices #893

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions Manifest-v1.11.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This file is machine-generated - editing it directly is not advised

julia_version = "1.11.1"
julia_version = "1.11.0"
manifest_format = "2.0"
project_hash = "f5f80681e1f41a61ae2064c46066ad6e608da783"

Expand Down Expand Up @@ -71,9 +71,9 @@ version = "0.1.38"

[[deps.Adapt]]
deps = ["LinearAlgebra", "Requires"]
git-tree-sha1 = "6a55b747d1812e699320963ffde36f1ebdda4099"
git-tree-sha1 = "d80af0733c99ea80575f612813fa6aa71022d33a"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "4.0.4"
version = "4.1.0"
weakdeps = ["StaticArrays"]

[deps.Adapt.extensions]
Expand Down Expand Up @@ -512,15 +512,15 @@ version = "0.1.10"

[[deps.DiskArrays]]
deps = ["LRUCache", "OffsetArrays"]
git-tree-sha1 = "dea23e3d787c25fbf5f879c4501da828bc729472"
git-tree-sha1 = "e0e89a60637a62d13aa2107f0acd169b9b9b77e7"
uuid = "3c3547ce-8d99-4f5e-a174-61eb10b00ae3"
version = "0.4.5"
version = "0.4.6"

[[deps.Distances]]
deps = ["LinearAlgebra", "Statistics", "StatsAPI"]
git-tree-sha1 = "66c4c81f259586e8f002eacebc177e1fb06363b0"
git-tree-sha1 = "c7e3a542b999843086e2f29dac96a618c105be1d"
uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7"
version = "0.10.11"
version = "0.10.12"
weakdeps = ["ChainRulesCore", "SparseArrays"]

[deps.Distances.extensions]
Expand Down Expand Up @@ -1104,10 +1104,10 @@ uuid = "88015f11-f218-50d7-93a8-a6af411a945d"
version = "4.0.0+0"

[[deps.LLVM]]
deps = ["CEnum", "LLVMExtra_jll", "Libdl", "Preferences", "Printf", "Requires", "Unicode"]
git-tree-sha1 = "4ad43cb0a4bb5e5b1506e1d1f48646d7e0c80363"
deps = ["CEnum", "LLVMExtra_jll", "Libdl", "Preferences", "Printf", "Unicode"]
git-tree-sha1 = "d422dfd9707bec6617335dc2ea3c5172a87d5908"
uuid = "929cbde3-209d-540e-8aea-75f648917ca0"
version = "9.1.2"
version = "9.1.3"

[deps.LLVM.extensions]
BFloat16sExt = "BFloat16s"
Expand Down Expand Up @@ -1218,9 +1218,9 @@ version = "1.6.0+0"

[[deps.Libgpg_error_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"]
git-tree-sha1 = "fbb1f2bef882392312feb1ede3615ddc1e9b99ed"
git-tree-sha1 = "c6ce1e19f3aec9b59186bdf06cdf3c4fc5f5f3e6"
uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
version = "1.49.0+0"
version = "1.50.0+0"

[[deps.Libiconv_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"]
Expand Down Expand Up @@ -1285,9 +1285,9 @@ version = "1.11.0"

[[deps.LoggingExtras]]
deps = ["Dates", "Logging"]
git-tree-sha1 = "c1dd6d7978c12545b4179fb6153b9250c96b0075"
git-tree-sha1 = "f02b56007b064fbfddb4c9cd60161b6dd0f40df3"
uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36"
version = "1.0.3"
version = "1.1.0"

[[deps.Lz4_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"]
Expand Down Expand Up @@ -1954,9 +1954,9 @@ version = "1.2.1"

[[deps.SentinelArrays]]
deps = ["Dates", "Random"]
git-tree-sha1 = "ff11acffdb082493657550959d4feb4b6149e73a"
git-tree-sha1 = "305becf8af67eae1dbc912ee9097f00aeeabb8d5"
uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c"
version = "1.4.5"
version = "1.4.6"

[[deps.Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
Expand Down Expand Up @@ -2075,9 +2075,9 @@ version = "0.1.1"

[[deps.StaticArrays]]
deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"]
git-tree-sha1 = "eeafab08ae20c62c44c8399ccb9354a04b80db50"
git-tree-sha1 = "777657803913ffc7e8cc20f0fd04b634f871af8f"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.9.7"
version = "1.9.8"
weakdeps = ["ChainRulesCore", "Statistics"]

[deps.StaticArrays.extensions]
Expand Down Expand Up @@ -2349,9 +2349,9 @@ version = "1.1.41+0"

[[deps.XZ_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"]
git-tree-sha1 = "ac88fb95ae6447c8dda6a5503f3bafd496ae8632"
git-tree-sha1 = "15e637a697345f6743674f1322beefbc5dcd5cfc"
uuid = "ffd25f8a-64ca-5728-b0f7-c24cf3aae800"
version = "5.4.6+0"
version = "5.6.3+0"

[[deps.Xorg_libX11_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
Expand Down Expand Up @@ -2421,9 +2421,9 @@ version = "0.7.3"

[[deps.YAXArrays]]
deps = ["CFTime", "DataStructures", "Dates", "DimensionalData", "DiskArrayTools", "DiskArrays", "Distributed", "DocStringExtensions", "Glob", "Interpolations", "IntervalSets", "IterTools", "Markdown", "OffsetArrays", "OnlineStats", "Optim", "OrderedCollections", "ParallelUtilities", "ProgressMeter", "Reexport", "Requires", "Statistics", "StatsBase", "Tables", "WeightedOnlineStats", "YAXArrayBase"]
git-tree-sha1 = "09cd01df4817c4d5f6eda845c4d75cc2855cf0b3"
git-tree-sha1 = "02d9149f67b26256ffa1e1c3915d474fae57099e"
uuid = "c21b50f5-aa40-41ea-b809-c0f5e47bfa5c"
version = "0.5.11"
version = "0.5.12"

[[deps.Zarr]]
deps = ["AWSS3", "Blosc", "CodecZlib", "DataStructures", "Dates", "DiskArrays", "HTTP", "JSON", "LRUCache", "OffsetArrays", "OpenSSL", "Pkg", "URIs", "ZipArchives"]
Expand Down
Binary file added docs/src/assets/imgs/criteria_spatial_plots.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions docs/src/usage/analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,63 @@ save("ranks_plot.png", rank_fig)

![Rank frequency plots for multiple ranks](../assets/imgs/analysis/ranks_plot.png)

## Intervention location selection - plot criteria maps

```julia

mcda_funcs = ADRIA.decision.mcda_methods()

dom = ADRIA.load_domain("path to domain","45")

scens = ADRIA.sample_guided(dom, 2^2)
scen = scens[1, :]

# Get seeding preferences
seed_pref = ADRIA.decision.SeedPreferences(dom, scen)

# Calculate criteria vectors
# Cover
sum_cover = vec(sum(dom.init_coral_cover; dims=1).data)
# DHWS
dhw_scens = dom.dhw_scens[:, :, Int64(scen["dhw_scenario"])]
plan_horizon = Int64(scen["plan_horizon"])
decay = 0.99 .^ (1:(plan_horizon + 1)) .^ 2
dhw_projection = ADRIA.decision.weighted_projection(dhw_scens, 1, plan_horizon, decay, 75)
# Connectivity
area_weighted_conn = dom.conn.data .* ADRIA.site_k_area(dom)
conn_cache = similar(area_weighted_conn)
in_conn, out_conn, network = ADRIA.connectivity_strength(
area_weighted_conn, sum_cover, conn_cache
)

# Create decision matrix
seed_decision_mat = ADRIA.decision.decision_matrix(
dom.loc_ids,
seed_pref.names;
seed_in_connectivity=in_conn,
seed_out_connectivity=out_conn,
seed_heat_stress=dhw_projection,
seed_coral_cover=sum_cover
)

# Get results from applying MCDA algorithm
crit_agg = ADRIA.decision.criteria_aggregated_scores(
seed_pref, seed_decision_mat, mcda_funcs[1]
)

# Don't plot constant criteria
is_const = Bool[length(x) == 1 for x in unique.(eachcol(seed_decision_mat.data))]

# Plot normalized scores and criteria as map
fig = ADRIA.viz.selection_criteria_map(
dom, seed_decision_mat[criteria=.!is_const], crit_agg.scores ./ maximum(crit_agg.scores)
)
save("criteria_plots.png", fig)
```

![Spatial maps of location selection criteria](/ADRIA.jl/dev/assets/imgs/criteria_spatial_plots.png?raw=true "Spatial maps of location selection criteria")


### PAWN sensitivity (heatmap overview)

The PAWN sensitivity analysis method is a moment-independent approach to Global Sensitivity
Expand Down
66 changes: 66 additions & 0 deletions ext/AvizExt/viz/location_selection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,72 @@
return f
end

"""
ADRIA.viz.selection_criteria_map(rs::Union{Domain,ResultSet}, decision_matrix::YAXArray, scores::Vector{Float64}; criteria::Vector{Symbol}=Array(decision_matrix.criteria), opts::OPT_TYPE=DEFAULT_OPT_TYPE(), fig_opts::OPT_TYPE=set_figure_defaults(DEFAULT_OPT_TYPE()), axis_opts::OPT_TYPE=set_axis_defaults(DEFAULT_OPT_TYPE()))
ADRIA.viz.selection_criteria_map!(g::Union{GridLayout,GridPosition}, rs::Union{Domain,ResultSet}, decision_matrix::YAXArray, scores::Vector{Float64}; criteria::Vector{Symbol}=Array(decision_matrix.criteria), opts::OPT_TYPE=DEFAULT_OPT_TYPE(), axis_opts::OPT_TYPE=set_axis_defaults(DEFAULT_OPT_TYPE()))

Plot several spatial maps showing spatial distribution of location selection criteria, with the final map being the
aggregate location selection score.

# Arguments
- `g` : Figure GridPosition or GridLayout.
- `rs` : Result set or Domain.
- `decision_matrix` : Decision matrix of size (n_locs*n_criteria)
- `scores` : Aggregate criteria scores calculated from `decision_matrix`.
- `criteria` : Names of criteria used, default uses decision matrix YAXArray dimension names.
- `opts` : Aviz options
- `colorbar_label`, label for colorbar. Defaults to "Relative Cover".
- `color_map`, preferred colormap for plotting heatmaps.
- `axis_opts` : Additional options to pass to adjust Axis attributes
See: https://docs.makie.org/v0.19/api/index.html#Axis
- `fig_opts` : Additional options to pass to adjust Figure creation
See: https://docs.makie.org/v0.19/api/index.html#Figure

# Returns
Figure
"""
function ADRIA.viz.selection_criteria_map(

Check warning on line 157 in ext/AvizExt/viz/location_selection.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/location_selection.jl#L157

Added line #L157 was not covered by tests
rs::Union{Domain,ResultSet},
decision_matrix::YAXArray,
scores::Vector{Float64};
criteria::Vector{Symbol}=Array(decision_matrix.criteria),
opts::OPT_TYPE=DEFAULT_OPT_TYPE(),
fig_opts::OPT_TYPE=set_figure_defaults(DEFAULT_OPT_TYPE()),
axis_opts::OPT_TYPE=set_axis_defaults(DEFAULT_OPT_TYPE())
)
f = Figure(; fig_opts...)
g = f[1, 1] = GridLayout()
ADRIA.viz.selection_criteria_map!(

Check warning on line 168 in ext/AvizExt/viz/location_selection.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/location_selection.jl#L166-L168

Added lines #L166 - L168 were not covered by tests
g, rs, decision_matrix, scores; criteria=criteria, opts=opts, axis_opts=axis_opts
)
return f

Check warning on line 171 in ext/AvizExt/viz/location_selection.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/location_selection.jl#L171

Added line #L171 was not covered by tests
end
function ADRIA.viz.selection_criteria_map!(

Check warning on line 173 in ext/AvizExt/viz/location_selection.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/location_selection.jl#L173

Added line #L173 was not covered by tests
g::Union{GridLayout,GridPosition},
rs::Union{Domain,ResultSet},
decision_matrix::YAXArray,
scores::Vector{Float64};
criteria::Vector{Symbol}=Array(decision_matrix.criteria),
opts::OPT_TYPE=DEFAULT_OPT_TYPE(),
axis_opts::OPT_TYPE=set_axis_defaults(DEFAULT_OPT_TYPE())
)
if length(rs.loc_data.site_id) != size(decision_matrix, 1)
error("Only unfiltered decision matrices can be plotted.")

Check warning on line 183 in ext/AvizExt/viz/location_selection.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/location_selection.jl#L182-L183

Added lines #L182 - L183 were not covered by tests
end

outputs_matrix = hcat(Matrix(decision_matrix), scores)
titles = human_readable_name(string.(vcat(criteria, :agregate_score)); title_case=true)

Check warning on line 187 in ext/AvizExt/viz/location_selection.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/location_selection.jl#L186-L187

Added lines #L186 - L187 were not covered by tests

return ADRIA.viz.map!(

Check warning on line 189 in ext/AvizExt/viz/location_selection.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/location_selection.jl#L189

Added line #L189 was not covered by tests
g,
rs,
outputs_matrix,
titles;
opts=opts,
axis_opts=axis_opts
)
end

"""
_default_colormap(rank_groups::Dict{Symbol,BitVector}, alpha_vals::Dict{Symbol,Float64})

Expand Down
72 changes: 70 additions & 2 deletions ext/AvizExt/viz/spatial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,9 @@
end
end

# Remove any empty subplots
trim!(f)
if typeof(f) == GridLayout
trim!(f)
end

return f
end
Expand Down Expand Up @@ -252,6 +253,73 @@
)
end

"""
ADRIA.viz.map(rs::Union{Domain,ResultSet}, outputs_matrix::Matrix, map_titles::Vector{String}; opts::OPT_TYPE=DEFAULT_OPT_TYPE(), fig_opts::OPT_TYPE=set_figure_defaults(DEFAULT_OPT_TYPE()), axis_opts::OPT_TYPE=set_axis_defaults(DEFAULT_OPT_TYPE()))
ADRIA.viz.map!(g::Union{GridLayout,GridPosition}, rs::Union{Domain,ResultSet}, outputs_matrix::Matrix, map_titles::Vector{String}; opts::OPT_TYPE=DEFAULT_OPT_TYPE(), axis_opts::OPT_TYPE=set_axis_defaults(DEFAULT_OPT_TYPE()))

Plot a series of maps from an arbitrary (n_locs*n_maps) matrix of outputs.

# Arguments
- `rs` : ResultSet
- `g` : Figure GridPosition or GridLayout.
- `outputs_matrix` : Matrix of outputs where n_locs is the numberof locations and n_maps is the number of different
maps to plot.
- `map_titles` : Titles for each map to be plotted.
- `opts` : Aviz options
- `colorbar_label`, label for colorbar. Defaults to "Relative Cover"
- `color_map`, preferred colormap for plotting heatmaps
- `axis_opts` : Additional options to pass to adjust Axis attributes
See: https://docs.makie.org/v0.19/api/index.html#Axis
"""
function ADRIA.viz.map(

Check warning on line 274 in ext/AvizExt/viz/spatial.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/spatial.jl#L274

Added line #L274 was not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since map is a very generic name, I don't think we should make a method called map plot a specific kind of map only (only maps of decision matrix scores). What I mean is: it is interesting to have a map function that plots multiple maps like you did, but not only for decision matrix. I could plot the average of some different metrics for each location, for example.

So, I propose we have an intermediate function selection_criteria_map, for example, that receives this matrix and this vector, concatenate them to become just a single matrix; builds up a tuple of titles for each plot; and call a map function that receives this matrix and the titles_tuple (and whatever else it needs) and plots this grid of maps. Then, in the future, if we want to plot other multiple map figure, it can be easily reused.

What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the current approach but I'm not 100% up on the context here, just latching onto the suggestion to create a separate map plotting function. Julia is not strictly an object oriented language and isn't intended to be used like Python or Java.

The advantage of having multiple dispatch (or something like it, as in R) is to prevent everyone from having to remember a lot of function names. Is it map or vizualize_selection_criteria_as_map or display_map or plot_selection_criteria_map or...

As a user I don't want to have to remember endless possible function names for specific use cases. I just want a map.

Instead, this behaviour of:

  1. You have a vector of results -> map() produces a single map.
  2. You have a matrix of results -> map() produces a series of maps.

is sensible to me.

But again, I don't have full context.

https://www.juliaopt.org/meetings/santiago2019/slides/stefan_karpinski.pdf

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand and I agree with what you said.

My problem with how this function is defined right now is that it doesn't plot selection criteria scores in particular. It plots multiple maps with whatever you pass as an argument. But still the names of variables and the plots default titles are related to this specific kind of plot (multiple maps with selection criteria scores). It's like having a function called sum and the arguments are called prime_number_a and prime_number_b. If it sums more than just prime numbers, they should be called number_a and number_b or whatever.

About the need for a specific function called selection_criteria_map, maybe we don't need one, I agree. depending on how this map function with multiple maps is defined we can just use this one and that's fine. My comment was more about making this map general than about the need of a specific function with a specific name for this kind of plot.

Copy link
Collaborator

@ConnectedSystems ConnectedSystems Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incidentally @Rosejoycrocker the variable names/titles displayed in the figure should be run through human_readable() (this isn't the exact function name but you should be able to find it easily)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the outcome of this discssuion is, but I've separated this into a generic map() method which plots multiple maps in a grid given a matrix of inputs, and then a function in location_selection.jl that plots criteria and an aggregate score given a decision matrix input and vector of scores (using the generic map() function). Not sure what you think but I think being able to quickly plot criteria and an output score is useful, hence its inclusion in location_selection.jl.

rs::Union{Domain,ResultSet},
outputs_matrix::Matrix,
map_titles::Vector{String};
criteria::Vector{Symbol}=Array(M.criteria),
opts::OPT_TYPE=DEFAULT_OPT_TYPE(),
fig_opts::OPT_TYPE=set_figure_defaults(DEFAULT_OPT_TYPE()),
axis_opts::OPT_TYPE=set_axis_defaults(DEFAULT_OPT_TYPE())
)
f = Figure(; fig_opts...)
g = f[1, 1] = GridLayout()
ADRIA.viz.map!(

Check warning on line 285 in ext/AvizExt/viz/spatial.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/spatial.jl#L283-L285

Added lines #L283 - L285 were not covered by tests
g, rs, outputs_matrix, map_titles; criteria=criteria, opts=opts, axis_opts=axis_opts
)
return f

Check warning on line 288 in ext/AvizExt/viz/spatial.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/spatial.jl#L288

Added line #L288 was not covered by tests
end
function ADRIA.viz.map!(

Check warning on line 290 in ext/AvizExt/viz/spatial.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/spatial.jl#L290

Added line #L290 was not covered by tests
g::Union{GridLayout,GridPosition},
rs::Union{Domain,ResultSet},
outputs_matrix::Matrix,
map_titles::Vector{String};
opts::OPT_TYPE=DEFAULT_OPT_TYPE(),
axis_opts::OPT_TYPE=set_axis_defaults(DEFAULT_OPT_TYPE())
)
opts[:color_map] = get(opts, :color_map, :viridis)
opts[:colorbar_limits] = get(opts, :colorbar_limits, (0.0, 1.0))

Check warning on line 299 in ext/AvizExt/viz/spatial.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/spatial.jl#L298-L299

Added lines #L298 - L299 were not covered by tests

n_plots::Int64 = length(map_titles)
n_rows, n_cols = _calc_gridsize(n_plots)
step::Int64 = 1

Check warning on line 303 in ext/AvizExt/viz/spatial.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/spatial.jl#L301-L303

Added lines #L301 - L303 were not covered by tests

for row in 1:n_rows, col in 1:n_cols
if step > length(map_titles)
break

Check warning on line 307 in ext/AvizExt/viz/spatial.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/spatial.jl#L305-L307

Added lines #L305 - L307 were not covered by tests
end
axis_opts[:title] = map_titles[step]
ADRIA.viz.map!(

Check warning on line 310 in ext/AvizExt/viz/spatial.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/spatial.jl#L309-L310

Added lines #L309 - L310 were not covered by tests
g[row, col],
rs,
vec(outputs_matrix[:, step]);
opts=opts,
axis_opts=axis_opts
)

step += 1
end
return g

Check warning on line 320 in ext/AvizExt/viz/spatial.jl

View check run for this annotation

Codecov / codecov/patch

ext/AvizExt/viz/spatial.jl#L318-L320

Added lines #L318 - L320 were not covered by tests
end

"""
ADRIA.viz.map(gdf::DataFrame; geom_col=:geometry, color=nothing)

Expand Down
29 changes: 25 additions & 4 deletions src/decision/Criteria/DecisionPreferences.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ function solve(
end

"""
rank_by_index(dp::T, dm::YAXArray, method::Function)::Vector{Int64} where {T<:DecisionPreference}
rank_by_index(dp::T, dm::YAXArray, method::Union{Function,DataType})::Vector{Int64} where {T<:DecisionPreference}

Default index rank method, returns location indices in order of their rank.

Expand All @@ -131,6 +131,29 @@ Index of locations ordered by their rank
function rank_by_index(
Zapiano marked this conversation as resolved.
Show resolved Hide resolved
dp::T, dm::YAXArray, method::Union{Function,DataType}
)::Vector{Int64} where {T<:DecisionPreference}
decision_results = criteria_aggregated_scores(dp, dm, method)
is_maximal = decision_results.bestIndex == argmax(decision_results.scores)
return sortperm(decision_results.scores; rev=is_maximal)
end

"""
criteria_aggregated_scores(dp::T, dm::YAXArray, method::Function)::NamedTuple where {T<:DecisionPreference}

Calculates raw aggreagted score for a set of locations, in order of the location indices.

Note: Ignores constant criteria values.

# Arguments
- `dp` : DecisionPreferences
- `dm` : The decision matrix to assess
- `method` : An MCDA method provided by the JMcDM package

# Returns
Returns raw aggreagted score for a set of locations
"""
function criteria_aggregated_scores(
dp::T, dm::YAXArray, method::Union{Function,DataType}
)::NamedTuple where {T<:DecisionPreference}
# Identify valid, non-constant, columns for use in MCDA
is_const = Bool[length(x) == 1 for x in unique.(eachcol(dm.data))]

Expand All @@ -150,9 +173,7 @@ function rank_by_index(
# or if the method fails for some reason...
throw(DomainError(res.scores, "No ranking possible"))
end

is_maximal = res.bestIndex == argmax(res.scores)
return sortperm(res.scores; rev=is_maximal)
return (scores=res.scores, bestIndex=res.bestIndex)
end

"""
Expand Down
Loading
Loading