Here is an example:

edge1 = Property[1 -> 2, EdgeStyle -> Red];
edge2 = Property[1 -> 2, EdgeStyle -> Blue];

Graph[{edge1, edge2}]


This does not work the way I want it. How can I make it so that I get two edges, one blue and one red?

  • $\begingroup$ Please post actual code in addition to pictures, so people can copy/paste your code and play with it. $\endgroup$
    – MarcoB
    Commented Aug 19, 2015 at 20:30
  • $\begingroup$ If one edge is directed and another not, there's no problem: Graph[{1, 2}, {Property[1 \[DirectedEdge] 2, EdgeStyle -> Red], Property[1 <-> 2, EdgeStyle -> Blue]}] $\endgroup$ Commented Aug 19, 2015 at 20:47
  • $\begingroup$ Hmm, is there a way around this sacrifice? :D $\endgroup$
    – user32497
    Commented Aug 19, 2015 at 21:31
  • $\begingroup$ I'm no expert of graph theory and its representation in Mathematica, but it seems to me that you are trying to specify two colors for the same edge of that graph, not for two different ones. David's suggestion works because now the graph has two different edges, one directed, and one undirected. $\endgroup$
    – MarcoB
    Commented Aug 19, 2015 at 21:34
  • $\begingroup$ duplicate: Graph - Coloring parallel edges individually $\endgroup$
    – kglr
    Commented Oct 3, 2018 at 22:43

2 Answers 2


Another trick you can do:

Graph[Join[Table[1 -> 2, {10}], Table[2 -> 3, {5}], 
  Table[3 -> 1, {5}]],
 EdgeShapeFunction -> {1 \[DirectedEdge] 
     2 -> (a = 0; {a++; ColorData[35, "ColorList"][[a]],
       Arrow[#]} &), 
   2 \[DirectedEdge] 
     3 -> (b = 0; {b++; ColorData[55, "ColorList"][[b]],
       Arrow[#]} &), 
   3 \[DirectedEdge] 1 -> (c = 0; {c++; ColorData[5, "ColorList"][[c]],
       Arrow[#]} &)}]

enter image description here

  • $\begingroup$ halmir's solution preserves the class of edge so that appropriate graph analysis functions work, e.g., VertexInDegree[g] yields $\{5, 10, 5\}$. +1. $\endgroup$ Commented Aug 20, 2015 at 21:23

The trick is to render both a directed and an undirected edge with the same arrow EdgeShapeFunction. Alas, the full graph representation will retain the different classes of edge, so functions such as FindKClan, VertexOutDegree, VertexInDegree, and others that distinguish between different classes of edge will give incorrect answers.

  Graph[{1, 2}, 
     {Property[1 \[DirectedEdge] 2, EdgeStyle -> Red], 
      Property[1 <-> 2, EdgeStyle -> Blue]}, 
    EdgeShapeFunction -> (Arrow[#] &)]

enter image description here

Because there are only two classes of edge (directed and undirected), following this approach also implies that one can have at most two edges between a given pair of vertexes.

You can kludge together a graph representation that appears as if three (or more) edges join two vertexes by forcing different vertexes to lie in the same position, through VertexCoordinates:

Graph[{1, 2, 3}, {Property[1 \[DirectedEdge] 2, EdgeStyle -> Red], 
  Property[1 <-> 2, EdgeStyle -> Blue], 
  Property[1 <-> 3, EdgeStyle -> Green]}, 
 EdgeShapeFunction -> (Arrow[#] &), 
 VertexCoordinates -> {{0, 0}, {1, 0}, {1, 0}}]

enter image description here

  • $\begingroup$ Although the funny-looking (Arrow[#]&) works, I think that more properly you would want (Arrow[#1]&) for your EdgeShapeFunction, to reming the reader that a custom edge function is passed a sequence of two arguments: 1) a list of points describing the edge; 2) the edge denomination itself. Arrow needs only the first one. I think this is also the reason why simply using Arrow doesn't work: the edge definition would be interpreted as an arrow setback amount, which is expected to be a number. $\endgroup$
    – MarcoB
    Commented Aug 19, 2015 at 22:21
  • $\begingroup$ I had originally defined an EdgeShapeFunction of the form ef[#, ___] and called it within Graph, as the two-argument approach would seem to require. I found indeed that both (Arrow[#]&) and (Arrow[#1]&) worked, but don't know why the former does. $\endgroup$ Commented Aug 19, 2015 at 22:24
  • $\begingroup$ I think (Arrow[#]&) works because # always represents only the first argument provided to the function, i.e. it is automatically equivalent to #1, so that call discards the second argument passed to Arrow by EdgeShapeFunction. In other words, (Arrow[#]&) is equivalent to Arrow[#1]&; both are different from (Arrow) alone, which would behave as (Arrow[__]&), i.e. SlotSequence[]. That's why I suggested using #1 rather than #: although they are perfectly equivalent, the latter makes the intended behavior more explicit. $\endgroup$
    – MarcoB
    Commented Aug 19, 2015 at 22:32
  • $\begingroup$ @becko Did you not see my three-edge solution posted yesterday? $\endgroup$ Commented Aug 20, 2015 at 20:12
  • $\begingroup$ I see it now. This edit was not visible to me before. Deleting comments. $\endgroup$
    – a06e
    Commented Aug 20, 2015 at 20:22

Your Answer

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