Flow Charts? LightGraphs?

How hard would it be to make a quick and dirty wrapper for flow chart plots from DAGs? I gave it a whirl for a jupyter notebook blog I am writing. Didn’t come out so hot!

using GraphRecipes
using Plots
using LightGraphs

g = WheelGraph(5)
add_edge!(g, 1, 2)
add_edge!(g, 2, 3)
add_edge!(g, 3, 4)
add_edge!(g, 4, 5)
add_edge!(g, 5, 3)
names = [:Thing, :Thingy :Thinger, :Things, :Stuff]
x = [0,0,0,0,0]
y = [5,4,3,2,1]
graphplot(g, x = x, y = y, names = names, markersize=2.9, shorten=0.23,
                arrow=1500, markercolor = :lightgray, color = :black, nodeshape=:rect)

Not really sure how to go about this or if this is just a bad call over-all. I think it could be really handy!

I made a lot of changes to GraphRecipes (including adding directed edges), but I haven’t tagged them yet. I will get around to that soon, but I don’t have access to Julia on my computer right now. What happens if you checkout master?

1 Like

I can give it a shot later today. The issue is I want this to be a blog/notebook so I don’t want to make readers pkg.add from master. That being said it’ll take a while before I finish this so checking the newest changes in the meantime is worthwhile!

I still don’t have access to a computer with Julia on it :frowning: .

Looking at your code, I don’t think that GraphRecipes is the right fit for you without some fairly serious modification. Right now we don’t do anything to make sure that edges go around nodes and other edges that are in their way. Instead, we always try to find a layout that minimizes intersections between edges.

The layout that you are forcing graphplot to use has edges 3\to4 and 4\to5 lying right on top of 5\to3. Presumably, you want edge 5\to3 to kind of go out to the side a little bit before it goes up to node 3. Collision avoidance could be a fun thing to add, although I can’t guaruntee that I could have it implemented and tagged in time for your blog post.

Since I can’t run the code, I could be totally wrong about the above. Also, I could be wrong about your expectations for the shape of a flowchart.

1 Like

That is basically the battle - collision avoidance and the arrows not mapping well to their origin/destination (when a box is used). I love your package its amazing for what its intended to do (plot graphs). I’m just wondering if we could/should extend it to make flowchart-like figures.

I also realize this isn’t a simple ask. I think really the only way for it to work is to define a ruleset for relative positions, and have an understanding of plotted boundaries(a lot of manual effort).

Maybe the cheap way forward for me is to follow the tree like recipes used in the docs? They do a really good job for everything except maybe loops/cliques. I just had an idea about how cool it would be to have a mathematical optimization which resulted in a graph/flowchart like object and having it be automatically plottable. About 90% of what I post on here is just to get people thinking outside the box.

Thanks! But it is not really my package, most of the initial work was done by Tom Brellof. Later, the JuliaPlots organization took on the work needed to maintain GraphRecipes and recently I have added a smatering of features. Tom Brellof was super influential in the Julia plotting universe once upon a time and he made some super powerful tools.

Have you had a look at TikzGraphs? I am fairly sure that they have collision avoidance.

Maybe the cheap way forward for me is to follow the tree like recipes used in the docs?

You might be able to get what you want that way, although I don’t think that it is too much to ask that the example that you gave just works. I definitely think that flowcharts like yours are not out of scope for GraphRecipes, the problem is that we haven’t added the machinery to do it yet.

1 Like

I finally have access to a computer with Julia on it!

I was able to solve your problem on master.

My solution is very hacky. Basically, there are two problems:

  1. Whenever you have all of the nodes in a line, GraphRecipes makes the window size too small and cuts all of the nodes in half.
  2. Edges don’t try to avoid each other as discussed above.

Problem 1 is a bug and is probably worth filing an issue on the repo for. Problem 2 is a missing feature and could also get its own issue.

The way I got around both problems is by creating ghost nodes that are there but can’t be seen. To get around problem one I placed a ghost node off to the side of the visible nodes that forced GraphRecipes to expand the window size. I then set self_edges_size=0, so that you don’t see the self loop for that node. To get around problem 2 I placed a ghost node (node 6) to the side of node 4 and instead of having an edge 5\to3 I made edges 5\to6 and 6\to4.

Here is my code:

using GraphRecipes
using Plots
using LightGraphs

# You had WheelGraph here, but I don't think that is what you intended?
g = DiGraph(7)
add_edge!(g, 1, 2)
add_edge!(g, 2, 3)
add_edge!(g, 3, 4)
add_edge!(g, 4, 5)
# Instead of adding an edge 5 -> 3, have an edge that goes from 5 to
# the ghost node, then to 3.
add_edge!(g, 5, 6)
add_edge!(g, 6, 3)
# Add an edge by itself that will force GraphRecipes to have a decent
# window size.
add_edge!(g, 7, 7)
names = [:Thing, :Thingy, :Thinger, :Things, :Stuff, "", ""]
x = [0,0,0,0,0,2,6]
y = [5,4,3,2,1,2,1]
graphplot(g, x=x, y=y, curvature_scalar=0.0, nodesize=0.5, 
          names=names, nodecolor=:lightgray, color=:black,
          nodeshape=:rect, self_edge_size=0.0)



Clever!!! Thank you I can work with your temporary solution it’s really all I need. Now that being said - I can invision some cool applications to flow charty like recipes. Thanks for thinking about this, I’ve been so tied up in like 12 different things.

1 Like

Yes, I agree. I will try to think of what will be a good solution, however, I can’t really guarantee that I can make things move quickly. In the meantime, I think that tikz is a much more polished option. I think that the best way to access tikz from inside Julia is through PGFPlotsX. For example:

using PGFPlotsX

p = @pgf TikzPicture(
    # Create nodes.
    raw"\node[draw] (Node1) at (0,0) {Node1};",
    raw"\node[draw] (Node2) at (0,1) {Node2};",
    raw"\node[draw] (Node3) at (0,2) {Node3};",
    raw"\node[draw] (Node4) at (0,3) {Node4};",
    # Flow connections.
    raw"\draw[->] (Node4) to (Node3);",
    raw"\draw[->] (Node3) to (Node2);",
    raw"\draw[->] (Node2) to (Node1);",
    # Connecting backwards.
    raw"\draw[->] (Node1) to[in=0,out=0] (Node3);",


1 Like

That’s really really nice and professional. I’ll use that :). I’ll post up a link to the blog when its done and give you a shout out if you want :D.

Cool! Just tag me when it is done.

1 Like

Will do, this solution is working great for me. I gave it a test run.