25
$\begingroup$

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". Graph with multiple edges to same vertices

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

Thanks for your help!

$\endgroup$
0

6 Answers 6

24
$\begingroup$

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]

enter image description here

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"] 

enter image description here

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 @ #}&)]

enter image description here


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]

enter image description here

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 *)
$\endgroup$
5
  • $\begingroup$ 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@#} &)]. $\endgroup$
    – Kuba
    Commented Jan 19, 2015 at 10:55
  • $\begingroup$ 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? $\endgroup$
    – Kuba
    Commented Jan 19, 2015 at 10:57
  • $\begingroup$ @Kuba, regarding "isnt it a bug i agree. An re "crowded places", i can't think of a quick fix for now. $\endgroup$
    – kglr
    Commented Jan 19, 2015 at 11:15
  • $\begingroup$ 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! $\endgroup$ Commented Jan 21, 2015 at 16:08
  • 1
    $\begingroup$ +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... $\endgroup$ Commented Nov 14, 2015 at 14:41
9
$\begingroup$

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 = GraphComputation`GraphConvertToGraphics[p];

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

enter image description here

$\endgroup$
2
  • $\begingroup$ 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. $\endgroup$ Commented Jan 21, 2015 at 16:09
  • 1
    $\begingroup$ @ThomasFankhauser it should but you have to locate and replace whole tooltip. $\endgroup$
    – Kuba
    Commented Jan 21, 2015 at 16:30
4
$\begingroup$

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"]}}}]
$\endgroup$
1
  • 5
    $\begingroup$ The problem is not only in wrappers. Graph[{a -> b, a -> b}, EdgeWeight -> {1, 2}, EdgeLabels -> "EdgeWeight"] is displayed incorrectly despite the correct InputForm. $\endgroup$
    – ybeltukov
    Commented Jan 19, 2015 at 13:47
4
$\begingroup$

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
]
$\endgroup$
4
$\begingroup$

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.

$\endgroup$
1
  • $\begingroup$ I, too, think the documentation examples were just copied from Graph. $\endgroup$
    – m_goldberg
    Commented Sep 18, 2020 at 1:35
4
$\begingroup$

You can use the third argument of DirectedEdge, together with EdgeLabels -> "EdgeTag":

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

Graph

$\endgroup$

Your Answer

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

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