From e4a2b34eb1c9dd884b6703b9641a64a4bae25687 Mon Sep 17 00:00:00 2001 From: hbsmith Date: Mon, 28 Apr 2025 15:41:09 +0900 Subject: [PATCH 1/9] same tuple size as dimension of space --- ext/AgentsVisualizations/src/spaces/abstract.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/AgentsVisualizations/src/spaces/abstract.jl b/ext/AgentsVisualizations/src/spaces/abstract.jl index bf74105594..a2600c2b04 100644 --- a/ext/AgentsVisualizations/src/spaces/abstract.jl +++ b/ext/AgentsVisualizations/src/spaces/abstract.jl @@ -183,6 +183,6 @@ function Agents.agent2string(agent::A) where {A<:AbstractAgent} return agentstring end -Agents.convert_element_pos(::S, pos) where {S<:Agents.AbstractSpace} = Tuple(pos) +Agents.convert_element_pos(s::S, pos) where {S<:Agents.AbstractSpace} = Tuple(pos[1:length(s.dims)]) Agents.ids_to_inspect(model::ABM, pos) = ids_in_position(pos, model) From 08fc3f6c189e1d0ff85f110da2beaf580cea078d Mon Sep 17 00:00:00 2001 From: hbsmith Date: Tue, 29 Apr 2025 09:55:18 +0900 Subject: [PATCH 2/9] use spacesize instead of s.dims --- ext/AgentsVisualizations/src/spaces/abstract.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/AgentsVisualizations/src/spaces/abstract.jl b/ext/AgentsVisualizations/src/spaces/abstract.jl index a2600c2b04..178e02a296 100644 --- a/ext/AgentsVisualizations/src/spaces/abstract.jl +++ b/ext/AgentsVisualizations/src/spaces/abstract.jl @@ -183,6 +183,6 @@ function Agents.agent2string(agent::A) where {A<:AbstractAgent} return agentstring end -Agents.convert_element_pos(s::S, pos) where {S<:Agents.AbstractSpace} = Tuple(pos[1:length(s.dims)]) +Agents.convert_element_pos(s::S, pos) where {S<:Agents.AbstractSpace} = Tuple(pos[1:length(spacesize(s))]) Agents.ids_to_inspect(model::ABM, pos) = ids_in_position(pos, model) From c95b025fe28d187d2a8d4de9e96591b19f951755 Mon Sep 17 00:00:00 2001 From: hbsmith Date: Fri, 9 May 2025 15:52:32 +0900 Subject: [PATCH 3/9] streamline fix into one function; still problems after rotation --- .../src/spaces/continuous.jl | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/ext/AgentsVisualizations/src/spaces/continuous.jl b/ext/AgentsVisualizations/src/spaces/continuous.jl index 1599c34359..1cab1f589f 100644 --- a/ext/AgentsVisualizations/src/spaces/continuous.jl +++ b/ext/AgentsVisualizations/src/spaces/continuous.jl @@ -40,5 +40,22 @@ end ## Inspection -Agents.ids_to_inspect(model::ABM{<:ContinuousSpace}, pos) = - nearby_ids_exact(pos, model, 0.00001) +# Agents.ids_to_inspect(model::ABM{<:ContinuousSpace}, pos) = +# nearby_ids_exact(pos, model, 0.00001) + + +# Fixed implementation for 3D +function Agents.ids_to_inspect(model::ABM{<:ContinuousSpace}, pos) + space = abmspace(model) + D = length(spacesize(space)) + + if D == 3 + # 3D plots in Makie use normalized coordinates + extent = space.extent + transformed_pos = ntuple(i -> (pos[i] + 1) * extent[i] / 2, D) + nearby_ids_exact(transformed_pos, model, 0.00001) + else + # 2D plots don't have this issue + nearby_ids_exact(pos, model, 0.00001) + end +end \ No newline at end of file From 8a7c1feb1b08fff2e61c56464b2f80d243c50f0d Mon Sep 17 00:00:00 2001 From: hbsmith Date: Fri, 9 May 2025 16:00:08 +0900 Subject: [PATCH 4/9] a fix which works even with camera rotation! --- .../src/spaces/abstract.jl | 78 ++++++++++++++++--- .../src/spaces/continuous.jl | 38 ++++----- 2 files changed, 87 insertions(+), 29 deletions(-) diff --git a/ext/AgentsVisualizations/src/spaces/abstract.jl b/ext/AgentsVisualizations/src/spaces/abstract.jl index 178e02a296..c082645bbd 100644 --- a/ext/AgentsVisualizations/src/spaces/abstract.jl +++ b/ext/AgentsVisualizations/src/spaces/abstract.jl @@ -125,35 +125,93 @@ function Makie.show_data(inspector::DataInspector, end # 3D space +# function Makie.show_data(inspector::DataInspector, +# p::ABMP{<:Agents.AbstractSpace}, idx, source::MeshScatter) +# @info "show_data called for MeshScatter! idx=$idx" + +# pos = Makie.position_on_plot(source, idx) +# @info "Position on plot: $pos" + +# proj_pos = Makie.shift_project(Makie.parent_scene(p), pos) +# @info "Projected position: $proj_pos" + +# Makie.update_tooltip_alignment!(inspector, proj_pos) + +# model = p.abmobs[].model[] +# converted_pos = convert_element_pos(abmspace(model), pos) +# @info "Converted position: $converted_pos" + +# agent_string = Agents.agent2string(model, converted_pos) +# @info "Agent string: $agent_string" + +# a = inspector.plot.attributes +# a.text[] = agent_string +# a.visible[] = true + +# @info "Tooltip visible: $(a.visible[]), Text: $(a.text[])" + +# return true +# end + function Makie.show_data(inspector::DataInspector, - p::ABMP{<:Agents.AbstractSpace}, idx, source::MeshScatter) - pos = Makie.position_on_plot(source, idx) - proj_pos = Makie.shift_project(Makie.parent_scene(p), pos) - Makie.update_tooltip_alignment!(inspector, proj_pos) + p::Plot{AgentsVisualizations._abmplot, <:Tuple}, + idx::UInt32, source::MeshScatter) model = p.abmobs[].model[] - a = inspector.plot.attributes - a.text[] = Agents.agent2string(model, convert_element_pos(abmspace(model), pos)) - a.visible[] = true - return true + # For meshscatter, each agent is represented by one marker instance + # The idx directly corresponds to the agent index in most cases + # But we should verify this with the actual data + + # Get all agent IDs in the order they appear in the plot + agent_ids = collect(allids(model)) + + # In Agents.jl, the meshscatter should have one marker per agent + # So idx should directly correspond to the agent index + agent_idx = Int(idx) + + if agent_idx <= length(agent_ids) + agent_id = agent_ids[agent_idx] + agent = model[agent_id] + + # Generate tooltip + a = inspector.plot.attributes + a.text[] = Agents.agent2string(agent) + a.visible[] = true + + # Position tooltip at the clicked point + pos = Makie.position_on_plot(source, idx) + proj_pos = Makie.shift_project(Makie.parent_scene(p), pos) + Makie.update_tooltip_alignment!(inspector, proj_pos) + + return true + end + + return false end function Agents.agent2string(model::ABM, pos) + @info "agent2string called with pos: $pos" ids = Agents.ids_to_inspect(model, pos) + + # Convert the iterator to an array + ids_array = collect(ids) + @info "Found agent IDs: $ids_array" + s = "" - - for (i, id) in enumerate(ids) + for (i, id) in enumerate(ids_array) if i > 1 s *= "\n" end s *= Agents.agent2string(model[id]) end + @info "Final string: '$s'" return s end function Agents.agent2string(agent::A) where {A<:AbstractAgent} + agentstring = "▶ $(nameof(A))\n" agentstring *= "id: $(getproperty(agent, :id))\n" diff --git a/ext/AgentsVisualizations/src/spaces/continuous.jl b/ext/AgentsVisualizations/src/spaces/continuous.jl index 1cab1f589f..2ca1633dc5 100644 --- a/ext/AgentsVisualizations/src/spaces/continuous.jl +++ b/ext/AgentsVisualizations/src/spaces/continuous.jl @@ -40,22 +40,22 @@ end ## Inspection -# Agents.ids_to_inspect(model::ABM{<:ContinuousSpace}, pos) = -# nearby_ids_exact(pos, model, 0.00001) - - -# Fixed implementation for 3D -function Agents.ids_to_inspect(model::ABM{<:ContinuousSpace}, pos) - space = abmspace(model) - D = length(spacesize(space)) - - if D == 3 - # 3D plots in Makie use normalized coordinates - extent = space.extent - transformed_pos = ntuple(i -> (pos[i] + 1) * extent[i] / 2, D) - nearby_ids_exact(transformed_pos, model, 0.00001) - else - # 2D plots don't have this issue - nearby_ids_exact(pos, model, 0.00001) - end -end \ No newline at end of file +Agents.ids_to_inspect(model::ABM{<:ContinuousSpace}, pos) = + nearby_ids_exact(pos, model, 0.00001) + + +# # Fixed implementation for 3D +# function Agents.ids_to_inspect(model::ABM{<:ContinuousSpace}, pos) +# space = abmspace(model) +# D = length(spacesize(space)) + +# if D == 3 +# # 3D plots in Makie use normalized coordinates +# extent = space.extent +# transformed_pos = ntuple(i -> (pos[i] + 1) * extent[i] / 2, D) +# nearby_ids_exact(transformed_pos, model, 0.00001) +# else +# # 2D plots don't have this issue +# nearby_ids_exact(pos, model, 0.00001) +# end +# end \ No newline at end of file From 59a652484eaae7fbf827f2bf2f4e3679de44f561 Mon Sep 17 00:00:00 2001 From: hbsmith Date: Fri, 9 May 2025 16:13:06 +0900 Subject: [PATCH 5/9] fix to show tooltips for multiple agents in the same position --- ext/AgentsVisualizations/src/spaces/abstract.jl | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/ext/AgentsVisualizations/src/spaces/abstract.jl b/ext/AgentsVisualizations/src/spaces/abstract.jl index c082645bbd..2818f05565 100644 --- a/ext/AgentsVisualizations/src/spaces/abstract.jl +++ b/ext/AgentsVisualizations/src/spaces/abstract.jl @@ -158,28 +158,19 @@ function Makie.show_data(inspector::DataInspector, idx::UInt32, source::MeshScatter) model = p.abmobs[].model[] - - # For meshscatter, each agent is represented by one marker instance - # The idx directly corresponds to the agent index in most cases - # But we should verify this with the actual data - - # Get all agent IDs in the order they appear in the plot agent_ids = collect(allids(model)) - - # In Agents.jl, the meshscatter should have one marker per agent - # So idx should directly correspond to the agent index agent_idx = Int(idx) if agent_idx <= length(agent_ids) agent_id = agent_ids[agent_idx] agent = model[agent_id] - # Generate tooltip + # Use existing Agents.jl functionality to handle multiple agents a = inspector.plot.attributes - a.text[] = Agents.agent2string(agent) + a.text[] = Agents.agent2string(model, agent.pos) a.visible[] = true - # Position tooltip at the clicked point + # Position tooltip pos = Makie.position_on_plot(source, idx) proj_pos = Makie.shift_project(Makie.parent_scene(p), pos) Makie.update_tooltip_alignment!(inspector, proj_pos) From d3b7c6642b20ce905b288735529d69508a9a3e6d Mon Sep 17 00:00:00 2001 From: hbsmith Date: Tue, 20 May 2025 11:11:26 +0900 Subject: [PATCH 6/9] remove comments and whitespace --- .../src/spaces/abstract.jl | 38 +------------------ .../src/spaces/continuous.jl | 17 --------- 2 files changed, 1 insertion(+), 54 deletions(-) diff --git a/ext/AgentsVisualizations/src/spaces/abstract.jl b/ext/AgentsVisualizations/src/spaces/abstract.jl index 2818f05565..cf351c2690 100644 --- a/ext/AgentsVisualizations/src/spaces/abstract.jl +++ b/ext/AgentsVisualizations/src/spaces/abstract.jl @@ -124,35 +124,6 @@ function Makie.show_data(inspector::DataInspector, return true end -# 3D space -# function Makie.show_data(inspector::DataInspector, -# p::ABMP{<:Agents.AbstractSpace}, idx, source::MeshScatter) -# @info "show_data called for MeshScatter! idx=$idx" - -# pos = Makie.position_on_plot(source, idx) -# @info "Position on plot: $pos" - -# proj_pos = Makie.shift_project(Makie.parent_scene(p), pos) -# @info "Projected position: $proj_pos" - -# Makie.update_tooltip_alignment!(inspector, proj_pos) - -# model = p.abmobs[].model[] -# converted_pos = convert_element_pos(abmspace(model), pos) -# @info "Converted position: $converted_pos" - -# agent_string = Agents.agent2string(model, converted_pos) -# @info "Agent string: $agent_string" - -# a = inspector.plot.attributes -# a.text[] = agent_string -# a.visible[] = true - -# @info "Tooltip visible: $(a.visible[]), Text: $(a.text[])" - -# return true -# end - function Makie.show_data(inspector::DataInspector, p::Plot{AgentsVisualizations._abmplot, <:Tuple}, idx::UInt32, source::MeshScatter) @@ -165,7 +136,7 @@ function Makie.show_data(inspector::DataInspector, agent_id = agent_ids[agent_idx] agent = model[agent_id] - # Use existing Agents.jl functionality to handle multiple agents + # Use existing functionality to handle multiple agents a = inspector.plot.attributes a.text[] = Agents.agent2string(model, agent.pos) a.visible[] = true @@ -182,13 +153,8 @@ function Makie.show_data(inspector::DataInspector, end function Agents.agent2string(model::ABM, pos) - @info "agent2string called with pos: $pos" ids = Agents.ids_to_inspect(model, pos) - - # Convert the iterator to an array ids_array = collect(ids) - @info "Found agent IDs: $ids_array" - s = "" for (i, id) in enumerate(ids_array) if i > 1 @@ -197,12 +163,10 @@ function Agents.agent2string(model::ABM, pos) s *= Agents.agent2string(model[id]) end - @info "Final string: '$s'" return s end function Agents.agent2string(agent::A) where {A<:AbstractAgent} - agentstring = "▶ $(nameof(A))\n" agentstring *= "id: $(getproperty(agent, :id))\n" diff --git a/ext/AgentsVisualizations/src/spaces/continuous.jl b/ext/AgentsVisualizations/src/spaces/continuous.jl index 2ca1633dc5..1599c34359 100644 --- a/ext/AgentsVisualizations/src/spaces/continuous.jl +++ b/ext/AgentsVisualizations/src/spaces/continuous.jl @@ -42,20 +42,3 @@ end Agents.ids_to_inspect(model::ABM{<:ContinuousSpace}, pos) = nearby_ids_exact(pos, model, 0.00001) - - -# # Fixed implementation for 3D -# function Agents.ids_to_inspect(model::ABM{<:ContinuousSpace}, pos) -# space = abmspace(model) -# D = length(spacesize(space)) - -# if D == 3 -# # 3D plots in Makie use normalized coordinates -# extent = space.extent -# transformed_pos = ntuple(i -> (pos[i] + 1) * extent[i] / 2, D) -# nearby_ids_exact(transformed_pos, model, 0.00001) -# else -# # 2D plots don't have this issue -# nearby_ids_exact(pos, model, 0.00001) -# end -# end \ No newline at end of file From 4102927e36314b673dc443cea5f4526595521349 Mon Sep 17 00:00:00 2001 From: hbsmith Date: Tue, 20 May 2025 11:18:38 +0900 Subject: [PATCH 7/9] revert collect, unneeded --- ext/AgentsVisualizations/src/spaces/abstract.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/AgentsVisualizations/src/spaces/abstract.jl b/ext/AgentsVisualizations/src/spaces/abstract.jl index cf351c2690..f434e0cfb9 100644 --- a/ext/AgentsVisualizations/src/spaces/abstract.jl +++ b/ext/AgentsVisualizations/src/spaces/abstract.jl @@ -154,9 +154,8 @@ end function Agents.agent2string(model::ABM, pos) ids = Agents.ids_to_inspect(model, pos) - ids_array = collect(ids) s = "" - for (i, id) in enumerate(ids_array) + for (i, id) in enumerate(ids) if i > 1 s *= "\n" end From c147d54b98f6c3aed0290e5d3cc71a3d1489b9c5 Mon Sep 17 00:00:00 2001 From: hbsmith Date: Tue, 20 May 2025 11:36:22 +0900 Subject: [PATCH 8/9] simplified changes, and added explanations --- .../src/spaces/abstract.jl | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/ext/AgentsVisualizations/src/spaces/abstract.jl b/ext/AgentsVisualizations/src/spaces/abstract.jl index f434e0cfb9..46c0b25bb9 100644 --- a/ext/AgentsVisualizations/src/spaces/abstract.jl +++ b/ext/AgentsVisualizations/src/spaces/abstract.jl @@ -125,30 +125,39 @@ function Makie.show_data(inspector::DataInspector, end function Makie.show_data(inspector::DataInspector, - p::Plot{AgentsVisualizations._abmplot, <:Tuple}, - idx::UInt32, source::MeshScatter) + p::ABMP{<:Agents.AbstractSpace}, idx, source::MeshScatter) + pos = Makie.position_on_plot(source, idx) + proj_pos = Makie.shift_project(Makie.parent_scene(p), pos) + Makie.update_tooltip_alignment!(inspector, proj_pos) model = p.abmobs[].model[] + + # BUGFIX: In 3D plots, position_on_plot returns coordinates in view/camera space, + # not world space. This causes position-based agent lookup to fail after camera + # manipulation. Instead, we use the index to get the agent's actual position. agent_ids = collect(allids(model)) agent_idx = Int(idx) + # Safety check to prevent index errors when hovering near plot boundaries if agent_idx <= length(agent_ids) agent_id = agent_ids[agent_idx] - agent = model[agent_id] + agent_pos = model[agent_id].pos - # Use existing functionality to handle multiple agents + # Use the agent's actual position (in world coordinates) instead of + # the transformed position from position_on_plot. This ensures we + # find all agents at the same position correctly. a = inspector.plot.attributes - a.text[] = Agents.agent2string(model, agent.pos) + a.text[] = Agents.agent2string(model, agent_pos) a.visible[] = true - # Position tooltip - pos = Makie.position_on_plot(source, idx) - proj_pos = Makie.shift_project(Makie.parent_scene(p), pos) - Makie.update_tooltip_alignment!(inspector, proj_pos) - return true end - + + # If index is invalid, hide the tooltip + a = inspector.plot.attributes + a.text[] = "" + a.visible[] = false + return false end From ed567a0818c08d56d5d50054397ca6e5b8d9e094 Mon Sep 17 00:00:00 2001 From: hbsmith Date: Tue, 20 May 2025 11:57:52 +0900 Subject: [PATCH 9/9] comment --- ext/AgentsVisualizations/src/spaces/abstract.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/AgentsVisualizations/src/spaces/abstract.jl b/ext/AgentsVisualizations/src/spaces/abstract.jl index 46c0b25bb9..8f73edfc18 100644 --- a/ext/AgentsVisualizations/src/spaces/abstract.jl +++ b/ext/AgentsVisualizations/src/spaces/abstract.jl @@ -124,6 +124,7 @@ function Makie.show_data(inspector::DataInspector, return true end +# 3D space function Makie.show_data(inspector::DataInspector, p::ABMP{<:Agents.AbstractSpace}, idx, source::MeshScatter) pos = Makie.position_on_plot(source, idx) @@ -164,6 +165,7 @@ end function Agents.agent2string(model::ABM, pos) ids = Agents.ids_to_inspect(model, pos) s = "" + for (i, id) in enumerate(ids) if i > 1 s *= "\n"