-
Notifications
You must be signed in to change notification settings - Fork 23
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
Text boxes instead of text labels #57
Comments
Currently not really, no. Each graph plot is based on a scatter + some connecting lines in GraphMakie. You might want to check out GraphRecipes for that. I think, they have this kind of feature. |
Thank's for the hints! Do GraphRecipes also work with Makie? I've only used them with Plots and I didn't find any references to Makie in the documentation. |
No they don't. It is Plots only... |
Ok thank's, then I have all the information needed so far! |
I'll keep this open because eventually I'd like to expand GraphMakie in that direction. This won't happen to soon though. There are some things which need to be done
Finally i am not sure whether this can be achieved as part of the |
Oh, it would be fantastic, if you could realize these plans. I'm looking forward to it. |
I needed something similar, so I've written code for it. It's only good for one character labels, though. And doesn't cover anything that @hexaeder has thought about above: No interaction, no handling of overlapping nodes, not even proper text boxes. I thought I share it here, in case somebody finds this useful. code# ╔═╡ 0de55944-f737-4a4f-849d-3a925b1eceb3
using Makie: automatic, Figure, Axis, hidedecorations!, hidespines!, text!
# ╔═╡ 7fd33644-b26a-439b-8a63-29535abc1dd3
using GraphMakie: graphplot!
# ╔═╡ c2bf3f66-b017-44ac-844e-cd2350828ddb
using NetworkLayout: Spring
# ╔═╡ 40ef5e6a-5b73-4963-bc71-5faad1948081
using Graphs: vertices, nv
# ╔═╡ 9fbfe652-e31b-4a09-99ed-62db24bc03c5
function numbered_graphplot(g; minimal = true, figure = (;), axis = (;), kwargs...)
fig = Figure(; figure...)
ax = Axis(fig[1,1]; axis...)
numbered_graphplot!(ax, g; minimal, kwargs...)
fig
end
# ╔═╡ a5be84d8-d9d5-4c1d-8b2c-7eca3857f2fb
function numbered_graphplot!(ax, g;
minimal=false, extend_limits=automatic,
nlabels = vertices(g),
layout = Spring(), node_color = (:lightgray, 1), node_attr = (;), kwargs...)
n = nv(g)
node_attr = (; node_attr..., marker = :circle, color = node_color, strokewidth = 1, markersize = n < 10 ? 35 : 45)
if minimal
hidedecorations!(ax)
hidespines!(ax)
end
if extend_limits !== automatic
positions = layout(g)
ax.limits[] = extended_box(positions, extend_limits)
else
ax.limits[] = (nothing, nothing, nothing, nothing)
end
#poly!(ax, Circle.(layout(g), 0.07px), color = (:white, 0))
graphplot!(ax, g; node_attr, layout, kwargs...) #node_marker = '1':'5')
text!(ax, string.(nlabels); position=layout(g), align = (:center, :center))
end
# ╔═╡ 0442bc7c-9c74-4325-9f8f-5f77b169a495
md"""
## Utils
"""
# ╔═╡ da154cf8-0939-4505-a8b7-3cb979a0a371
function extended_extrema(points, margin = 0.05)
min, max = extrema(points)
ε = (max - min) * margin
if ε > 0
return min - ε, max + ε
else
return nothing, nothing
end
end
# ╔═╡ 6cb5f932-ee5c-40db-bed7-ec592532cfff
function extended_box(points, margin = 0.05)
(extended_extrema(first.(points), margin)...,
extended_extrema(last.(points), margin)...)
end
# ╔═╡ c05bf8a6-d5db-43d7-a855-ed1a98d71057
md"""
## Tests
"""
# ╔═╡ 53ac8dd8-26d1-4c8b-ba50-580a7086dbf4
using Graphs: complete_digraph, cycle_graph, cycle_digraph
# ╔═╡ d10d10bf-ae56-480c-b60c-232c0e0ad3ce
using NetworkLayout: Shell
# ╔═╡ fbd2ab88-7f46-4e64-8954-99539a7fb75e
using CairoMakie: DataAspect
# ╔═╡ 5554c7be-7e00-47c1-b1cb-fc11c84acd9f
begin
g = complete_digraph(5)
fig = Figure(font = "CMU")
ax = Axis(fig[1,1], aspect = DataAspect())
#hidedecorations!(ax)
numbered_graphplot!(ax, g; layout = Shell(), arrow_size = 15)
fig
end
# ╔═╡ 3a5e4d4e-204f-44d4-924f-9d85abef79c1
let
g = cycle_digraph(5)
numbered_graphplot(g, arrow_size = 15)
end
# ╔═╡ 700d5452-c2ce-4ab1-aa40-2a8ffaa0f6bf
let
g = cycle_graph(5)
numbered_graphplot(g, nlabels = 'A':'E')
end
|
Ah that looks really good! ... and demonstrates again the need for such solutions. I'm currently playing around with |
@greimel, it seems like you only need to get the boundingbox and maximum width of the text. I suggest the following basic modification, which allows you to automatically find the text size: Codefunction text_bbox(textstring::AbstractString, textsize::Union{AbstractVector, Number}, font, align, rotation, justification, lineheight)
glyph_collection = Makie.layout_text(
textstring, textsize,
font, align, rotation, justification, lineheight,
RGBAf(0,0,0,0), RGBAf(0,0,0,0), 0f0
)
return Rect2f(Makie.boundingbox(glyph_collection, Point3f(0), Makie.to_rotation(rotation)))
end
# ╔═╡ a5be84d8-d9d5-4c1d-8b2c-7eca3857f2fb
function numbered_graphplot!(ax, g;
minimal=false, extend_limits=automatic,
nlabels = vertices(g),
layout = Spring(), node_color = (:lightgray, 1), node_attr = (;), node_markersize = automatic, node_marker = :rect, node_font = Makie.defaultfont(), node_textsize = 16, kwargs...)
n = nv(g)
# Extract text sizes and layout accordingly
label_sizes = [widths(text_bbox(string(label), node_textsize, node_font, (:center, :center), 0f0, 0, 0)) for label in nlabels]
# label_diags = collect(sqrt.(sum.([label_size .^ 2 for label_size in label_sizes])))
# max_size = maximum(first.(label_sizes))# .+ node_textsize
# We can specify markersize as a Vec2f, which is the eltype of label_sizes.
# Thus, we can explicitly cause the node drawing to be large enough to accomodate
# the marker size.
node_attr = (;
node_attr...,
marker = node_marker, color = node_color,
strokewidth = 1, markersize = node_markersize == automatic ? map(x -> x .+ node_textsize, label_sizes) : node_markersize,
markerspace = :pixel,
)
if minimal
hidedecorations!(ax)
hidespines!(ax)
end
if extend_limits !== automatic
positions = layout(g)
ax.limits[] = extended_box(positions, extend_limits)
else
ax.limits[] = (nothing, nothing, nothing, nothing)
end
#poly!(ax, Circle.(layout(g), 0.07px), color = (:white, 0))
graphplot!(ax, g; node_attr, layout, kwargs...) #node_marker = '1':'5')
text!(ax, string.(nlabels); position=layout(g), font = node_font, textsize = node_textsize, align = (:center, :center))
end Basically, what this does is it computes the text's bounding box by using Makie's layout utilities, and passes the computed widths to This means that all markers are sized independently. With this, let
g = cycle_digraph(15)
numbered_graphplot(g, arrow_size = 15, nlabels = string.(100 .* (1:15)))
end Setting |
@asinghvi17 thanks, that looks great! Is there a way to have proper circles (non-squished) with your way? |
Yea, just select the maximum width instead of using both :) |
Phantastic, thanks! |
@hexaeder This looks very good, doesn't it? Still it doesn't address all of your concerns above.
What do you think about this now? Also, what about
One could integrate this using existing keywords. E.g.
Do would you think about a draft PR that tries to integrate this into GraphMakie? |
I think this would be a great addition, even without having all the features. I think there are good reasons for both: extending the current recipe and creating a second recipe. Extending the recipe comes with a less clear interface. For example, what should happen if you combine On the other hand, the different parts of the graph plots need to be more modular in order to play well with different root recipes. I started this by creating a separate |
@greimel @asinghvi17 are either of you planning on writing a PR for this? |
See https://discourse.julialang.org/t/textbox-graph-with-networklayout-with-labels-cut-off-using-graphmakie/96566/ on the expanding limits. |
I'm using
GraphMakie
to plot trees. Basically I get what I want, but the text labels on the nodes don't really look good, because they get plotted underneath the edges (or the node markers):I would like to have some rectangles around the text labels and the edges attaching to these rectangles. More like this:
How can I achieve this using GraphMakie?
The text was updated successfully, but these errors were encountered: