Prevent auto-layout of Graph[] objects in Mathematica 8
Asked Answered
B

3

6

Some types of objects have special input/output formatting in Mathematica. This includes Graphics, raster images, and, as of Mathematica 8, graphs (Graph[]). Unfortunately large graphs may take a very long time to visualize, much longer than most other operations I'm doing on them during interactive work.

How can I prevent auto-layout of Graph[] objects in StandardForm and TraditionalForm, and have them displayed as e.g. -Graph-, preferably preserving the interpretability of the output (perhaps using Interpretation?). I think this will involve changing Format and/or MakeBoxes in some way, but I was unsuccessful in getting this to work.

I would like to do this in a reversible way, and preferably define a function that will return the original interactive graph display when applied to a Graph object (not the same as GraphPlot, which is not interactive).

On a related note, is there a way to retrieve Format/MakeBoxes definitions associated with certain symbols? FormatValues is one relevant function, but it is empty for Graph.

Sample session:

In[1]:= Graph[{1->2, 2->3, 3->1}]
Out[1]= -Graph-

In[2]:= interactiveGraphPlot[%] (* note that % works *)
Out[2]= (the usual interactive graph plot should be shown here)
Brought answered 9/5, 2011 at 14:49 Comment(1)
Szabolcs, please try my $PrePrint version and tell me if it works.Helotry
H
2

Though I do not have Mathematica 8 to try this in, one possibility is to use this construct:

Unprotect[Graph]

MakeBoxes[g_Graph, StandardForm] /; TrueQ[$short] ^:= 
 ToBoxes@Interpretation[Skeleton["Graph"], g]

$short = True;

Afterward, a Graph object should display in Skeleton form, and setting $short = False should restore default behavior.

Hopefully this works to automate the switching:

interactiveGraphPlot[g_Graph] := Block[{$short}, Print[g]]

Mark's concern about modifying Graph caused me to consider the option of using $PrePrint. I think this should also prevent the slow layout step from taking place. It may be more desirable, assuming you are not already using $PrePrint for something else.

$PrePrint = 
  If[TrueQ[$short], # /. _Graph -> Skeleton["Graph"], #] &;

$short = True

Also conveniently, at least with Graphics (again I cannot test with Graph in v7) you can get the graphic with simply Print. Here, shown with Graphics:

g = Plot[Sin[x], {x, 0, 2 Pi}]

(*  Out =  <<"Graphics">>  *)

Then

Print[g]

enter image description here

I left the $short test in place for easy switching via a global symbol, but one could leave it out and use:

    $PrePrint = # /. _Graph -> Skeleton["Graph"] &;

And then use $PrePrint = . to reset the default functionality.

Helotry answered 9/5, 2011 at 16:33 Comment(8)
It seems to work. interactiveGraphPlot gives the original, but using the interactive features reverts it to the <<Graph>> form. (Actually this part wasn't so important anyway.) I should learn how Format and MakeBoxes work, and the difference between them (and also ToBoxes). E.g. why is that the unmodified MakeBoxes does NOT return an interactive object, ToBoxes does, yet one needs to modify MakeBoxes here?Brought
I don't think I understand what you said, but ToBoxes in needed because the output of MakeBoxes is, expectably, supposed to be Boxes; leaving it out will result in an error. MakeBoxes by default is doing (something like) ToBoxes unless you give it special rules, like this one.Helotry
I guess I don't get it. Is it truly worth calling Unprotect on a built in command so that the output of Graph becomes -Graph-? I do agree that output format of a graph as an image is odd, perhaps even unfortunate. The question is, what is the proper way to deal with it? It seems to me that simple suppression of the output should be the recommended approach.Assent
@Mark, suppressing output is the standard way to do this since version 6, and I agree that it is usually best. However, sometimes the direct graphics formatting gets in the way. There are times, if g is a Graphics object, and I have a expression like {1, 2, p, 3} I would rather see {1, 2, -Graphic-, 3} than a list with an actual graphic embedded in it, especially when it comes at the cost of slow display.Helotry
@Mr. Wizard - Good point! I am typically very cautious when using Unprotect. I share notebooks with a lot of people - students and colleagues alike. In my experience, any customization that I do is likely to confuse others and will typically not be very robust. That is the source of my reticence.Assent
@Mark Good point yourself. Would modifying $PrePrint be more comfortable?Helotry
@Mr.Wizard, you might be interested in this: groups.google.com/group/comp.soft-sys.math.mathematica/… I saw this discussed many years ago on MathGroup, but I can't find that discussion now.Brought
@Szabolcs, thank you, that is interesting. But does it relate to this answer?Helotry
O
2

You can use GraphLayout option of Graph as well as graph-constructors to suppress the rendering. A graph can still be visualized with GraphPlot. Try the following

{gr1, gr2, gr3} = {RandomGraph[{100, 120}, GraphLayout -> None], 
  PetersenGraph[10, 3, GraphLayout -> None], 
  Graph[{1 -> 2, 2 -> 3, 3 -> 1}, GraphLayout -> None]}

enter image description here

In order to make working easier, you can use SetOptions to set GraphLayout option to None for all graph constructors you are interested in.

Over answered 19/5, 2011 at 19:53 Comment(0)
A
1

Have you tried simply suppressing the output? I don't think that V8's Graph command does any layout, if you do so. To explore this, we can generate a large list of edges and compare the timings of graph[edges];, Graph[edges];, and GraphPlot[edges];

In[23]:= SeedRandom[1];
edges = Union[Rule @@@ (Sort /@ 
      RandomInteger[{1, 5000}, {50000, 2}])];

In[25]:= t = AbsoluteTime[];
graph[edges];

In[27]:= AbsoluteTime[] - t

Out[27]= 0.029354

In[28]:= t = AbsoluteTime[];
Graph[edges];

In[30]:= AbsoluteTime[] - t

Out[30]= 0.080434

In[31]:= t = AbsoluteTime[];
GraphPlot[edges];

In[33]:= AbsoluteTime[] - t

Out[33]= 4.934918

The inert graph command is, of course, the fastest. The Graph command takes much longer, but no where near as long as the GraphPlot command. Thus, it seems to me that Graph is not, in fact, computing the layout, as GraphPlot does.

The logical question is, what is Graph spending it's time on. Let's examine the InputForm of Graph output in a simple case:

Graph[{1 -> 2, 2 -> 3, 3 -> 1, 1 -> 4}] // InputForm

Out[123]//InputForm=
    Graph[{1, 2, 3, 4}, 
      {DirectedEdge[1, 2], 
       DirectedEdge[2, 3], 
       DirectedEdge[3, 1], 
       DirectedEdge[1, 4]}]

Note that the vertices of the graph have been determined and I think this is what Graph is doing. In fact, the amount of time it took to compute Graph[edges] in the first example, comparable to the fastest way that I can think to do this:

Union[Sequence @@@ edges]; // Timing

This took 0.087045 seconds.

Assent answered 10/5, 2011 at 2:57 Comment(3)
Graph itself does not do the layout, its interactive output does. It's just like waiting for graphics to be rendered. Therefore you can't even measure this time using either Timing or AbsoluteTiming. Yes, I can suppress the output, but the whole point is that I don't really want to bother doing that, and I will forget it occasionally anyway: I don't want to be punished for forgetting to suppress the output by having to wait for half a minute or more.Brought
In fact now I started to wonder whether it's the layout algorithm or the graphics rendering that takes so long to complete...Brought
I've edited my example to properly measure the time, even though there's some front end stuff going on that I had supposed to be negligible. I think the timings still support my conclusions. I agree that the graphics rendering is likely to be more expensive than the vertex layout.Assent

© 2022 - 2024 — McMap. All rights reserved.