I am using a textbox graph with NetworkLayout. Using their layout algorithms it creates the positions based on the graph but when the labels are bigger than the points it cuts it of. What would be a good solution for computing the limits conserving the placement and avoiding the labels to cut off?
One could in principle write a function that solves for the limits that should be set so that all text elements are within those bounds. But because text extent is usually in screen space, this depends on axis size as well, and if the text is too large or the axis too small, there doesn’t even have to be a solution. Or the limits would have to get ridiculously wide.
I believe that is one of the issues since one can’t just adjust the limits afterwards as the positions get updated. Therefore one needs to solve the positions simultaneously.
phew, finally i got it but took me so much longer than i am willing to admit. Its not super nice and readable, I guess this can be expressed much better with the right linear algebra.
using GraphMakie using GLMakie using Graphs using GeometryBasics: HyperRectangle, Point2f g = complete_graph(3) nlabels=["this is a super long node label", "this isn't", "but this is again, or is isn't it?\nWell it is.\nAnd also multiline!"] fig, ax, p = graphplot(g; nlabels, layout=_->[(0,1),(1,0),(0,-1)], nlabels_align=[(:right,:bottom), (:left,:center), (:left,:top)])
function update_limits!(ax) p = only(ax.scene.plots) @assert p isa GraphPlot nodep = get_node_plot(p) textp = get_nlabel_plot(p) to_corners = r -> (Point2f(r.origin[1:2]), Point2f(r.origin[1:2] + r.widths[1:2])) to_px = pts -> Makie.project(ax.scene, pts) # get lower left and upper right node bounding box in data and px space n1_dat, n2_dat = to_corners(boundingbox(nodep)) n1, n2 = to_px(n1_dat), to_px(n2_dat) # get text bounding box in pixel sapce t1, t2 = to_corners(boundingbox(textp)) # get axis limits in data and pixel space ax1_dat, ax2_dat = to_corners(ax.finallimits) ax1, ax2 = to_px(ax1_dat), to_px(ax2_dat) # check difference between nodelabel and node bounding box in px px_diff1 = map(x->min(0, x), t1-n1) px_diff2 = map(x->max(0, x), t2-n2) # define "targets" in pixelspace where n1 and n2 bounding should end up n1_target = ax1-px_diff1 + Point2f(20, 20) n2_target = ax2-px_diff2 - Point2f(20, 20) # calculate axis limits such as bounding box of node plot goes to target scale = (n2_dat - n1_dat) ./ (n2_target - n1_target) origin = n1_dat - scale .* (n1_target - ax1) width = ((n2_dat - n1_dat) ./ (n2_target - n1_target)) .* (ax2 - ax1) xlims!(ax, origin, origin+width ) ylims!(ax, origin, origin+width ) end update_limits!(ax)