14
$\begingroup$

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.

$\endgroup$
7
  • $\begingroup$ 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. $\endgroup$
    – Szabolcs
    Apr 20, 2012 at 13:18
  • $\begingroup$ 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. $\endgroup$
    – Yves Klett
    Apr 20, 2012 at 13:23
  • $\begingroup$ @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. $\endgroup$
    – Szabolcs
    Apr 20, 2012 at 13:27
  • $\begingroup$ 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? $\endgroup$
    – Yves Klett
    Apr 20, 2012 at 13:33
  • $\begingroup$ This seems to change the "layout": PropertyValue[g1, Properties] = {"GraphProperties" -> {GraphLayout -> "CircularEmbedding"}}; But the image doesn't reconfigure itself. $\endgroup$
    – amr
    Apr 20, 2012 at 17:01

4 Answers 4

2
$\begingroup$

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.

$\endgroup$
5
  • $\begingroup$ 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)? $\endgroup$
    – Szabolcs
    Jul 12, 2012 at 9:09
  • $\begingroup$ @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. $\endgroup$ Jul 12, 2012 at 16:01
  • 1
    $\begingroup$ I'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. $\endgroup$
    – Szabolcs
    Jul 16, 2012 at 13:11
  • $\begingroup$ 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. $\endgroup$
    – Szabolcs
    Jul 16, 2012 at 13:15
  • $\begingroup$ @Szabolcs Sure, if you find a more robust way - please go ahead and edit. $\endgroup$ Jul 16, 2012 at 14:31
3
$\begingroup$

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

$\endgroup$
2
$\begingroup$

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.

$\endgroup$
9
  • $\begingroup$ 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 $\endgroup$
    – Szabolcs
    Apr 20, 2012 at 13:58
  • $\begingroup$ @belisarius How did you discover the right hand side of the rule? AbsoluteOptions[g1, EdgeShapeFunction] returns EdgeShapeFunction -> $Failed $\endgroup$
    – DavidC
    Apr 20, 2012 at 23:24
  • $\begingroup$ @Szabolcs You are correct. I updated my answer aiming to recover some of the likely missing information. Take a look. $\endgroup$
    – DavidC
    Apr 20, 2012 at 23:26
  • $\begingroup$ @David AbsoluteOption[g1] just plain $\endgroup$ Apr 20, 2012 at 23:30
  • $\begingroup$ And there are SEVERAL bugs there $\endgroup$ Apr 20, 2012 at 23:30
1
$\begingroup$

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

$\endgroup$
2
  • $\begingroup$ Strange that PropertyValue can read the option name too though. $\endgroup$
    – Szabolcs
    Apr 21, 2012 at 10:52
  • 1
    $\begingroup$ @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. $\endgroup$ Apr 22, 2012 at 15:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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