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

(Default)Dict for some attributes #89

Merged
merged 9 commits into from
Jun 20, 2023
Merged
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
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ authors = ["Simon Danisch", "Hans Würfel"]
version = "0.5.4"

[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
NetworkLayout = "46757867-2c16-5918-afeb-47bfcb05e46a"
PolynomialRoots = "3a141323-8675-5d76-9d11-e1df1406c778"
SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

[compat]
Expand Down
Binary file added assets/reftests.jl-25.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-26.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-27.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-28.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-29.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-30.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-31.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-33.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-34.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-35.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-36.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-37.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-38.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-39.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-40.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-41.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-42.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/reftests.jl-43.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[deps]
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
Cbc = "9961bab8-2fa3-5c5a-9d89-47fab24efd76"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
GraphMakie = "1ecd5474-83a3-4783-bb4f-06765db800d2"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
Expand Down
95 changes: 94 additions & 1 deletion docs/examples/reftests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ testing. They might be interesting but they are most probably not.
=#
# ## Test different `nlabels_align` modes
using Graphs, GraphMakie, CairoMakie, NetworkLayout
import DataStructures: DefaultDict

CairoMakie.activate!(type="png") # hide
set_theme!(resolution=(400, 400)) #hide
g = SimpleGraph(9)
Expand Down Expand Up @@ -194,4 +196,95 @@ p[:ilabels_fontsize][] = 10
@save_reference fig

p[:node_color][] = :red
@save_reference fig
@save_reference fig

# ## Changes of node and label sizes
gc = circular_ladder_graph(5);
ons = Observable(30);
onf = Observable(30);
fig,ax,p = graphplot(gc; nlabels=repr.(vertices(gc)), node_size=ons, nlabels_fontsize=onf)
@save_reference fig

# Change node size
ons[] = 10; # check changes
@save_reference fig

# Change label font size
onf[] = 10; # check changes
@save_reference fig


# Do the same with a `Dict`
onf = Observable(Dict(1=>30, 10=>30));
ons = Observable(Dict(1=>30, 10=>30));
fig,ax,p = graphplot(gc; nlabels=repr.(vertices(gc)), node_size=ons, nlabels_fontsize=onf)
@save_reference fig

# Change label font size
onf[] = Dict(7=>30); # check changes
@save_reference fig

# Change node size
ons[] = Dict(7=>30); # check changes
@save_reference fig

# Do the same with a `DefaultDict`
ons = Observable(DefaultDict(70, 1=>30, 10=>30));
onf = Observable(DefaultDict(70, 1=>30, 10=>30));
fig,ax,p = graphplot(gc; nlabels=repr.(vertices(gc)), node_size=ons, nlabels_fontsize=onf)
@save_reference fig

# Change node size
ons[] = DefaultDict(20, 10=>70); # check changes
@save_reference fig

# Change label font size
onf[] = DefaultDict(20, 10=>70); # check changes
@save_reference fig

# ## Dict and DefaultDict
# Test out argument functionality with `Dict` and `DefaultDict`
# First with a normal `Dict`
gc = circular_ladder_graph(5);
fig,ax,p = graphplot(gc, nlabels=Dict(1=>"One", 2 => "Two"))
@save_reference fig

# And also with a `DefaultDict`
fig,ax,p = graphplot(gc, nlabels=DefaultDict("Unknown", 1=>"One", 2 => "Two"))
@save_reference fig

# ## Use Dict{Edge} for edge arguments
fig,ax,p = graphplot(gc, edge_color=Dict(Edge(7,8)=>:blue))
@save_reference fig

# try out also the DefaultDict
fig,ax,p = graphplot(gc, edge_color=DefaultDict(:green, Edge(7,8)=>:blue))
@save_reference fig

# Of course you can still use integers labeling
ind = findfirst(==(Edge(7,8)) , collect(edges(gc)))
fig,ax,p = graphplot(gc, edge_color=DefaultDict(:green, ind=>:blue))
@save_reference fig

# The same can be done with all enumerations of edge arguments
fig,ax,p = graphplot(gc, elabels=DefaultDict("Unknown", Edge(1,2)=>"1-2", Edge(7,8) => "7-8"))
@save_reference fig

# directed and undirected graphs are handled appropriately.
# For example for directed graphs
gcd = SimpleDiGraph(gc)
fig,ax,p = graphplot(gcd, elabels=DefaultDict("Unknown", Edge(8,7)=>"8-7", Edge(2,7) => "2-7"), nlabels=repr.(vertices(gcd)))
@save_reference fig

# and non-directed graphs
fig,ax,p = graphplot(gc, elabels=DefaultDict("Unknown", Edge(8,7)=>"8-7", Edge(2,7) => "2-7"), nlabels=repr.(vertices(gc)))
@save_reference fig

# Test edge-specific updates
ec = Observable(Dict(Edge(8,7)=>:blue))
fig,ax,p = graphplot(gc, edge_color=ec, nlabels=repr.(vertices(gc)))
@save_reference fig

# update `Observable`
ec[] = Dict(Edge(7,2)=> :green)
@save_reference fig
7 changes: 7 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ There are also [plot examples](generated/plots.md) and [interaction examples](ge
graphplot
```

## Passing arguments
The recipe can handle a range of argument types.
For all the arguments that support a collection of configurations per element, you pass-in a `Vector`.
However you can also pass in a `Dict` or a `DefaultDict` to only specify a configuration for a specific element of interest, while the rest get the default value.
The `keys` of the `Dict`ionaries are the `Int` index of the element or the `Edge` when reasonable.
See some demonstration on [Changes of node and label sizes](@ref), [Dict and DefaultDict](@ref) and [Use Dict{Edge} for edge arguments](@ref).

## Network Layouts
The layout algorithms are provided by [`NetworkLayout.jl`](https://github.com/JuliaGraphs/NetworkLayout.jl). See
the [docs](https://juliagraphs.org/NetworkLayout.jl/stable/) for a list of available layouts.
Expand Down
2 changes: 2 additions & 0 deletions src/GraphMakie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ using NetworkLayout
using Graphs
using Makie
using LinearAlgebra
using SimpleTraits

import Makie: DocThemer, ATTRIBUTES, project, automatic
import DataStructures: DefaultDict, DefaultOrderedDict

include("beziercurves.jl")
include("recipes.jl")
Expand Down
92 changes: 47 additions & 45 deletions src/recipes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ end

function Makie.plot!(gp::GraphPlot)
graph = gp[:graph]

dfth = default_theme(gp.parent, GraphPlot)

# create initial vertex positions, will be updated on changes to graph or layout
# make node_position-Observable available as named attribute from the outside
Expand Down Expand Up @@ -249,29 +251,29 @@ function Makie.plot!(gp::GraphPlot)

translate!(ilabels_plot, 0, 0, 1)

node_size = lift(ilabels_plot.plots[1][1], gp.ilabels_fontsize) do glyphcollections, ilabels_fontsize
node_size_m = lift(ilabels_plot.plots[1][1], gp.ilabels_fontsize) do glyphcollections, ilabels_fontsize
map(glyphcollections) do gc
rect = Rect2f(boundingbox(gc, Quaternion((1,0,0,0))))
norm(rect.widths) + 0.1 * ilabels_fontsize
end
end
else
node_size = @lift $(gp.node_size) === automatic ? scatter_theme.markersize[] : gp.node_size[]
node_size_m = @lift $(gp.node_size) === automatic ? scatter_theme.markersize[] : $(gp.node_size)
end

node_color = @lift if $(gp.node_color) === automatic
node_color_m = @lift if $(gp.node_color) === automatic
gp.ilabels[] !== nothing ? :gray80 : scatter_theme.color[]
else
$(gp.node_color)
end

node_marker = @lift if $(gp.node_marker) === automatic
node_marker_m = @lift if $(gp.node_marker) === automatic
gp.ilabels[] !== nothing ? Circle : scatter_theme.marker[]
else
$(gp.node_marker)
end

node_strokewidth = @lift if $(gp.node_strokewidth) === automatic
node_strokewidth_m = @lift if $(gp.node_strokewidth) === automatic
gp.ilabels[] !== nothing ? 1.0 : scatter_theme.strokewidth[]
else
$(gp.node_strokewidth)
Expand All @@ -287,42 +289,43 @@ function Makie.plot!(gp::GraphPlot)

# plot edges
edge_plot = edgeplot!(gp, edge_paths;
color=gp.edge_color,
linewidth=gp.edge_width,
gp.edge_attr...)
color=prep_edge_attributes(gp.edge_color, graph, dfth.edge_color),
linewidth=prep_edge_attributes(gp.edge_width, graph, dfth.edge_width),
gp.edge_attr...)

# plot arrow heads
arrow_shift = lift(edge_paths, to_px, gp.arrow_shift, node_marker, node_size, gp.arrow_size) do paths, tpx, shift, nmarker, nsize, asize
update_arrow_shift(graph[], gp, paths, tpx, node_marker, node_size)
arrow_shift_m = lift(edge_paths, to_px, gp.arrow_shift, node_marker_m, node_size_m, gp.arrow_size) do paths, tpx, shift, nmarker, nsize, asize
update_arrow_shift(graph[], gp, paths, tpx, node_marker_m, node_size_m, shift)
end
arrow_pos = @lift if !isempty(edge_paths[])
broadcast(interpolate, edge_paths[], $arrow_shift)
broadcast(interpolate, edge_paths[], $arrow_shift_m)
else # if no edges return (empty) vector of points, broadcast yields Vector{Any} which can't be plotted
Vector{eltype(node_pos[])}()
end
arrow_rot = @lift if !isempty(edge_paths[])
Billboard(broadcast($to_angle, edge_paths[], $arrow_pos, arrow_shift[]))
Billboard(broadcast($to_angle, edge_paths[], $arrow_pos, $(arrow_shift_m)))
else
Billboard(Float32[])
end
arrow_show = @lift $(gp.arrow_show) === automatic ? Graphs.is_directed($graph) : $(gp.arrow_show)
arrow_show_m = @lift $(gp.arrow_show) === automatic ? Graphs.is_directed($graph) : $(gp.arrow_show)
arrow_heads = scatter!(gp,
arrow_pos;
marker = gp.arrow_marker,
markersize = gp.arrow_size,
color = gp.edge_color,
rotations = arrow_rot,
strokewidth = 0.0,
markerspace = :pixel,
visible = arrow_show,
gp.arrow_attr...)
arrow_pos;
marker = prep_edge_attributes(gp.arrow_marker, graph, dfth.arrow_marker),
markersize = prep_edge_attributes(gp.arrow_size, graph, dfth.arrow_size),
color=prep_edge_attributes(gp.edge_color, graph, dfth.edge_color),
rotations = arrow_rot,
strokewidth = 0.0,
markerspace = :pixel,
visible = arrow_show_m,
gp.arrow_attr...)

# plot vertices
vertex_plot = scatter!(gp, node_pos;
color=node_color,
marker=node_marker,
markersize=node_size,
strokewidth=node_strokewidth,
gp.node_attr...)
color=prep_vertex_attributes(node_color_m, graph, scatter_theme.color),
marker=prep_vertex_attributes(node_marker_m, graph, scatter_theme.marker),
markersize=prep_vertex_attributes(node_size_m, graph, scatter_theme.markersize),
strokewidth=prep_vertex_attributes(node_strokewidth_m, graph, scatter_theme.strokewidth),
gp.node_attr...)

# plot node labels
if gp.nlabels[] !== nothing
Expand All @@ -341,12 +344,12 @@ function Makie.plot!(gp::GraphPlot)
end

nlabels_plot = text!(gp, positions;
text=gp.nlabels,
align=gp.nlabels_align,
color=gp.nlabels_color,
offset=offset,
fontsize=gp.nlabels_fontsize,
gp.nlabels_attr...)
text=prep_vertex_attributes(gp.nlabels, graph, Observable("")),
align=prep_vertex_attributes(gp.nlabels_align, graph, dfth.nlabels_align),
color=prep_vertex_attributes(gp.nlabels_color, graph, dfth.nlabels_color),
offset=offset,
fontsize=prep_vertex_attributes(gp.nlabels_fontsize, graph, dfth.nlabels_fontsize),
gp.nlabels_attr...)
end

# plot edge labels
Expand Down Expand Up @@ -389,15 +392,14 @@ function Makie.plot!(gp::GraphPlot)
offsets = map(p -> Point(-p.data[2], p.data[1])/norm(p), tangent_px)
offsets .= elabels_distance_offset(graph[], gp.attributes) .* offsets
end

elabels_plot = text!(gp, positions;
text=gp.elabels,
rotation=rotation,
offset=offsets,
align=gp.elabels_align,
color=gp.elabels_color,
fontsize=gp.elabels_fontsize,
gp.elabels_attr...)
text=prep_edge_attributes(gp.elabels, graph, Observable("")),
rotation=rotation,
offset=offsets,
align=prep_edge_attributes(gp.elabels_align, graph, dfth.elabels_align),
color=prep_edge_attributes(gp.elabels_color, graph, dfth.elabels_color),
fontsize=prep_edge_attributes(gp.elabels_fontsize, graph, dfth.elabels_fontsize),
gp.elabels_attr...)
end

return gp
Expand Down Expand Up @@ -742,11 +744,11 @@ end
Checks `arrow_shift` attr so that `arrow_shift = :end` gets transformed so that the arrowhead for that edge
lands on the surface of the destination node.
"""
function update_arrow_shift(g, gp, edge_paths::Vector{<:AbstractPath{PT}}, to_px, node_markers, node_sizes) where {PT}
function update_arrow_shift(g, gp, edge_paths::Vector{<:AbstractPath{PT}}, to_px, node_markers, node_sizes, shift) where {PT}
arrow_shift = Vector{Float32}(undef, ne(g))

for (i,e) in enumerate(edges(g))
t = getattr(gp.arrow_shift, i, 0.5)
t = getattr(shift, i, 0.5)
if t === :end
j = dst(e)
p0 = getattr(gp.node_pos, j)
Expand All @@ -771,11 +773,11 @@ function update_arrow_shift(g, gp, edge_paths::Vector{<:AbstractPath{PT}}, to_px

return arrow_shift
end
function update_arrow_shift(g, gp, edge_paths::Vector{<:AbstractPath{<:Point3}}, to_px)
function update_arrow_shift(g, gp, edge_paths::Vector{<:AbstractPath{<:Point3}}, to_px, shift)
arrow_shift = Vector{Float32}(undef, ne(g))

for (i,e) in enumerate(edges(g))
t = getattr(gp.arrow_shift, i, 0.5)
t = getattr(shift, i, 0.5)
if t === :end #not supported because to_px does not give pixels in 3D space (would need to map 3D coordinates to pixels...?)
error("`arrow_shift = :end` not supported for 3D plots.")
end
Expand Down
Loading
Loading