-
Notifications
You must be signed in to change notification settings - Fork 6
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
base: main
Are you sure you want to change the base?
Changes from 8 commits
6ef0899
2d9f37c
25d2890
833a3c5
9d27f72
05def0f
2feceff
7e26a3e
1c52cd3
2d18fa4
d2f4772
409bfba
01a997c
1a677cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -151,8 +151,9 @@ function create_map!( | |
end | ||
end | ||
|
||
# Remove any empty subplots | ||
trim!(f) | ||
if typeof(f) == GridLayout | ||
trim!(f) | ||
end | ||
|
||
return f | ||
end | ||
|
@@ -167,6 +168,10 @@ Plot spatial choropleth of outcomes. | |
# Arguments | ||
- `rs` : ResultSet | ||
- `y` : results of scenario metric | ||
- `S` : A normalised decision matrix calculated using decison.decision_matrices | ||
- `scores` : Aggregated criteria scores. | ||
- `criteria` : Names of criteria to be plotted, if not specified all criteria in | ||
S will be plotted. | ||
- `opts` : Aviz options | ||
- `colorbar_label`, label for colorbar. Defaults to "Relative Cover" | ||
- `color_map`, preferred colormap for plotting heatmaps | ||
|
@@ -251,6 +256,75 @@ function ADRIA.viz.map!( | |
axis_opts | ||
) | ||
end | ||
function ADRIA.viz.map( | ||
rs::Union{Domain,ResultSet}, | ||
M::YAXArray, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
scores::Vector{Float64}; | ||
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!( | ||
g, rs, M, scores; criteria=criteria, opts=opts, axis_opts=axis_opts | ||
) | ||
return f | ||
end | ||
function ADRIA.viz.map!( | ||
g::Union{GridLayout,GridPosition}, | ||
rs::Union{Domain,ResultSet}, | ||
M::YAXArray, | ||
scores::Vector{Float64}; | ||
criteria::Vector{Symbol}=Array(M.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(M, 1) | ||
error("Only unfiltered decision matrices can be plotted.") | ||
end | ||
|
||
opts[:color_map] = get(opts, :color_map, :viridis) | ||
opts[:colorbar_limits] = get(opts, :colorbar_limits, (0.0, 1.0)) | ||
|
||
m_spec = model_spec(rs) | ||
criteria_names::Vector{String} = m_spec[ | ||
dropdims( | ||
any( | ||
reshape(criteria, 1, length(criteria)) .== m_spec[:, "fieldname"]; dims=2 | ||
); | ||
dims=2 | ||
), "name"] | ||
n_criteria::Int64 = length(criteria) | ||
n_rows, n_cols = _calc_gridsize(n_criteria + 1) | ||
step::Int64 = 1 | ||
|
||
for row in 1:n_rows, col in 1:n_cols | ||
if step > length(criteria_names) | ||
axis_opts[:title] = "Aggregate criteria score" | ||
ADRIA.viz.map!( | ||
g[row, col], | ||
rs, | ||
vec(scores); | ||
opts=opts, | ||
axis_opts=axis_opts | ||
) | ||
break | ||
end | ||
axis_opts[:title] = string(criteria_names[step]) | ||
ADRIA.viz.map!( | ||
g[row, col], | ||
rs, | ||
vec(M[criteria=At(criteria[step])]); | ||
opts=opts, | ||
axis_opts=axis_opts | ||
) | ||
|
||
step += 1 | ||
end | ||
return g | ||
end | ||
|
||
""" | ||
ADRIA.viz.map(gdf::DataFrame; geom_col=:geometry, color=nothing) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -131,6 +131,30 @@ Index of locations ordered by their rank | |
function rank_by_index( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function signature doesn't match the docstring (I know this wasn't updated by you, if you prefer just open an issue to fix that on a separate PR). |
||
dp::T, dm::YAXArray, method::Union{Function,DataType} | ||
)::Vector{Int64} where {T<:DecisionPreference} | ||
res = get_criteria_aggregate(dp, dm, method) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I imagine There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its a result structure that the MCDA package uses, so it contains more than just the aggregate score. Maybe change it to |
||
is_maximal = res.bestIndex == argmax(res.scores) | ||
return sortperm(res.scores; rev=is_maximal) | ||
end | ||
|
||
""" | ||
get_criteria_aggregate(dp::T, dm::YAXArray, method::Function)::Tuple{Vector{Float64,Int64}} | ||
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 get_criteria_aggregate( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for spotting, I'll fix the signature and change the name to |
||
dp::T, dm::YAXArray, method::Union{Function,DataType} | ||
) 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))] | ||
|
||
|
@@ -150,9 +174,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 | ||
|
||
""" | ||
|
There was a problem hiding this comment.
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 calledmap
plot a specific kind of map only (only maps of decision matrix scores). What I mean is: it is interesting to have amap
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 amap
function that receives this matrix and thetitles_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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good :)
There was a problem hiding this comment.
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
orvizualize_selection_criteria_as_map
ordisplay_map
orplot_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:
map()
produces a single map.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
There was a problem hiding this comment.
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 calledprime_number_a
andprime_number_b
. If it sums more than just prime numbers, they should be callednumber_a
andnumber_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 thismap
function with multiple maps is defined we can just use this one and that's fine. My comment was more about making thismap
general than about the need of a specific function with a specific name for this kind of plot.There was a problem hiding this comment.
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)There was a problem hiding this comment.
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.