16
$\begingroup$

Most graph layouts supported by Mathematica use straight lines for edges; or at least something that only depends on the coordinates of the two adjacent vertices of the edge and nothing else.

A special exception is the layered embedding for directed acyclic graphs:

Graph@{1 -> 11, 2 -> 7, 3 -> 19, 4 -> 10, 4 -> 11, 4 -> 14, 4 -> 19, 
  5 -> 10, 5 -> 18, 6 -> 1, 6 -> 12, 6 -> 16, 6 -> 19, 8 -> 10, 
  9 -> 2, 9 -> 7, 9 -> 12, 9 -> 18, 10 -> 11, 10 -> 15, 11 -> 2, 
  11 -> 7, 13 -> 19, 13 -> 20, 14 -> 15, 15 -> 3, 15 -> 9, 16 -> 14, 
  17 -> 3, 17 -> 4, 18 -> 12, 19 -> 9, 19 -> 11, 20 -> 6}

Mathematica graphics

This layout generator can do advanced edge routing.

Now suppose I have my own layout generator and I want to apply it to a Mathematica Graph. In most cases all I need to do is to set the VertexCoordinates property. But what can I do if I also have edge routing information? How can I store this information in the graph object? When using the "LayeredEmbedding", such information does seem to be present because the EdgeShapeFunction receives not only the endpoints for drawing the lines, but also intermediate ones. So note that the routing is not done by the EdgeShapeFunction; it is instead precomputed and stored as a set of points which are then converted to graphics objects by this function.

Can I manually specify the points along which the edges will run?

$\endgroup$
  • $\begingroup$ If you're doing both edge layout and vertex layout, you might consider just writing your own graph-plotting function using Graphics[] and the Point[] (or Disk[]/Circle[]), Arrow[], BezierCurve[], etc. primitives. At this point, it sounds like you are already doing most of the hard work in the general graph layout/plotting problem. $\endgroup$ – nben Sep 19 '15 at 15:04
  • $\begingroup$ @user21382 I want to make it well integrated, supporting all other style options (such as VertexStyle, etc). Take a look here: github.com/szhorvat/IGraphM $\endgroup$ – Szabolcs Sep 19 '15 at 15:14
  • $\begingroup$ Gotcha, makes sense. I have had similar kinds of library/graphics/display design problems myself (github.com/noahbenson/Neurotica). I don't know offhand if there is a 'pure' solution, but one solution that comes to mind is to overload MakeBoxes for your graphs specifically, then use use GraphPlot with Prolog to draw the edges manually and specify in the GraphPlot options that no edges be drawn by GraphPlot. This forces you to implement edge style options, but the rest will be automatic. I can post a longer answer with an example if that sounds like what you want? $\endgroup$ – nben Sep 19 '15 at 15:21
  • 2
    $\begingroup$ Have you looked into the GraphComputation context? Perhaps there is something useful in there. No time to spelunk right now $\endgroup$ – Dr. belisarius Sep 20 '15 at 5:27
15
$\begingroup$

I would do it like this:

The example graph g:

g = Graph[{1 <-> 2, 2 <-> 3, 3 <-> 1}];

Desired locations of the vertice in result:

vtxPosStore = Association[{
                1 -> {0, 0},
                2 -> {1, 0},
                3 -> {.5, 1}
                }];

Desired edge-shapes:

edgeRoutingStore = Thread[# -> (Join[
                                            {vtxPosStore[[Key[#1]]]},
                                            RandomReal[1, {4, 2}],
                                            {vtxPosStore[[Key[#2]]]}
                                            ] & @@@ #)] &[EdgeList[g] /.
                    ue_UndirectedEdge :> Sort[ue]] // Association;

The EdgeShapeFunction and VertexShapeFunction will ignore their first argument, and extract the geometric information from vtxPosStore and edgeRoutingStore through the second arguments (i.e. e_ and v_):

Clear[ef]
ef[terminals_List, e_] :=
    Block[{pts},
            pts = edgeRoutingStore[[Key[e]]];
            {
             AbsoluteThickness[RandomInteger[{2, 4}]], Hue[RandomReal[], .6, .7], 
             pts // BSplineCurve // Arrow,
             AbsoluteThickness[1], Dashed, GrayLevel[.6], pts // Line
            }
        ]

Clear[vf]
vf[pos_List, v_, size_List] :=
    Block[{truePos, hue},
        truePos = vtxPosStore[[Key[v]]];
        hue = RandomReal[];
            {
               EdgeForm[Hue[hue, .6, .7]], Hue[hue, .3, .9],
               Disk[truePos, size RandomReal[{2, 4}], 
                    2 π {RandomReal[{0, .25}], RandomReal[{.75, 1}]}]
            }
        ]

Thus the result will be fully customizable:

Graph[EdgeList[g],
    EdgeShapeFunction -> ef,
    VertexShapeFunction -> vf,
    VertexCoordinates -> (VertexList[g] /. vtxPosStore),
    VertexLabels -> "Name"
  ]

graph with customized edge-routing

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.