How to recompute the layout of a Graph?

13

4

I asked a question about changing Graph properties in a similar way to how Show can change Graphics properties. The answer was to use SetProperty.

Unfortunately this does not work for GraphLayout. Take the following example:

g1 = RandomGraph[{10, 20}]
g2 = RandomGraph[{10, 20}, GraphLayout -> "SpringEmbedding"]

{PropertyValue[g1, GraphLayout], PropertyValue[g2, GraphLayout]}

(* ==> {Automatic, "SpringEmbedding"} *)

ng1 = SetProperty[g1, GraphLayout -> "CircularEmbedding"]
ng2 = SetProperty[g2, GraphLayout -> "CircularEmbedding"]

{PropertyValue[ng1, GraphLayout], PropertyValue[ng2, GraphLayout]}

(* ==> {Automatic, "SpringEmbedding"} *)

Note that while GraphLayout can be queried through the standard property API, it doesn't seem like it can be set. Again, a hack like HighlightGraph[g, {}, GraphLayout -> "CircularEmbedding"] will work, but it is just a hack.

One could retrieve the vertex and edge lists of the graph and build a new Graph[...], but that is both tedious and it'll discard other property values.

So, what is the best way to re-layout a graph?

Right-clicking the graph and choosing a new layout works, but I'm looking for a programmatic way. Also, right-clicking and choosing a new layout is terribly slow---much much slower than rebuilding the graph or using HighlighGraph (can anyone reproduce this problem, is it slow for you as well?)

Update

Some spelunking reveals that GraphComputation`CloneGraph[g, GraphLayout -> "CircularEmbedding"] will do the job, but I'd rather not use internal and undocumented functionality for this.

Szabolcs

Posted 2012-04-20T13:17:09.493

Reputation: 213 047

To clarify: I'm not looking to just just visualize a graph, so GraphPlot is not appropriate here. I want to re-layout it using the new Graph functionality, and also retrieve the coordinates. – Szabolcs – 2012-04-20T13:18:14.610

I cannot confirm slow speed for right-click layouting. This seems to work with the same speed as a rebuild with different layout. This is on Win 7 64bit with a quadcore Intel i7 CPU with 16GB RAM. – Yves Klett – 2012-04-20T13:23:23.830

@Yves I have a single-core CPU here, I suspect it has to do soemthing with the slowness. I get a "spinner" that runs for a long time before the new layout is shown. – Szabolcs – 2012-04-20T13:27:35.813

If you have a particularly nasty graph please share. I tried with your examples and some rather larger ones - all worked speedily. Time for new hardware? – Yves Klett – 2012-04-20T13:33:38.950

This seems to change the "layout": PropertyValue[g1, Properties] = {"GraphProperties" -> {GraphLayout -> "CircularEmbedding"}}; But the image doesn't reconfigure itself. – amr – 2012-04-20T17:01:35.127

I am not sure if you noticed that I added an answer to this old question. – Vitaliy Kaurov – 2012-07-12T08:00:40.967

In version 11.2.0, {PropertyValue[ng1, GraphLayout], PropertyValue[ng2, GraphLayout]} gives {"CircularEmbedding", "CircularEmbedding"} as it should. – kglr – 2017-09-28T17:36:39.870

Answers

2

Imagine that you have a graph with quite a few complex custom properties - below every edge and vertex have their unique properties:

g = Graph[Table[Style[j, Hue[j/2^8 - 1]], {j, 0, 2^8 - 1}], 
  Table[Style[j \[UndirectedEdge] FromDigits[Drop[IntegerDigits[j, 2], 1], 2], 
    Hue[j/2^8]], {j, 0, 2^8 - 1}], GraphLayout -> "RadialDrawing", 
  GraphStyle -> "LargeNetwork"]

enter image description here

To keep these properties and change the GraphLayout:

ToExpression@StringReplace[ToString[InputForm[g]], "RadialDrawing" -> "SpringElectricalEmbedding"]

enter image description here

Alternatively you could just use Shift+Ctrl+E and retype the GraphLayout option.

Yet another alternative, which avoids potentially unsafe string replacements, is the following:

ReleaseHold[
 ToExpression[ToString[InputForm[g]], InputForm, Hold] /. 
  "RadialDrawing" -> "SpringElectricalEmbedding"
]

This converts the Graph object to a non-atomic Mathematica expression with the head Graph. Since this expression is not atomic, standard expression manipulation functions, including ReplaceAll, can be used on it.

Vitaliy Kaurov

Posted 2012-04-20T13:17:09.493

Reputation: 66 672

Thanks for the answer! You're working around the fact that Graph is not an atomic object by converting it to InputForm as a string. That's a nice idea though manipulating code as string makes me a little uneasy ... Are you sure that all of the properties of the graph are preserved when converting to input form (they are in my limited test)? – Szabolcs – 2012-07-12T09:09:16.070

@Szabolcs It is a trick, but string processing is quite robust. If you look at the InputForm output in the above case, you'll see it is not small, yet it works. This is basically programmatic code editing, which is a general approach. – Vitaliy Kaurov – 2012-07-12T16:01:39.047

1I'm a bit uncomfortable with changing code in the string representation ... suppose for example that we need to replace Ticks with something else. When using a string repersentation, it's not so easy to tell apart Ticks from FrameTicks without starting to write a rudimentary parsers. More importantly, it's all too easy to miss these little details and not think of an edge case where string replacement may lead to undesirable results. – Szabolcs – 2012-07-16T13:11:45.490

Perhaps instead of doing string replacement, we could improve your approach to get the graph representation as an actual expression: ToExpression[ToString@InputForm[g], InputForm, Hold] Then ReplaceAll what needs to be replaced and ReleaseHold. What do you think? If you think it's a good idea, could you edit it into the answer (or would you mind if I did)? Then I'll accept. – Szabolcs – 2012-07-16T13:15:10.823

@Szabolcs Sure, if you find a more robust way - please go ahead and edit. – Vitaliy Kaurov – 2012-07-16T14:31:38.087

3

I posted a way to update options of Graph objects like Show works for Graphics here, could you please confirm whether this is a solution for your needs with recomputing the layout?

Options[showGraph] = Options@Graph;
showGraph[g_] := g;
showGraph[g_Graph, {new___}] := showGraph[g, new];
showGraph[g_Graph, new : OptionsPattern[]] := Module[{old = Options@g, opts},
   opts = DeleteDuplicates[First /@ Join[old, {new}]];
   Graph[VertexList@g, EdgeList@g, Thread[opts -> (opts /. {new} /. old)]]
   ];

It simply replaces existing option values with new ones and adds new options, while maintaining the first two arguments of Graph without change. Using Vitaliy's example:

g1 = Graph[Table[Style[j, Hue[j/2^8 - 1]], {j, 0, 2^8 - 1}], 
   Table[Style[
     j <-> FromDigits[Drop[IntegerDigits[j, 2], 1], 2], 
     Hue[j/2^8]], {j, 0, 2^8 - 1}], GraphLayout -> "RadialDrawing", 
   GraphStyle -> "LargeNetwork", ImageSize -> 300];
g2 = showGraph[g1, GraphLayout -> "SpringElectricalEmbedding"];

Column@{{g1, PropertyValue[g1, GraphLayout]}, {g2, 
   PropertyValue[g2, GraphLayout]}}
PropertyValue[g1, VertexCoordinates]
PropertyValue[g2, VertexCoordinates]

Mathematica graphics

István Zachar

Posted 2012-04-20T13:17:09.493

Reputation: 44 135

2

Edit

If you know the options you want to preserve, you can explicitly list them and change the ones you want to alter through ReplaceAll:

ng1 = g1;
a = AbsoluteOptions[g1, {GraphLayout, DirectedEdges, EdgeLabelStyle, EdgeLabels, 
      GraphRoot, Properties, VertexLabels, VertexShape,  VertexLabelStyle}] 
   /. {(GraphLayout -> _) -> GraphLayout -> "CircularEmbedding"};
Graph[Join[VertexList[g1],EdgeList[g1]], a]

This is admittedly a bit clunky, but I cannot find a simpler way.

You can't simply grab all of the AbsoluteOptions. For example, in the default options, EdgeShapeFunction-> $Failed, returned by AbsoluteOptions, will cause Graph to fail. I'm not sure whether there is such a thing as a universal list of desirable graph properties.

DavidC

Posted 2012-04-20T13:17:09.493

Reputation: 15 949

Yep, this is the simple way I'd like to avoid because it loses other information, e.g. vertex sizes or highlighting. Obtaining the vertex coordinates is fortunately easy, as you say. It also works with PropertyValue – Szabolcs – 2012-04-20T13:58:58.410

@belisarius How did you discover the right hand side of the rule? AbsoluteOptions[g1, EdgeShapeFunction] returns EdgeShapeFunction -> $Failed – DavidC – 2012-04-20T23:24:43.547

@Szabolcs You are correct. I updated my answer aiming to recover some of the likely missing information. Take a look. – DavidC – 2012-04-20T23:26:56.367

@David AbsoluteOption[g1] just plain – Dr. belisarius – 2012-04-20T23:30:14.710

And there are SEVERAL bugs there – Dr. belisarius – 2012-04-20T23:30:53.053

@belisarius My first reaction was also to use AbsoluteOptions[g1] plain, but MMA would not process the information correctly; it even refused to provide a graph. One of the difficulties arose because of EdgeShapeFunction-> $failed. I am puzzled. – DavidC – 2012-04-20T23:44:31.617

@David run this one http://ideone.com/pi8hK

– Dr. belisarius – 2012-04-21T00:21:20.073

@belisarius I ran it. It did not work. More troubling is that I could not understand the code. Perhaps after a night's sleep it will look clearer to me. – DavidC – 2012-04-21T01:30:24.667

@David Sleep well! And don't mind it too much! :) – Dr. belisarius – 2012-04-21T02:08:59.283

1

Not an answer, but an explanation why the properties route doesn't work. I suspect that GraphLayout is an option of the Graph, and not a property. While it is possible to introduce an inert property named GraphLayout using

PropertyValue[g, Properties] = {"GraphProperties" -> 
                                    {GraphLayout -> "CircularEmbedding"}}

as amr suggests, this doesn't set the option:

g = RandomGraph[{10, 20}, GraphLayout -> "SpringEmbedding"];

FullForm[g]

Mathematica graphics

PropertyValue[g, Properties] = {"GraphProperties" -> 
                                    {GraphLayout -> "CircularEmbedding"}}

FullForm[g]

Mathematica graphics

Sjoerd C. de Vries

Posted 2012-04-20T13:17:09.493

Reputation: 63 549

Strange that PropertyValue can read the option name too though. – Szabolcs – 2012-04-21T10:52:13.717

1@Szabolcs True. I'm a bit stymied. In all examples of the properties talk is only about vertex and edge properties, I couldn't find anything about setting Graph level properties. – Sjoerd C. de Vries – 2012-04-22T15:50:21.013