4
$\begingroup$

I am trying to plot a network with colored links and nodes. I would like to color links with a gradient depending on the colors of its endpoints/nodes. For instance, a link between a blue and a red node should have a linear gradient between blue and red. I would also like for links to be curved so a I am using also a BezierCurve function.

In order to obtain the gradient on the BezierCurve I am using VertexColors, which however works only on the Line graphics. So what I am doing is: for every couple of nodes get their coordinates, interpolate and create a BezierFunction, run the BezierFunction over an evenly split range and get a collection of lines approximating a BezierCurve, then color the lines.

However, I am unable to obtain colored links and would like to know where is the problem. The code is this one:

 versiz = {1 -> 0.8317766166719344`, 2 -> 0.7193685818395111`, 
   3 -> 0.6238324625039507`, 4 -> 0.7917171988845775`, 
   5 -> 0.769484807238461`, 6 -> 0.6907755278982137`, 
   7 -> 0.583773044716594`, 8 -> 0.48283137373023005`, 
   9 -> 0.48283137373023005`, 10 -> 0.48283137373023005`, 
   11 -> 0.48283137373023005`, 12 -> 0.4158883083359672`, 
   13 -> 0.48283137373023005`, 14 -> 0.5375278407684164`, 
   15 -> 0.4158883083359672`, 16 -> 0.4158883083359672`, 
   17 -> 0.5375278407684164`, 18 -> 0.4158883083359672`, 
   19 -> 0.4158883083359672`, 20 -> 0.4158883083359672`};
cols = Table[If[RandomReal[] < 0.3, Red, Blue], {i, 1, 20}];

edges = {{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}, {1, 
    9}, {1, 10}, {1, 11}, {1, 14}, {1, 15}, {1, 16}, {1, 18}, {1, 
    19}, {1, 20}, {2, 3}, {2, 4}, {2, 5}, {2, 6}, {2, 7}, {2, 10}, {2,
     11}, {2, 12}, {2, 13}, {2, 20}, {3, 4}, {3, 5}, {3, 6}, {3, 
    8}, {3, 9}, {3, 13}, {4, 5}, {4, 6}, {4, 10}, {4, 11}, {4, 
    12}, {4, 13}, {4, 14}, {4, 15}, {4, 16}, {4, 17}, {4, 18}, {5, 
    7}, {5, 8}, {5, 9}, {5, 12}, {5, 14}, {5, 15}, {5, 17}, {5, 
    18}, {5, 19}, {6, 7}, {6, 9}, {6, 11}, {6, 13}, {6, 16}, {6, 
    20}, {7, 8}, {7, 15}, {7, 19}, {8, 10}, {9, 17}, {10, 12}, {11, 
    18}, {13, 14}, {14, 16}, {14, 17}, {17, 19}, {17, 20}};

    Graph[UndirectedEdge @@@ edges, 
 EdgeShapeFunction -> ({AbsoluteThickness[4], 
     Line[BezierFunction[{#1[[1]], #1[[1]] + 
          0.5 RotationMatrix[.3].(#1[[2]] - #1[[1]]), #1[[2]]}] /@ 
       Range[0, 1, 0.1], 
      VertexColors -> (Blend[cols[[List @@ #2]], #] & /@ 
         Range[0, 1, 0.1])]} &), VertexSize -> versiz, 
 VertexStyle -> Thread[Range[VertexCount[net]] -> cols]]

I am afraid that the Blend function is not working properly here. If I substitute #2 with fixed colors, I do get colored links (although they are static):

 Graph[UndirectedEdge @@@ edges, 
     EdgeShapeFunction -> ({AbsoluteThickness[4], 
         Line[BezierFunction[{#1[[1]], #1[[1]] + 
              0.5 RotationMatrix[.3].(#1[[2]] - #1[[1]]), #1[[2]]}] /@ 
           Range[0, 1, 0.1], 
          VertexColors -> (Blend[{Red, Blue}, #] & /@ 
             Range[0, 1, 0.1])]} &), VertexSize -> versiz, 
     VertexStyle -> Thread[Range[20] -> cols]]

enter image description here

$\endgroup$
  • $\begingroup$ Can you also post the exact code that does not work? The one in the question does work fine, I assume that you already substituted #2. $\endgroup$ – Szabolcs Aug 29 '18 at 15:11
  • $\begingroup$ Thanks for the reply! I added also the code that does not work. $\endgroup$ – MatheM Aug 29 '18 at 15:46
4
$\begingroup$

You have a nested pure-function, both levels of which use Slot:

({AbsoluteThickness[4], 
   Line[BezierFunction[{#1[[1]], #1[[1]] + 
        0.5 RotationMatrix[.3].(#1[[2]] - #1[[1]]), #1[[2]]}] /@ 
     Range[0, 1, 0.1], 
    VertexColors -> (Blend[cols[[List @@ #2]], #] & /@ 
       Range[0, 1, 0.1])]} &)

You intend for the #2 to bind to the outer &, but it instead binds to the inner &. For situations like this, you can change one of these to a Function with named arguments:

Graph[UndirectedEdge @@@ edges, 
 EdgeShapeFunction -> ({AbsoluteThickness[4], 
     Line[BezierFunction[{#1[[1]], #1[[1]] + 
          0.5 RotationMatrix[.3].(#1[[2]] - #1[[1]]), #1[[2]]}] /@ 
       Range[0, 1, 0.1], 
      VertexColors -> (Function[val, Blend[cols[[List @@ #2]], val]] /@
          Range[0, 1, 0.1])]} &), VertexSize -> versiz, 
 VertexStyle -> Thread[Range[20] -> cols]]

enter image description here

$\endgroup$
  • $\begingroup$ This is a great solution, thanks! I would like to ask another question: unfortunately adding the edge bundling layout seems not to work with the above code. In fact, adding GraphLayout -> {"EdgeLayout" -> "HierarchicalEdgeBundling"} seems to break the styling of the lines. Is there any way of integrating the above edge colouring with an edge bundling algorithm maybe? @szabolcs. $\endgroup$ – MatheM Aug 30 '18 at 13:10
  • $\begingroup$ @MatheM - that looks like a separate issue. For the edge bundling layout, it seems that the EdgeShapeFunction is given not the line segments, but the control points for Bezier curve. Here is a modification that should do what you want. $\endgroup$ – Jason B. Aug 30 '18 at 19:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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