If there is a series of rules from which a TreePlot/LayeredGraphPlot is made:

{D->C, C->B, B->A}

And a new vertex is added that is technically the same as an existing vertex, but has an alternate name or alias, for instance, "Q", which is the same as "A", and we create a new rule:


Is there a way in TreePlot/LayeredGraphPlot to combine Q and A into a single vertex with two names? It seems that it should be possible to have aliases in TreePlot/LayeredGraphPlot that allow a vertices to point to other vertices that have more than 1 name. Here is a graphical example of what I mean:

enter image description here

EDIT: An alternative way of viewing this question is merging 2 distinct trees but preserving all names and aliases of the linking vertex.

  • $\begingroup$ I think a few more examples might help. I am interested, but I don't understand your needs well enough to attempt an answer. $\endgroup$ – Mr.Wizard Feb 2 '15 at 3:02
  • $\begingroup$ @Mr.Wizard I guess what I am really asking is whether or not a vertex within a plot can have two simultaneous values, in the above case "A" and "Q". Therefore, given the rules lists I mention in the post, rather than generating two different plots, combining them into one plot, in which the vertex in question has two names rather than one. I'll update the post to change "node" to "vertex". Also, I see this is something that could apply to LayeredGraphPlot, among others. $\endgroup$ – iwantmyphd Jun 29 '15 at 15:00
treea = {D -> C, C -> B, B -> A};

treeb = {B -> Q};

Combine two trees based on starting vertex:

combined = 
  Flatten[GatherBy[Join[treea, treeb], First] /. 
    x : {a_Rule, b__} :> a[[1]] -> Row[Riffle[x[[All, 2]], "/"]]]

{D -> C, C -> B, B -> Row[{A, "/", Q}]}


vshape[c : {xc_, yc_}, name_, {w_, h_}] := {
  Hue[0.6, 0.77, 0.8], 
  EdgeForm[{Hue[0.6, 0.77, 0.22], Thickness[.05]}], 
  Disk[c, {3 w, 2 h}]}

res = Graph[#, VertexShapeFunction -> vshape, 
     PerformanceGoal -> "Quality", 
     VertexLabels -> Placed["Name", Center], 
     VertexLabelStyle -> Directive[13, White], 
     EdgeStyle -> Hue[0.6, 0.77, 0.8], 
     GraphLayout -> {"LayeredDigraphEmbedding", 
       "Orientation" -> Bottom}, VertexSize -> .2, 
     ImageSize -> 50] & /@ {treea, treeb, combined};

Row[{res[[1]], Spacer[50], "+", Spacer[50], res[[2]], Spacer[50], 
  "->", Spacer[50], res[[3]]}]

enter image description here

  • $\begingroup$ How would you handle treeb = {Q -> B} instead? $\endgroup$ – Carl Woll Aug 17 '17 at 18:44
  • 1
    $\begingroup$ @Carl Woll you could use the similar technique: Flatten[GatherBy[combined, Last] /. x : {a_Rule, b__} :> Row[Riffle[x[[All, 1]], "/"]] -> a[[2]]] $\endgroup$ – halmir Aug 17 '17 at 19:02
  • $\begingroup$ Or treeb = {Q->B, A->R}? Or treeb = {Q<->B, A->R}. My point is that using GatherBy instead of graph operations like VertexContract or VertexReplace seems a lot more complicated. $\endgroup$ – Carl Woll Aug 17 '17 at 19:37
  • $\begingroup$ @Carl Woll yes, can be. But to use VertexContract or VertexReplace you need to find out what vertices you want to operate anyhow. $\endgroup$ – halmir Aug 17 '17 at 19:51
edges1 = {"D" -> "C", "C" -> "B", "B" -> "A"};
edges2 = {"B" -> "Q"};

options = {GraphLayout -> {"LayeredEmbedding", "RootVertex" -> "D", 
      "Orientation" -> Bottom}, 
   EdgeShapeFunction -> ({Thick, Arrowheads[.1], Arrow[#1, {0, .1}]} &), 
   VertexLabels -> Placed["Name", Center], VertexSize -> Medium};

g1 = Graph[edges1];
g2 = Graph[edges2];
g3 = GraphUnion[g1, g2, ## & @@ options, ImageSize -> Medium];
g4 = SetProperty[
   VertexContract[g3, {"A", "Q"}], {VertexSize -> {"A" -> Medium}, 
    VertexLabels -> {"A" -> Placed["A/Q", Center]}, (options /. 
      Arrowheads[_] :> Arrowheads[.5]), ImageSize -> Medium}];

Row[{g3, g4}, Spacer[20]]

enter image description here


An alternative to @kglr's answer is to use VertexReplace. Your original Graph:

g = Graph[
    {"D"->"C", "C"->"B", "B"->"A", "B"->"Q"},
    GraphLayout -> {"LayeredEmbedding", "RootVertex" -> "D", "Orientation" -> Left},

enter image description here

Use VertexReplace to identify both "A" and "Q" as "A/Q":

new = VertexReplace[g, Thread[{"A","Q"}->"A/Q"]];

And view the result:

Graph[new, VertexLabels->"Name"]

enter image description here

{"D", "C", "B", "A/Q"}


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.