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$
2
  • $\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, 2018 at 15:11
  • $\begingroup$ Thanks for the reply! I added also the code that does not work. $\endgroup$
    – MatheM
    Aug 29, 2018 at 15:46

1 Answer 1

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$
2
  • $\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, 2018 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, 2018 at 19:54

Your Answer

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

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