-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Layered layout drawing algorithm #4743
base: main
Are you sure you want to change the base?
Conversation
draw_netorkx_edges updated to draw edge paths; testing remains to do.
The The I'll leave comments about |
modifié : drawing/layout.py
Sorry my PR was messy. I was in a hurry yesterday. About the I'll now bootstrap the tests. |
For testing, I was thinking about calling the tests = [
{
"edges": [(1, 2)],
"align": "vertical",
"expected_pos": {1: np.array([0., 1.]), 2: np.array([ 0., -1.])},
"expected_edges_path": {}
},
{
"edges": [(1, 2), (1, 3)],
"align": "vertical",
"expected_pos": {1: np.array([-0.5, 1. ]), 3: np.array([-0.5, -0.5]), 2: np.array([ 1. , -0.5])},
"expected_edges_path": {}
},
] Called with: G = DiGraph()
G.add_edges_from(tests[i]['edges'])
pos, edges_path = nx.layered_layout(G, align=tests[i]['align'])
# incorrect, just for the example: needs a function for deep comparison
assert pos == tests[i]['expected_pos']
assert edges_path == tests[i]['expected_edges_path'] I see no other function does this though. Would my test process be alright, still? |
I'm happy with the code, now! Even big graphs seem free of glitches (at the cost of more time complexity). Last things to do before we can call it a day:
We could do more (layer width minimization, non-DAGs, MultiDiGraphs, spine edges...), but the result is already good looking as-is, and should serve most purposes. So: future works! |
I added references, cleaned up the doc, built it. It looks ok. Also added a gallery example. Now all that's missing is the arrow head for long edges (see example). I tried, but couldn't figure out FancyArrowPatch's magic. |
I took a quick look at the code -- nothing close... Strange that the arrowheads show up fine for some edges and not others. I expected them to appear but be mispositioned. But it looks to me like they aren't even there for some edges. |
Sorry for the unnecessary modifications. I'm not experimented in FOSS contributions. I made the changes you mention for myself; e.g. I felt it was clearer to have utils/ubiquitous functions at the file's top, but didn't revert before shipping, sorry. Regarding the drawing of long edges: the FancyArrowPatch object is created differently depending on the edge being "long" or not. Long edges have to follow the path described in Thanks for your review! |
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.
There's a lot here so it will take time to get a full picture of how all the pieces fit together, but from what I can gather, it seems like the edge path specification can be decoupled from the process of determining the node positions - though like I said there's a lot here so I may just be missing that part.
I am still of the opinion that it would be much better to have any new layout conform to the same pattern as the others (i.e. only computing node positions, with a relatively consistent signature and output) and to keep the edge drawing and node position determination entirely separate.
So my question is: is it possible to formulate this layout in such a way that determining the node positions can be performed without considering edges at all? I understand that doing so would be suboptimal for performance(in #4710 you mention that this would require computing things multiple times) , visual appeal, etc. but is the coupling of edge paths and node positions intrinsic to this layout (not the drawing)? If so, then this represents a significant break not only from the API, but also the layout semantics in NX.
Yes indeed. It is an intrinsic objective of Sugiyama's method (the one I used) to minimize edge crossings. Towards this goal, in the algorithm, each non-unit edge is separated into a path spanning several virtual "dummy" edges, before node positioning is performed.
We can skip edge positioning altogether and let We could call another function returning only edge positioning. It would call the exact same code as |
I recently proposed to add a new
layered_layout
algorithm to NetworkX's display toolkit, in discussion #4710.This is still work in progress, but working to the point where I'd like NetworkX community's reviews.
I want to focus on solving glitches for some edge cases (edges drawn awkward when they could be straight, too big spacing between groups of nodes...). If someone has time, notably to fix the display of long edges (see below), I'd be glad :)
FancyArrowPatch
? Usingpath
parameter hides the arrow for long edges, probably becauseFancyArrowPatch
discardsshrinkA
andshrinkB
parameters whenpath
is given. Seeny_pylab.py:794
.import numpy as np
appeared 17 times inlayout.py
. I made it a global import in this file. -> reverteddim
parameter when most layouts don't supportdim != 2
? A lot of layout functions do that.Hail NetworkX! :D