3
$\begingroup$

I have different cylinders, in a graph with vertex coordinates specification. I would like to plot these cylinders with different radii consistent with a related element in a vector q. My code is:

q = {1, 3, 0.5, -1, -2};
Grafo = Graph[{1 <-> 2, 2 <-> 3, 3 <-> 4, 4 <-> 5, 5 <-> 1}, 
EdgeWeight -> q];
el = EdgeList[Grafo];
edgestylea = 
Thread[el -> (Directive[
ColorData[{"Rainbow", {Min[q], Max[q]}}][#]] & /@ q)];
Graph3D[Grafo, EdgeStyle -> edgestylea, 
EdgeShapeFunction -> ({ColorFunction -> (ColorData["Rainbow", #] & /@
q), Cylinder[#, If[# < 0, 0.1, 0.5] & /@ q]} &), 
VertexShapeFunction -> ({Yellow, Sphere[#, 1]} &), 
VertexCoordinates -> {{0, 0, 0}, {0, 0, 10}, {10, 0, 10}, {10, 10, 
0}, {5, 15, 10}}]

Why doesn't it work?

Furthermore, how can I simplify my code?

$\endgroup$
  • 2
    $\begingroup$ Please make a minimal example that demonstrates the problem. $\endgroup$ – Szabolcs May 2 '17 at 10:13
  • $\begingroup$ @Szabolcs, what are you talking about? an image? $\endgroup$ – Gae P May 2 '17 at 10:20
  • 1
    $\begingroup$ Follow the link in my comment. It is explained there. Most of the code you posted here is irrelevant to the question and is just a hindrance for either understanding or solving your problem. Please remove it yourself. Do not wait for someone else to do it. $\endgroup$ – Szabolcs May 2 '17 at 10:25
2
$\begingroup$

Why doesn't your code work?

The EdgeShapeFunction should be a function that takes two arguments:

  • the coordinates of the points an edge will pass through
  • the name of that edge

and returns a set of graphics primitives and directives that describe the shape of the edge: one single edge. It is used on edges one at a time.

Be sure to always read the Details section of reference pages in the documentation. This is explained in that section.

Now look at your edge shape function:

yourFun = {ColorFunction -> (ColorData["Rainbow", #] & /@ q), 
    Cylinder[#, If[# < 0, 0.1, 0.5] & /@ q]} &;

Did you test it on its own, without using it in Graph? It is important to always do this to better understand what is happening.

Suppose it is used for an edge that goes from point {0,0,0} to point {1,1,1} and connects vertices 1 and 2:

yourFun[{{0, 0, 0}, {1, 1, 1}}, 1 <-> 2]
(* {ColorFunction -> {RGBColor[0.857359, 0.131106, 0.132128], 
   RGBColor[0.857359, 0.131106, 0.132128], RGBColor[
   0.513417, 0.72992, 0.440682], RGBColor[
   0.471412, 0.108766, 0.527016], RGBColor[
   0.471412, 0.108766, 0.527016]}, 
 Cylinder[{{0, 0, 0}, {1, 1, 1}}, {0.5, 0.5, 0.5, 0.1, 0.1}]} *)

What's wrong with this?

ColorFunction is not a graphics directive. Also, you already used the EdgeStyle option, and it worked, so what are you trying to achieve with ColorFunction?

And the second argument of Cylinder is not a number, as it should be. A list of numbers makes no sense for a single cylinder. Mathematica tells you this in the error message that appears when you move the mouse over the output of your code.

From this, it should be clear why your code does not work. The key thing to remember that each edge is processed individually by the EdgeShapeFunction.

How to set a separate thickness for each edge?

There are two ways to set the edge thickness separately for each edge in three dimensions:

1. Look up the thickness based on the edge's name in the EdgeShapeFunction

q = {1, 3, 0.5, -1, -2};
thicknesses = If[# < 0, 0.02, 0.1] & /@ q;
edges = {1 <-> 2, 2 <-> 3, 3 <-> 4, 4 <-> 5, 5 <-> 1};

asc = AssociationThread[Sort /@ edges -> thicknesses]
(* <|1 <-> 2 -> 0.1, 2 <-> 3 -> 0.1, 3 <-> 4 -> 0.1, 
 4 <-> 5 -> 0.02, 1 <-> 5 -> 0.02|> *)

Graph3D[edges, 
 EdgeShapeFunction -> ({CapForm["Round"], Tube[{First[#1], Last[#1]}, asc@Sort[#2]]} &)]

Mathematica graphics

I used Tube instead of Cylinder because it supports rounded caps: CapForm. You can use Cylinder if you prefer it.

I also used Sort on each edge to put it into a canonical form, and make sure that 1<->2 is treated the same as 2<->1.

2. Set a different EdgeShapeFunction for each edge

edgeFun[thickness_] := {CapForm["Round"], 
   Tube[{First[#1], Last[#1]}, thickness]} &

Graph3D[
 edges,
 EdgeShapeFunction -> Thread[edges -> (edgeFun /@ thicknesses)]
]

Mathematica graphics

For a two-dimensional graph layout we could simple use the Thickness directive in the EdgeStyle. This is unfortunately not possible in 3D, so we needed to resort to EdgeShapeFunction.

How to do the same with the IGraph/M package?

Finally, you may find it easier to do this kind of styling using the IGraph/M package. I would do it like this:

g = Graph3D[edges, EdgeWeight -> q, 
  VertexCoordinates -> {{0, 0, 0}, {0, 0, 10}, {10, 0, 10}, {10, 10, 0}, {5, 15, 10}}]

Mathematica graphics

Mathematica graphics

Graph[g, VertexStyle -> Yellow, VertexSize -> 0.2] //
 IGEdgeMap[
   ColorData["Rainbow"],
   EdgeStyle -> Rescale@*IGEdgeProp[EdgeWeight]
 ] //
 IGEdgeMap[
   Function[weight,
    {CapForm["Round"], Tube[#1, If[weight < 0, 0.1, 0.5]]} &
   ],
   EdgeShapeFunction -> IGEdgeProp[EdgeWeight]
 ]

Mathematica graphics

IGEdgeMap[function, prop -> propfun] is a function itself. If you apply it to the graph g, it will set the property prop for each edge of the graph. Here we are setting the EdgeStyle and EdgeShapeFunction properties. The property values will be taken from the list function /@ propfun[g], and applied to the corresponding edge from EdgeList[g].

IGEdgeProp[EdgeWeight] is a function that returns the list of EdgeWeights when applied to g (i.e. just the values from q):

IGEdgeProp[EdgeWeight][g]
(* {1, 3, 0.5, -1, -2} *)

We apply two IGEdgeMap operators: one to set the colour through EdgeStyle and one to set the thickness through EdgeShapeFunction.

You can add a legend using

Legended[..., BarLegend[{"Rainbow", MinMax[IGEdgeProp[EdgeWeight][g]]}]]

If you find this notation easy and intuitive, then go ahead and enjoy the package. If you find it confusing, I recommend staying away until you get more familiar with Mathematica. All this styling can be done without this package. The package simply makes it a bit easier.

$\endgroup$

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.