16
$\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$
15
$\begingroup$

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"};
i = 1; 
Graph[{a -> b, a -> b, a -> b, a -> b, a -> e, e -> b},  
EdgeShapeFunction -> ({Text[labels[[i++]], 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$
  • $\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 Jan 19 '15 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 Jan 19 '15 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 Jan 19 '15 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$ – Thomas Fankhauser Jan 21 '15 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$ – István Zachar Nov 14 '15 at 14:41
6
$\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$
  • $\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$ – Thomas Fankhauser Jan 21 '15 at 16:09
  • 1
    $\begingroup$ @ThomasFankhauser it should but you have to locate and replace whole tooltip. $\endgroup$ – Kuba Jan 21 '15 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$
  • 4
    $\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 Jan 19 '15 at 13:47
2
$\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$

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.