Creating a graph with variable size of vertices and variable thickness of edges

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


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


To fix the arrowhead positioning, use

PerformanceGoal -> "Quality"

If I remove the EdgeShapeFunction and add the above option, your code produces this:

enter image description here

Using the latest version of IGraph/M (prerelease), you can also simplify and structure your styling code. We start by creating a graph with edge and vertex weights:

g = Graph[trans, VertexWeight -> r, EdgeWeight -> rr]

Then each IGEdgeMap and IGVertexMap operator sets one style property based on another one. We chain multiple operators for each styling step. You can use // instead of /*, but the Front End indents more nicely with /*.

Graph[g, (* set static style options *)  
   VertexShapeFunction -> "Capsule", 
   VertexLabels -> Placed["Name", Center],
   PerformanceGoal -> "Quality", ImageSize -> Large
  ] //
  IGEdgeMap[ (* scale edge thickness and arrowhead size based on edge weight *)   
   Directive[Thickness[#], Arrowheads[4 #]] &,
   EdgeStyle -> IGEdgeProp[EdgeWeight]
  ] /*  
  IGVertexMap[ (* scale vertices based on vertex weight *)
   # &,
   VertexSize -> IGVertexProp[VertexWeight]
  ] /*  
  IGVertexMap[ (* scale vertex labels based on vertex weight *)   
   FontSize -> 15 # &,
   VertexLabelStyle -> IGVertexProp[VertexWeight]
  ]

enter image description here