# Label multiple edges between same vertices

I have a simple graph with multiple edges between two vertices, say:

Graph[{
Labeled[a -> b, "A"],
Labeled[a -> b, "B"]
}]


Unfortunately, Mathematica labels both edges "A".

How can I label both distinct edges? They really both need to point to the same vertex.

Update 3: Styling and labeling edges individually can now be more conveniently done using new-in-version-12.1 function EdgeTaggedGraph:

labels = {"A", "B", "C", "D", "E", "F"};
edges = {a -> b, a -> b, a -> b, a -> b, a -> e, e -> b};
styles = ColorData[97] /@ Range[6];

labelededges =  MapThread[Style[Labeled[#, #2], #3] &, {edges, labels, styles}] ;

EdgeTaggedGraph[labelededges, EdgeLabels -> "Name",
ImageSize -> Medium, EdgeLabelStyle -> 16]


Update 2: Dealing with the issue raised by @Kuba in the comments:

Using the function LineScaledCoordinate from the GraphUtilities package to place the text labels:

Needs["GraphUtilities"]

labels ={"A", "B", "C", "D", "E", "F"};

Graph[{a -> b, a -> b, a -> b, a -> b, a -> e, e -> b},
EdgeShapeFunction ->
({Text[Last[labels = RotateLeft[labels]], LineScaledCoordinate[#, 0.5]], Arrow@#} &),
VertexLabels->"Name"]


Update: Using EdgeShapeFunction:

labels = Reverse @ {"A","B","C","D"};
i = 1;
Graph[{a -> b, a -> b, a -> b, a -> b},
EdgeShapeFunction- > ({Text[labels[[i++]], Mean @ #],Arrow @ #}&)]


Simplest method to convert a Graph g to Graphics is to use Show[g] (see this answer by @becko).

We can post-process Show[g] to modify the Text primitives:

Show[Graph[{Labeled[a->b,"A"],Labeled[a->b,"B"]}]]/.
Text["A",{x_,y_/; (y<0.)},z___]:>Text["B",{x,y},z]


Or, we can construct a Graph with modified edge directions (and correct labels) and post-process it to change the edge directions:

Show[Graph[{Labeled[a->b,"A"], Labeled[b->a,"B"]}]]/.
BezierCurve[{{-1.,0.},m__,y_}]:>BezierCurve[{{1.,0.},m,{-1.,0.}}]
(* same picture *)

• It may not be the best idea for more crowded places: labels = Reverse@{"A", "B", "C", "D", "E", "F"}; i = 1; Graph[{a -> b, a -> b, a -> b, a -> b, a -> e, e -> b}, EdgeShapeFunction -> ({Text[labels[[i++]], Mean@#], Arrow@#} &)]. – Kuba Jan 19 '15 at 10:55
• btw. for V9 something like Graph[{a -> b, a -> b}] yells that Mixed graphs and multigraphs are not supported. So in V10 it should work correctly with labeling, isn't it bug then? – Kuba Jan 19 '15 at 10:57
• @Kuba, regarding "isnt it a bug i agree. An re "crowded places", i can't think of a quick fix for now. – kglr Jan 19 '15 at 11:15
• Thank you very much. That's a bit sad for me - as I'm constructing graphs with lots of vertices where the manual replacement might be a bit cumbersome. But thanks for the many ways you showed! – Thomas Fankhauser Jan 21 '15 at 16:08
• +1 This is a clever answer. My only problem is that now the Graph object is not self-contained: i must be reset before any extra call to the graph. Such a pity that internal edge functions use ReplaceAll so that one cannot identifiy different instances of the same edge... – István Zachar Nov 14 '15 at 14:41

This ****, and so does my answer, but if it works it's not stupid, right? :)

p = Graph[{Labeled[a -> b, "A"], Labeled[a -> b, "B"]}];

grp = GraphComputationGraphConvertToGraphics[p];

ReplacePart[grp, Position[grp, "A"][[1]] -> "B"]


• Thank you! I'll have to try if this also works with Tooltip - as this is what I actually need with the number of edges I'm targeting. – Thomas Fankhauser Jan 21 '15 at 16:09
• @ThomasFankhauser it should but you have to locate and replace whole tooltip. – Kuba Jan 21 '15 at 16:30

It appears that in Mathematica 10.0.2 Graph does not natively support this by way of wrappers such as Labeled. Note that each of these wrappers is converted to a canonical form that seems to support only one directive for each edge:

Table[
InputForm @ Graph[{fn[a -> b, "A"], fn[a -> b, "B"]}],
{fn, {Labeled, Annotation, Tooltip, Style, Hyperlink, EventHandler, Button}}
] // Column

Graph[{a, b}, {DirectedEdge[a, b], DirectedEdge[a, b]},
{EdgeLabels -> {DirectedEdge[a, b] -> "A"}}]

Graph[{a, b}, {DirectedEdge[a, b], DirectedEdge[a, b]},
{Properties -> {DirectedEdge[a, b] -> {Annotation -> "A"}}}]

Graph[{a, b}, {DirectedEdge[a, b], DirectedEdge[a, b]},
{Properties -> {DirectedEdge[a, b] -> {Tooltip -> "A"}}}]

Graph[{a, b}, {DirectedEdge[a, b], DirectedEdge[a, b]},
{EdgeStyle -> {DirectedEdge[a, b] -> {"A"}}}]

Graph[{a, b}, {DirectedEdge[a, b], DirectedEdge[a, b]},
{Properties -> {DirectedEdge[a, b] -> {Hyperlink -> "A"}}}]

Graph[{a, b}, {DirectedEdge[a, b], DirectedEdge[a, b]},
{Properties -> {DirectedEdge[a, b] -> {EventHandler -> "A"}}}]

Graph[{a, b}, {DirectedEdge[a, b], DirectedEdge[a, b]},
{Properties -> {DirectedEdge[a, b] -> {Button -> Unevaluated["B"]}}}]

• The problem is not only in wrappers. Graph[{a -> b, a -> b}, EdgeWeight -> {1, 2}, EdgeLabels -> "EdgeWeight"] is displayed incorrectly despite the correct InputForm. – ybeltukov Jan 19 '15 at 13:47

If your application allows it, one workaround to Mathematica's inability to handle multigraphs in Graph objects is simply to allow edge labels to be lists of multiple labels. So, for example, the original graph could be represented via either of these forms:

Graph[{Labeled[a -> b, {"A", "B"}]}]

Graph[{Labeled[DirectedEdge[a, b], {"A", "B"}]}]


In representing finite state machines, this has served me quite well. In addition, I don’t use the Graph object to store the information about my machines, since Mathematica likes to “own” the data contained in those objects. So my approach is to create a separate FiniteStateMachine data structure in which I can define my own rules (and yes: multigraphs are supported there). I only need to produce Graph objects 'on the fly' when I need to see what a FiniteStateMachine looks like. This also lets me skirt around the differences in how Graph objects are handled in MMA 9, 10 and 11, all of which I want my code to support.

I also experimented with GraphPlot, since it does support multigraphs. However, it only works with Rule-based edges. If you use DirectedEdge to define the edges, it won’t work. Furthermore, the results are far less graphically appealing. So, for example, the original multigraph could be represented this way using GraphPlot:

GraphPlot[
{{a -> b, "A"}, {a -> b, "B"}},
DirectedEdges -> True, VertexLabeling -> True
]


The new 12.1 EdgeTaggedGraph feels like a mess to be honest. The tags are not labels, so they don't visualize in the graph. In the example above you've hacked Labeled to do the labeling instead. The problem with that is that it seems to be incompatible with our ability to append or modify graphs. For instance, if one wanted to add a new edge with a new label with EdgeAdd, one can not use Labeled. The other way of showing labels, EdgeLabel, isn't compatible with EdgeTaggedGraph.

EdgeTaggedGraph[{A -> B, A -> B, A -> B},
EdgeLabels -> {(A -> B) -> 1, (A -> B) -> 2, (A -> B) -> 3}]


What is even more crazy is, if you look in the documentation for EdgeTaggedGraph, they use EdgeLabels in a 100 examples for EdgeTaggedGraph that are useless because the graphs have no duplicated edges. It looks ass if someone just copied examples from the documentation of Graph.

• I, too, think the documentation examples were just copied from Graph. – m_goldberg Sep 18 '20 at 1:35