Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I'm trying to create a graph to represent transitions between different states of a system. I would like to represent the time the systems spent in a state with the size of the vertex and the frequency of transition between two states with the thickness of the edge connecting the two vertices. In short I need to control the size of vertices and the thickness of edges.

Now that I grasp the difference between Graph and GraphPlot a bit better, I wanted to implement this using the newer Graph functunality, specifically VertexSize and EdgeStyle.

Here is my clumsy attempt:

trans = Uncompress@
   "1:eJyVV01vwjAMRfu47U/sv3RKKc2KGsahxw2YOE0aXPff17RJSZD8/HIBga3Efn5+\
dl4/f/rT32q1ujyNH+35cj09+F8v40d1/j1+XY+\
Ht8P30T2Pf9ihbyvn7Y0T3GbjzZtyM5LbYmcP9Els++FdTWJy7EwrOEYzTjbeRkHyODnvB\
adgnb7d8KHi4e3OgBudmb5sB3xsV1CBOTLpymCdv1sp/\
mBlzhq9tJrfqolRC9aSDNSzGPwxFv5f05GAldDVoJKbrgBWJsnCIuFMB/\
28JVXNMR7IQsfVvZSTCD07V79Z78Clo1VLIS+YVn5/2H67Q3h4M83wZr2B4W/\
oCmhaFDXSWysUWcVpH4sElyUTFYsEGxnPRl7nlRgTFoFBu0xGjuDToRLAs5GeeDWqes22H\
ORPLDl/FENXLXCmuVWQanrkBwmT88uGjhh8JgIyYRI91EW4aBoqtOIbg60RxD+IAGjuZC+\
QRSeXfC2qkhGor6gqD60WfdoZTOy8SGu9iONKFEJeVO7eELQGMvOD0UDYaXHN5a6DT5Zlv\
GuYlu2TmhIyD726bP5gSnswmEttWR9puG1wH6WE1VuSBI2sVNA6cfxlK6JIx7utFDE7vI5\
lyAL+Kv09FopgpA9t+\
cIcCcjZMXgYV4YWrHd86DFyR2xpTh012aCEY8sSoy3sX3A0OHUHTjWYWgR8fv/wd/kB";
l = VertexList[Graph[trans]];
(*Weigths for vertices*)
r = RandomReal[{0.5, 1}, Length[l]];
vs = Transpose@{l, r} /. List[a_, b_] -> Rule[a, b];
(*Adjust font size*)
vls = Transpose@{l, r} /. 
   List[a_, b_] -> Rule[a, Directive[Black, Bold, 20*b]];
(*Weigths for line thicknes*)
rr = RandomReal[{0.1, 1}, Length[DeleteDuplicates@trans]]/100;
es = (First@# -> Directive[Thickness[Last@#], Opacity[.5]]) & /@ 
   Transpose@{DeleteDuplicates@trans, rr};
g = Graph[DeleteDuplicates@trans, 
  VertexLabels -> Placed["Name", Center], 
  VertexShapeFunction -> "Capsule", VertexSize -> vs, 
  VertexLabelStyle -> vls, EdgeStyle -> es, 
  EdgeShapeFunction -> 
   GraphElementData["ShortUnfilledArrow", "ArrowSize" -> 0.03]]

But the result is useless (the text is not readable and it's not clear from where to where the arrows are going):

Resulting graph

How can I either fix this graph so that it's readable or implement variable vertex sizes and variable edge thickens using GraphLayout?

EDIT @kguler's comment helps. so using:

esf = Function[
    a, (First@
       a -> ({Arrowheads[{{.03, 1}}], 
         Arrow[#1, {.10 + 6 Last@a, .15}]} &))] /@ 
   Transpose@{DeleteDuplicates@trans, rr};
g = Graph[DeleteDuplicates@trans, 
  VertexLabels -> Placed["Name", Center], VertexSize -> vs, 
  VertexLabelStyle -> vls, EdgeStyle -> es, EdgeShapeFunction -> esf(*,
  EdgeShapeFunction->GraphElementData["ShortUnfilledArrow",
  "ArrowSize"->0.03]*)]

I get Mathematica graphics, which is almost usable. Is there perhaps a way to draw vertices on top of the edges?

share|improve this question
    
To get a list of vertices from a Graph you could do VertexList[Graph[trans]]. –  Heike Jun 5 '12 at 10:31
    
@Heike Thanks, I knew there had to be a simple way (I was looking under Property). –  Ajasja Jun 5 '12 at 10:46
1  
You might want to change the EdgeShapeFunction to something like EdgeShapeFunction -> ({Arrowheads[{{.03, 1}}], Arrow[#1, {.1, .15}]} &) to avoid too much traffic on top of vertices. –  kguler Jun 5 '12 at 11:26
    
@kguler Thanks, your suggestion is very helpful (See edit). Is there perhaps a way to draw vertices on top of the edges? –  Ajasja Jun 5 '12 at 15:11
    
Capsule is a difficult shape to deal with - calculation of the appropriate setbacks gets really complicated because it depends on the entire layout. But, for Circle the following works: EdgeShapeFunction -> ({Arrowheads[{{.03, 1}}], Arrow[#1, {.2 #2[[1]] /. vs, .2 #2[[2]] /. vs}]} &). –  kguler Jun 5 '12 at 15:12
show 1 more comment

2 Answers

up vote 6 down vote accepted

Using the setback argument of Arrow in the EdgeShapeFunction to account for different vertex sizes

EdgeShapeFunction -> 
      ({Arrowheads[{{.03, 1}}], Arrow[#1, {.2  #2[[1]] /. vs, .2 #2[[2]] /. vs}]} &)];

takes care of the first problem. One way to approach the second problem (putting vertices on top) is to superimpose an edge-less version of g on top of g.

First get a slightly modified version of your original graph,

l = VertexList[Graph[trans]];
r = RandomReal[{0.5, 1}, Length[l]];
vs = Transpose@{l, r} /. List[a_, b_] -> Rule[a, b];
vls = Transpose@{l, r} /. List[a_, b_] -> Rule[a, Directive[Black, Bold, 16 b]];
rr = RandomReal[{0.1, 1}, Length[DeleteDuplicates@trans]]/100;
es = (First@# -> Directive[Thickness[Last@#], Opacity[.5]]) & /@ 
   Transpose@{DeleteDuplicates@trans, rr};
g = Graph[DeleteDuplicates@trans, 
    VertexLabels -> Placed["Name", Center], 
    VertexShapeFunction -> "Circle", VertexStyle -> {Opacity[1]}, 
    VertexSize -> vs, VertexLabelStyle -> vls, EdgeStyle -> es, 
    EdgeShapeFunction -> 
      ({Arrowheads[{{.03, 1}}], Arrow[#1, {.2  #2[[1]] /. vs, .2 #2[[2]] /. vs}]} &)];

Then get an edge-less version of g using

Fold[SetProperty[{#1, #2}, EdgeStyle -> Opacity[0]] &, g, EdgeList[g]]

Finally, Show the two graphs.

All three graphs in a column:

 Column[{g, 
  Fold[SetProperty[{#1, #2}, EdgeStyle -> Opacity[0]] &, g, EdgeList[g]], 
  Show[g, Fold[SetProperty[{#1, #2}, EdgeStyle -> Opacity[0]] &, g, EdgeList[g]]]}]

enter image description here

EDIT: Perhaps, you do not want the edges to be completely occluded by the vertices. In that case, we can play with combinations of the opacity settings of the edges and vertex styles to make vertices look less cluttered. For example, using

es = (First@# -> Directive[Thickness[Last@#], Opacity[.3]]) & /@ 
     Transpose@{DeleteDuplicates@trans, rr};
vstyl = (Sequence @@ {# -> Hue@{.6 # /. vs}} & /@ l);

(where I modified the opacity setting in es to 3 and defined a vertex style setting that uses the values in vs to determined the vertex color), in

 Graph[DeleteDuplicates@trans, VertexLabels -> Placed["Name", Center], 
  VertexShapeFunction -> "Circle", VertexSize -> vs, 
  VertexStyle -> vstyl, VertexLabelStyle -> vls, EdgeStyle -> es, 
  EdgeShapeFunction -> 
   ({Arrowheads[{{.03, 1}}], Arrow[#1, {.2  #2[[1]] /. vs, .2 #2[[2]] /. vs}]} &),
 ImageSize -> 600]

gives

enter image description here

Another alternative is to use styles for the vertices in HighlightGraph as follows:

 HighlightGraph[g, {#, Style[#, {Opacity[1], Hue@{.2  # /. vs}}]} & /@ VertexList[g]]

which gives:

enter image description here

share|improve this answer
    
Thanks! Got something which is quite OK. Are there any options to make the edges go around vertices (like in LayeredGraphPlot)? But this should probably be a whole new question then ;) –  Ajasja Jun 12 '12 at 12:11
    
@Ajasja,thank you for the accept. And, yes that would be an interesting new question indeed:) –  kguler Jun 12 '12 at 19:20
add comment

Since I already have this code, I'm going to show an example using GraphPlot and an adjacency graph based on a matrix nums where the links can take positive values other than 1, or zero. Rather than having two arrows for each link, I use line thickness to indicate the sum of the two link values, color to show the ratio of the net (difference between the two directions’ values) to gross (sum of the two link values), and the size of the arrowhead to show which is the stronger link direction.

As kguler noted in comments, EdgeRenderingFunction (or in the case of Graph rather than GraphPlot, EdgeShapeFunction) can be specified so that the arrowheads don’t overlap the vertex.

GraphPlot[nums, DirectedEdges -> True, 
 VertexRenderingFunction -> ({White, EdgeForm[Black], Disk[#, .04], 
     Black, Text[names[[#2]], #1]} &), 
 EdgeRenderingFunction -> ({AbsoluteThickness[(nums[[#2[[1]], #2[[
           2]]]] + nums[[#2[[2]], #2[[1]]]])/(0.08 maxthick)], 
     RGBColor[
      Abs[(nums[[#2[[1]], #2[[2]]]] - 
          nums[[#2[[2]], #2[[1]]]])]/(0.8 (nums[[#2[[1]], #2[[2]]]] + 
           nums[[#2[[2]], #2[[1]]]])), 0.1, 0.7], 
     Arrowheads[
      0.010 + 0.004 Sign@(nums[[#2[[1]], #2[[2]]]] - 
           nums[[#2[[2]], #2[[1]]]])], Arrow[#1, 0.05]} &), 
 VertexLabeling -> True, ImageSize -> 900, 
 PlotLabel -> Style["Plot Label", Bold, 14, FontFamily -> "Arial"], 
 ImagePadding -> 0, PlotRangePadding -> 0.02]

I've just labelled the vertices with names = Range[20] but you could use strings or whatever you like.

enter image description here

Here is an example with multiple arrows, where thickness, gray shade and arrowhead size all depend on the value of the element in the adjaceny matrix.

GraphPlot[Sign[nums], DirectedEdges -> True, MultiedgeStyle -> True, 
 VertexRenderingFunction -> ({White, EdgeForm[Black], Disk[#, .04], 
     Black, Text[names[[#2]], #1]} &), 
 EdgeRenderingFunction -> (With[{relexp = (nums[[#2[[1]], #2[[2]]]])/
        maxthick}, {AbsoluteThickness[relexp*20.], 
      RGBColor[relexp*0.8, relexp*0.8, relexp*0.8], 
      Arrowheads[0.06 relexp + 0.008], Arrow[#1, 0.05]}] &), 
 VertexLabeling -> True, ImageSize -> 900, 
 PlotLabel -> Style["Plot Heading", Bold, 14, FontFamily -> "Arial"], 
 ImagePadding -> 0, PlotRangePadding -> 0.02]

enter image description here

Setting a numerical value for the MultiEdgeStyle option can bring the arrow pairs closer together and tidy up the look considerably.

 GraphPlot[Sign[nums], DirectedEdges -> True, MultiedgeStyle -> 0.02, 
 VertexRenderingFunction -> ({White, EdgeForm[Black], Disk[#, .04], 
     Black, Text[names[[#2]], #1]} &), 
 EdgeRenderingFunction -> (With[{relexp = (nums[[#2[[1]], #2[[2]]]])/
        maxthick}, {AbsoluteThickness[relexp*20.], 
      RGBColor[relexp*0.8, relexp*0.8, relexp*0.8], 
      Arrowheads[0.06 relexp + 0.008], Arrow[#1, 0.05]}] &), 
 VertexLabeling -> True, ImageSize -> 700, ImagePadding -> 0, 
 PlotRangePadding -> 0.02]

enter image description here

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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