Elegant implementation of factorial tree graph











up vote
22
down vote

favorite
8












Consider the tree graph used in part of my solution to this question:



Factorial tree graph



Each level $i$ has $i!$ nodes, and the branching ratio is $i+1$:



I kludged together code to generate this graph (with code better left un-reproduced).



Is there an elegant method for generating such a tree graph for arbitrary number of levels?



A three-dimensional layout might look like this:



enter image description here



but I'd prefer a better embedding at the higher-$n$ levels, closer to this:



enter image description here










share|improve this question
























  • @J42161217 Fixed. Thanks.
    – David G. Stork
    Nov 30 at 21:29















up vote
22
down vote

favorite
8












Consider the tree graph used in part of my solution to this question:



Factorial tree graph



Each level $i$ has $i!$ nodes, and the branching ratio is $i+1$:



I kludged together code to generate this graph (with code better left un-reproduced).



Is there an elegant method for generating such a tree graph for arbitrary number of levels?



A three-dimensional layout might look like this:



enter image description here



but I'd prefer a better embedding at the higher-$n$ levels, closer to this:



enter image description here










share|improve this question
























  • @J42161217 Fixed. Thanks.
    – David G. Stork
    Nov 30 at 21:29













up vote
22
down vote

favorite
8









up vote
22
down vote

favorite
8






8





Consider the tree graph used in part of my solution to this question:



Factorial tree graph



Each level $i$ has $i!$ nodes, and the branching ratio is $i+1$:



I kludged together code to generate this graph (with code better left un-reproduced).



Is there an elegant method for generating such a tree graph for arbitrary number of levels?



A three-dimensional layout might look like this:



enter image description here



but I'd prefer a better embedding at the higher-$n$ levels, closer to this:



enter image description here










share|improve this question















Consider the tree graph used in part of my solution to this question:



Factorial tree graph



Each level $i$ has $i!$ nodes, and the branching ratio is $i+1$:



I kludged together code to generate this graph (with code better left un-reproduced).



Is there an elegant method for generating such a tree graph for arbitrary number of levels?



A three-dimensional layout might look like this:



enter image description here



but I'd prefer a better embedding at the higher-$n$ levels, closer to this:



enter image description here







graphs-and-networks trees






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 1 at 1:17

























asked Nov 30 at 21:17









David G. Stork

22.6k21950




22.6k21950












  • @J42161217 Fixed. Thanks.
    – David G. Stork
    Nov 30 at 21:29


















  • @J42161217 Fixed. Thanks.
    – David G. Stork
    Nov 30 at 21:29
















@J42161217 Fixed. Thanks.
– David G. Stork
Nov 30 at 21:29




@J42161217 Fixed. Thanks.
– David G. Stork
Nov 30 at 21:29










4 Answers
4






active

oldest

votes

















up vote
17
down vote



accepted










here is my elegant implementation



l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]];
T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]];

T@3


which returns



enter image description here



but if your Mathematica version doesn't support TakeList here is another way



s[x_] := Sum[k!,{k,x}];
z[y_] := Partition[Range[s@y+1,s[y+1]],1+y];
v[n_] := Table[{Flatten[z[n-1]][[i]]->z[n][[i,j]]},{i,n!},{j,n+1}];
tree[t_] := Graph[Flatten[Array[v@#&,t],3]];

tree@3


enter image description here



tree@6    


enter image description here






share|improve this answer























  • Very nice (+1). I would add only Embedding -> "RadialEmbedding" to your code.
    – David G. Stork
    Nov 30 at 22:38










  • @DavidG.Stork updated with a new approach
    – J42161217
    Dec 1 at 1:16






  • 1




    Now THAT is elegant! (accept) Thanks so much! I'm now working on getting a clear three-dimensional embedding (see revised question).
    – David G. Stork
    Dec 1 at 1:19


















up vote
23
down vote













Update 2: a more streamlined version for 2D graphs:



ClearAll[g]
g = GraphComputation`ExpressionGraph[ConstantArray[x, #], VertexLabels -> None] &;


Examples:



g[Range[2, 4]]


enter image description here



SetProperty[g[{3, 1, 3, 1, 2, 1, 4}],
{GraphLayout -> "RadialEmbedding", EdgeShapeFunction -> "Line"}]


enter image description here



Original answer:



ClearAll[f]
f[g_: Graph][n_List, o : OptionsPattern] := g[UndirectedEdge @@@ EdgeList@
GraphComputation`ExpressionGraph[ConstantArray[x, n]],
o, GraphLayout -> {"BalloonEmbedding"}, ImageSize -> Large]
f[g_: Graph][n_Integer, o : OptionsPattern] := f[g][Range[n], o]


Examples:



f[6]


enter image description here



f[6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



g1 = f[Graph3D][6]


enter image description here



g2 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



Use a list for number of vertices on each layer as the argument:



f[{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}]


enter image description here



Update: ... to take the Graph3D and somehow improve the layout on the high-n layers: There seems to be lots of wasted space.



One way to change the box ratios without distorting the vertex shapes is to modify the VertexCoordinates using ScalingTransform:



SetProperty[g1, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g1]]


enter image description here



SetProperty[g2, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g2]]


enter image description here



Or add the suboption "LayerSizeFunction" in "RadialEmbedding":



g3 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}];
SetProperty[g3, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g3]]


enter image description here



SetProperty[#, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@#]] &@
f[Graph3D][{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction"->(#&)}]


enter image description here






share|improve this answer























  • I knew you'd come up with something powerful and elegant. My only suggestion for improvement would be to take the Graph3D and somehow improve the layout on the high-$n$ layers: There seems to be lots of wasted space. Other than that... great! (+1)
    – David G. Stork
    Dec 1 at 6:33










  • Just wow. That's hardly to top in terms of elegance.
    – Henrik Schumacher
    Dec 1 at 8:52










  • @David, please see the update.
    – kglr
    Dec 1 at 16:03






  • 2




    @HenrikSchumacher: l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]]; T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]]; seems incredibly efficient, clever and... yes.. "elegant." All other implementations include more code or are less elegant (in my humble opinion). About 1/6 the code in my (non-optimized) implementation.
    – David G. Stork
    Dec 1 at 17:15








  • 1




    I've joined the community just to upvote this answer and those wonderful graphs.
    – Eric Duminil
    yesterday




















up vote
18
down vote













IGraph/M already has this built-in as IGSymmetricTree. You can specify the number of branches at each level.



enter image description here



IGSymmetricTree[
Range[2, 4],
DirectedEdges -> True,
GraphLayout -> "LayeredEmbedding"
]


enter image description here



The implementation is mostly in C (not Mathematica) and not from igraph this time. This is simply easier to implement procedurally, for which C is a good fit. This is why I did not do it in pure WL.



Here's another structure, with a different number of branches at each level.



IGSymmetricTree[{5, 4, 3, 2}]


enter image description here






share|improve this answer























  • This is precisely the functionality I need (thanks... +1), but I was hoping for the full code to be available, and (hopefully) clever and elegant.
    – David G. Stork
    Nov 30 at 22:01










  • @DavidG.Stork The full code is available (I linked to part of it), it is just not fully in Mathematica.
    – Szabolcs
    Nov 30 at 22:02












  • Thanks, but I need fully Mathematica code. Perhaps WRI will add this valuable functionality to its next release.
    – David G. Stork
    Nov 30 at 22:04






  • 4




    @David I accept that you want WL code, but could you explain why, just to satisfy my interest? People often refuse to use my package "because it's not built in". I do not understand why that is an issue. The package is polished, more robust than most, easy to install, and easy to uninstall without leaving traces. Other than for using the function in the cloud or in a FreeCDF (which is on the way out...) I do not see why having this functionality in a package (instead of built in) would be a problem.
    – Szabolcs
    Nov 30 at 22:07








  • 1




    Sure. I appreciate your wonderful coding efforts. However, in many cases I make CDF figures for class presentation and it is simpler to generate such figures without linking to libraries (especially $C$ or $C++$ libraries). Also, I understand and can thus modify Mathematica code better. Why not write all the code in Mathematica?
    – David G. Stork
    Nov 30 at 22:18


















up vote
12
down vote













I don't know if you find this elegant. But I give it a try.



maxdepth = 5;
Graph[
Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, (i + 1)]],
Join[{{1}}, Partition[Accumulate[Range[maxdepth - 1]!], 2, 1] + ConstantArray[{1, 0}, maxdepth - 2]]
],
Range[2, Total[Range[maxdepth]!]]
}],
DirectedEdges -> True,
GraphLayout -> "BalloonEmbedding"
]


enter image description here



Edit



Out of curiosity, I adapted the algorithm above to produce also other symmetric trees.



SymmetricTree[branchlist_?(VectorQ[#, IntegerQ] &)] := 
Module[{levelnodecounts},
levelnodecounts = FoldList[#1 #2 &, 1, branchlist];
Graph[Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, branchlist[[i[[1]]]]]],
Join[
{{1}},
Partition[Accumulate[Most[levelnodecounts]], 2, 1] + ConstantArray[{1, 0}, Length[branchlist] - 1]
]
],
Range[2, 1 + Total[Rest[levelnodecounts]]]}],
DirectedEdges -> True
]
]


Regarding speed, it seems to be on par with IGSymmetricTree. Of course, I cannot provide such a detailed user interface as Szabolcs so I would suggest to use IGraphM whenever possible.



Edit 2



Adapting my (slow) code for fractal trees, here is another way to embedd the tree:



BoccoliEmbedding[branchlist_] := 
Module[{data0, data, θ, stem, thickness, s1, s2, f, F},
θ = Pi/4.;
s1 = 1/GoldenRatio // N;
s2 = 1/GoldenRatio // N;
stem = {0., 0., 1.};
thickness = 0.15;
data0 = {Join[
{{0., 0., 0.}},
{stem},
{{thickness, 1., 0.}},
Table[
RotationMatrix[2. k Pi/branchlist[[1]], {0, 0, 1}].{Cos[θ], 0.,Sin[θ]},
{k, 0, branchlist[[1]] - 1}]
]
};
f = {U, n} [Function] Table[
Join[
{U[[1]] + U[[2]]},
{U[[i]]},
{s2 U[[3]]},
Dot[
s1 Table[RotationMatrix[2. Pi j/n, U[[2]]].U[[i]], {j, 0, n - 1}],
RotationMatrix[{U[[i]], U[[2]]}]
]
],
{i, 4, Length[U]}];
F = {data, n} [Function] Join @@ (f[#, n] & /@ data);
data = Join @@ FoldList[F, data0, Join[Rest[branchlist], {1}]];
data[[All, 1]] + data[[All, 2]]
];


And this is how we apply it:



b = Range[2, 7];
plot = Graph[
EdgeList[SymmetricTree[b]],
VertexCoordinates -> BoccoliEmbedding[b]
]


enter image description here






share|improve this answer



















  • 1




    Elegant enough! (+1) GraphLayout -> "LayeredEmbedding" works fine for $4$ levels, but not $5$, so your layout choice is probably one of the best. Before I accept, let me wait to see if someone is clever with specifying vertex order or other approach.
    – David G. Stork
    Nov 30 at 21:59










  • Thanks for the wonderful coding... extremely helpful. I know it wasn't part of my original question, but I've been working on a three-dimensional graph embedding, using VertexCoordinates, in which each level $i$ is at a different (stacked) height and the vertices at each height are packed efficiently. This would be a very cool graphic, and interpretable for $n=7$ or possibly higher!
    – David G. Stork
    Dec 1 at 0:39













Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["$", "$"], ["\\(","\\)"]]);
});
});
}, "mathjax-editing");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "387"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f187060%2felegant-implementation-of-factorial-tree-graph%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























4 Answers
4






active

oldest

votes








4 Answers
4






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
17
down vote



accepted










here is my elegant implementation



l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]];
T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]];

T@3


which returns



enter image description here



but if your Mathematica version doesn't support TakeList here is another way



s[x_] := Sum[k!,{k,x}];
z[y_] := Partition[Range[s@y+1,s[y+1]],1+y];
v[n_] := Table[{Flatten[z[n-1]][[i]]->z[n][[i,j]]},{i,n!},{j,n+1}];
tree[t_] := Graph[Flatten[Array[v@#&,t],3]];

tree@3


enter image description here



tree@6    


enter image description here






share|improve this answer























  • Very nice (+1). I would add only Embedding -> "RadialEmbedding" to your code.
    – David G. Stork
    Nov 30 at 22:38










  • @DavidG.Stork updated with a new approach
    – J42161217
    Dec 1 at 1:16






  • 1




    Now THAT is elegant! (accept) Thanks so much! I'm now working on getting a clear three-dimensional embedding (see revised question).
    – David G. Stork
    Dec 1 at 1:19















up vote
17
down vote



accepted










here is my elegant implementation



l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]];
T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]];

T@3


which returns



enter image description here



but if your Mathematica version doesn't support TakeList here is another way



s[x_] := Sum[k!,{k,x}];
z[y_] := Partition[Range[s@y+1,s[y+1]],1+y];
v[n_] := Table[{Flatten[z[n-1]][[i]]->z[n][[i,j]]},{i,n!},{j,n+1}];
tree[t_] := Graph[Flatten[Array[v@#&,t],3]];

tree@3


enter image description here



tree@6    


enter image description here






share|improve this answer























  • Very nice (+1). I would add only Embedding -> "RadialEmbedding" to your code.
    – David G. Stork
    Nov 30 at 22:38










  • @DavidG.Stork updated with a new approach
    – J42161217
    Dec 1 at 1:16






  • 1




    Now THAT is elegant! (accept) Thanks so much! I'm now working on getting a clear three-dimensional embedding (see revised question).
    – David G. Stork
    Dec 1 at 1:19













up vote
17
down vote



accepted







up vote
17
down vote



accepted






here is my elegant implementation



l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]];
T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]];

T@3


which returns



enter image description here



but if your Mathematica version doesn't support TakeList here is another way



s[x_] := Sum[k!,{k,x}];
z[y_] := Partition[Range[s@y+1,s[y+1]],1+y];
v[n_] := Table[{Flatten[z[n-1]][[i]]->z[n][[i,j]]},{i,n!},{j,n+1}];
tree[t_] := Graph[Flatten[Array[v@#&,t],3]];

tree@3


enter image description here



tree@6    


enter image description here






share|improve this answer














here is my elegant implementation



l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]];
T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]];

T@3


which returns



enter image description here



but if your Mathematica version doesn't support TakeList here is another way



s[x_] := Sum[k!,{k,x}];
z[y_] := Partition[Range[s@y+1,s[y+1]],1+y];
v[n_] := Table[{Flatten[z[n-1]][[i]]->z[n][[i,j]]},{i,n!},{j,n+1}];
tree[t_] := Graph[Flatten[Array[v@#&,t],3]];

tree@3


enter image description here



tree@6    


enter image description here







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 1 at 1:30

























answered Nov 30 at 22:29









J42161217

3,597220




3,597220












  • Very nice (+1). I would add only Embedding -> "RadialEmbedding" to your code.
    – David G. Stork
    Nov 30 at 22:38










  • @DavidG.Stork updated with a new approach
    – J42161217
    Dec 1 at 1:16






  • 1




    Now THAT is elegant! (accept) Thanks so much! I'm now working on getting a clear three-dimensional embedding (see revised question).
    – David G. Stork
    Dec 1 at 1:19


















  • Very nice (+1). I would add only Embedding -> "RadialEmbedding" to your code.
    – David G. Stork
    Nov 30 at 22:38










  • @DavidG.Stork updated with a new approach
    – J42161217
    Dec 1 at 1:16






  • 1




    Now THAT is elegant! (accept) Thanks so much! I'm now working on getting a clear three-dimensional embedding (see revised question).
    – David G. Stork
    Dec 1 at 1:19
















Very nice (+1). I would add only Embedding -> "RadialEmbedding" to your code.
– David G. Stork
Nov 30 at 22:38




Very nice (+1). I would add only Embedding -> "RadialEmbedding" to your code.
– David G. Stork
Nov 30 at 22:38












@DavidG.Stork updated with a new approach
– J42161217
Dec 1 at 1:16




@DavidG.Stork updated with a new approach
– J42161217
Dec 1 at 1:16




1




1




Now THAT is elegant! (accept) Thanks so much! I'm now working on getting a clear three-dimensional embedding (see revised question).
– David G. Stork
Dec 1 at 1:19




Now THAT is elegant! (accept) Thanks so much! I'm now working on getting a clear three-dimensional embedding (see revised question).
– David G. Stork
Dec 1 at 1:19










up vote
23
down vote













Update 2: a more streamlined version for 2D graphs:



ClearAll[g]
g = GraphComputation`ExpressionGraph[ConstantArray[x, #], VertexLabels -> None] &;


Examples:



g[Range[2, 4]]


enter image description here



SetProperty[g[{3, 1, 3, 1, 2, 1, 4}],
{GraphLayout -> "RadialEmbedding", EdgeShapeFunction -> "Line"}]


enter image description here



Original answer:



ClearAll[f]
f[g_: Graph][n_List, o : OptionsPattern] := g[UndirectedEdge @@@ EdgeList@
GraphComputation`ExpressionGraph[ConstantArray[x, n]],
o, GraphLayout -> {"BalloonEmbedding"}, ImageSize -> Large]
f[g_: Graph][n_Integer, o : OptionsPattern] := f[g][Range[n], o]


Examples:



f[6]


enter image description here



f[6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



g1 = f[Graph3D][6]


enter image description here



g2 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



Use a list for number of vertices on each layer as the argument:



f[{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}]


enter image description here



Update: ... to take the Graph3D and somehow improve the layout on the high-n layers: There seems to be lots of wasted space.



One way to change the box ratios without distorting the vertex shapes is to modify the VertexCoordinates using ScalingTransform:



SetProperty[g1, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g1]]


enter image description here



SetProperty[g2, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g2]]


enter image description here



Or add the suboption "LayerSizeFunction" in "RadialEmbedding":



g3 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}];
SetProperty[g3, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g3]]


enter image description here



SetProperty[#, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@#]] &@
f[Graph3D][{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction"->(#&)}]


enter image description here






share|improve this answer























  • I knew you'd come up with something powerful and elegant. My only suggestion for improvement would be to take the Graph3D and somehow improve the layout on the high-$n$ layers: There seems to be lots of wasted space. Other than that... great! (+1)
    – David G. Stork
    Dec 1 at 6:33










  • Just wow. That's hardly to top in terms of elegance.
    – Henrik Schumacher
    Dec 1 at 8:52










  • @David, please see the update.
    – kglr
    Dec 1 at 16:03






  • 2




    @HenrikSchumacher: l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]]; T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]]; seems incredibly efficient, clever and... yes.. "elegant." All other implementations include more code or are less elegant (in my humble opinion). About 1/6 the code in my (non-optimized) implementation.
    – David G. Stork
    Dec 1 at 17:15








  • 1




    I've joined the community just to upvote this answer and those wonderful graphs.
    – Eric Duminil
    yesterday

















up vote
23
down vote













Update 2: a more streamlined version for 2D graphs:



ClearAll[g]
g = GraphComputation`ExpressionGraph[ConstantArray[x, #], VertexLabels -> None] &;


Examples:



g[Range[2, 4]]


enter image description here



SetProperty[g[{3, 1, 3, 1, 2, 1, 4}],
{GraphLayout -> "RadialEmbedding", EdgeShapeFunction -> "Line"}]


enter image description here



Original answer:



ClearAll[f]
f[g_: Graph][n_List, o : OptionsPattern] := g[UndirectedEdge @@@ EdgeList@
GraphComputation`ExpressionGraph[ConstantArray[x, n]],
o, GraphLayout -> {"BalloonEmbedding"}, ImageSize -> Large]
f[g_: Graph][n_Integer, o : OptionsPattern] := f[g][Range[n], o]


Examples:



f[6]


enter image description here



f[6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



g1 = f[Graph3D][6]


enter image description here



g2 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



Use a list for number of vertices on each layer as the argument:



f[{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}]


enter image description here



Update: ... to take the Graph3D and somehow improve the layout on the high-n layers: There seems to be lots of wasted space.



One way to change the box ratios without distorting the vertex shapes is to modify the VertexCoordinates using ScalingTransform:



SetProperty[g1, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g1]]


enter image description here



SetProperty[g2, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g2]]


enter image description here



Or add the suboption "LayerSizeFunction" in "RadialEmbedding":



g3 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}];
SetProperty[g3, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g3]]


enter image description here



SetProperty[#, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@#]] &@
f[Graph3D][{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction"->(#&)}]


enter image description here






share|improve this answer























  • I knew you'd come up with something powerful and elegant. My only suggestion for improvement would be to take the Graph3D and somehow improve the layout on the high-$n$ layers: There seems to be lots of wasted space. Other than that... great! (+1)
    – David G. Stork
    Dec 1 at 6:33










  • Just wow. That's hardly to top in terms of elegance.
    – Henrik Schumacher
    Dec 1 at 8:52










  • @David, please see the update.
    – kglr
    Dec 1 at 16:03






  • 2




    @HenrikSchumacher: l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]]; T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]]; seems incredibly efficient, clever and... yes.. "elegant." All other implementations include more code or are less elegant (in my humble opinion). About 1/6 the code in my (non-optimized) implementation.
    – David G. Stork
    Dec 1 at 17:15








  • 1




    I've joined the community just to upvote this answer and those wonderful graphs.
    – Eric Duminil
    yesterday















up vote
23
down vote










up vote
23
down vote









Update 2: a more streamlined version for 2D graphs:



ClearAll[g]
g = GraphComputation`ExpressionGraph[ConstantArray[x, #], VertexLabels -> None] &;


Examples:



g[Range[2, 4]]


enter image description here



SetProperty[g[{3, 1, 3, 1, 2, 1, 4}],
{GraphLayout -> "RadialEmbedding", EdgeShapeFunction -> "Line"}]


enter image description here



Original answer:



ClearAll[f]
f[g_: Graph][n_List, o : OptionsPattern] := g[UndirectedEdge @@@ EdgeList@
GraphComputation`ExpressionGraph[ConstantArray[x, n]],
o, GraphLayout -> {"BalloonEmbedding"}, ImageSize -> Large]
f[g_: Graph][n_Integer, o : OptionsPattern] := f[g][Range[n], o]


Examples:



f[6]


enter image description here



f[6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



g1 = f[Graph3D][6]


enter image description here



g2 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



Use a list for number of vertices on each layer as the argument:



f[{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}]


enter image description here



Update: ... to take the Graph3D and somehow improve the layout on the high-n layers: There seems to be lots of wasted space.



One way to change the box ratios without distorting the vertex shapes is to modify the VertexCoordinates using ScalingTransform:



SetProperty[g1, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g1]]


enter image description here



SetProperty[g2, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g2]]


enter image description here



Or add the suboption "LayerSizeFunction" in "RadialEmbedding":



g3 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}];
SetProperty[g3, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g3]]


enter image description here



SetProperty[#, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@#]] &@
f[Graph3D][{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction"->(#&)}]


enter image description here






share|improve this answer














Update 2: a more streamlined version for 2D graphs:



ClearAll[g]
g = GraphComputation`ExpressionGraph[ConstantArray[x, #], VertexLabels -> None] &;


Examples:



g[Range[2, 4]]


enter image description here



SetProperty[g[{3, 1, 3, 1, 2, 1, 4}],
{GraphLayout -> "RadialEmbedding", EdgeShapeFunction -> "Line"}]


enter image description here



Original answer:



ClearAll[f]
f[g_: Graph][n_List, o : OptionsPattern] := g[UndirectedEdge @@@ EdgeList@
GraphComputation`ExpressionGraph[ConstantArray[x, n]],
o, GraphLayout -> {"BalloonEmbedding"}, ImageSize -> Large]
f[g_: Graph][n_Integer, o : OptionsPattern] := f[g][Range[n], o]


Examples:



f[6]


enter image description here



f[6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



g1 = f[Graph3D][6]


enter image description here



g2 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding"}]


enter image description here



Use a list for number of vertices on each layer as the argument:



f[{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}]


enter image description here



Update: ... to take the Graph3D and somehow improve the layout on the high-n layers: There seems to be lots of wasted space.



One way to change the box ratios without distorting the vertex shapes is to modify the VertexCoordinates using ScalingTransform:



SetProperty[g1, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g1]]


enter image description here



SetProperty[g2, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g2]]


enter image description here



Or add the suboption "LayerSizeFunction" in "RadialEmbedding":



g3 = f[Graph3D][6, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction" -> (# &)}];
SetProperty[g3, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@g3]]


enter image description here



SetProperty[#, VertexCoordinates -> ScalingTransform[{1, 1, 3}][GraphEmbedding@#]] &@
f[Graph3D][{3, 5, 2, 4}, GraphLayout -> {"RadialEmbedding", "LayerSizeFunction"->(#&)}]


enter image description here







share|improve this answer














share|improve this answer



share|improve this answer








edited 11 hours ago

























answered Dec 1 at 3:20









kglr

174k9196402




174k9196402












  • I knew you'd come up with something powerful and elegant. My only suggestion for improvement would be to take the Graph3D and somehow improve the layout on the high-$n$ layers: There seems to be lots of wasted space. Other than that... great! (+1)
    – David G. Stork
    Dec 1 at 6:33










  • Just wow. That's hardly to top in terms of elegance.
    – Henrik Schumacher
    Dec 1 at 8:52










  • @David, please see the update.
    – kglr
    Dec 1 at 16:03






  • 2




    @HenrikSchumacher: l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]]; T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]]; seems incredibly efficient, clever and... yes.. "elegant." All other implementations include more code or are less elegant (in my humble opinion). About 1/6 the code in my (non-optimized) implementation.
    – David G. Stork
    Dec 1 at 17:15








  • 1




    I've joined the community just to upvote this answer and those wonderful graphs.
    – Eric Duminil
    yesterday




















  • I knew you'd come up with something powerful and elegant. My only suggestion for improvement would be to take the Graph3D and somehow improve the layout on the high-$n$ layers: There seems to be lots of wasted space. Other than that... great! (+1)
    – David G. Stork
    Dec 1 at 6:33










  • Just wow. That's hardly to top in terms of elegance.
    – Henrik Schumacher
    Dec 1 at 8:52










  • @David, please see the update.
    – kglr
    Dec 1 at 16:03






  • 2




    @HenrikSchumacher: l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]]; T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]]; seems incredibly efficient, clever and... yes.. "elegant." All other implementations include more code or are less elegant (in my humble opinion). About 1/6 the code in my (non-optimized) implementation.
    – David G. Stork
    Dec 1 at 17:15








  • 1




    I've joined the community just to upvote this answer and those wonderful graphs.
    – Eric Duminil
    yesterday


















I knew you'd come up with something powerful and elegant. My only suggestion for improvement would be to take the Graph3D and somehow improve the layout on the high-$n$ layers: There seems to be lots of wasted space. Other than that... great! (+1)
– David G. Stork
Dec 1 at 6:33




I knew you'd come up with something powerful and elegant. My only suggestion for improvement would be to take the Graph3D and somehow improve the layout on the high-$n$ layers: There seems to be lots of wasted space. Other than that... great! (+1)
– David G. Stork
Dec 1 at 6:33












Just wow. That's hardly to top in terms of elegance.
– Henrik Schumacher
Dec 1 at 8:52




Just wow. That's hardly to top in terms of elegance.
– Henrik Schumacher
Dec 1 at 8:52












@David, please see the update.
– kglr
Dec 1 at 16:03




@David, please see the update.
– kglr
Dec 1 at 16:03




2




2




@HenrikSchumacher: l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]]; T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]]; seems incredibly efficient, clever and... yes.. "elegant." All other implementations include more code or are less elegant (in my humble opinion). About 1/6 the code in my (non-optimized) implementation.
– David G. Stork
Dec 1 at 17:15






@HenrikSchumacher: l[c_]:=TakeList[Range@Sum[k!,{k,c}],Range@c!][[c-1]]; T[x_]:=Graph[(F=Flatten)@Table[MapThread[#->#2&,{Sort@F@Table[l@i,i],l[i+1]}],{i,2,x+1}]]; seems incredibly efficient, clever and... yes.. "elegant." All other implementations include more code or are less elegant (in my humble opinion). About 1/6 the code in my (non-optimized) implementation.
– David G. Stork
Dec 1 at 17:15






1




1




I've joined the community just to upvote this answer and those wonderful graphs.
– Eric Duminil
yesterday






I've joined the community just to upvote this answer and those wonderful graphs.
– Eric Duminil
yesterday












up vote
18
down vote













IGraph/M already has this built-in as IGSymmetricTree. You can specify the number of branches at each level.



enter image description here



IGSymmetricTree[
Range[2, 4],
DirectedEdges -> True,
GraphLayout -> "LayeredEmbedding"
]


enter image description here



The implementation is mostly in C (not Mathematica) and not from igraph this time. This is simply easier to implement procedurally, for which C is a good fit. This is why I did not do it in pure WL.



Here's another structure, with a different number of branches at each level.



IGSymmetricTree[{5, 4, 3, 2}]


enter image description here






share|improve this answer























  • This is precisely the functionality I need (thanks... +1), but I was hoping for the full code to be available, and (hopefully) clever and elegant.
    – David G. Stork
    Nov 30 at 22:01










  • @DavidG.Stork The full code is available (I linked to part of it), it is just not fully in Mathematica.
    – Szabolcs
    Nov 30 at 22:02












  • Thanks, but I need fully Mathematica code. Perhaps WRI will add this valuable functionality to its next release.
    – David G. Stork
    Nov 30 at 22:04






  • 4




    @David I accept that you want WL code, but could you explain why, just to satisfy my interest? People often refuse to use my package "because it's not built in". I do not understand why that is an issue. The package is polished, more robust than most, easy to install, and easy to uninstall without leaving traces. Other than for using the function in the cloud or in a FreeCDF (which is on the way out...) I do not see why having this functionality in a package (instead of built in) would be a problem.
    – Szabolcs
    Nov 30 at 22:07








  • 1




    Sure. I appreciate your wonderful coding efforts. However, in many cases I make CDF figures for class presentation and it is simpler to generate such figures without linking to libraries (especially $C$ or $C++$ libraries). Also, I understand and can thus modify Mathematica code better. Why not write all the code in Mathematica?
    – David G. Stork
    Nov 30 at 22:18















up vote
18
down vote













IGraph/M already has this built-in as IGSymmetricTree. You can specify the number of branches at each level.



enter image description here



IGSymmetricTree[
Range[2, 4],
DirectedEdges -> True,
GraphLayout -> "LayeredEmbedding"
]


enter image description here



The implementation is mostly in C (not Mathematica) and not from igraph this time. This is simply easier to implement procedurally, for which C is a good fit. This is why I did not do it in pure WL.



Here's another structure, with a different number of branches at each level.



IGSymmetricTree[{5, 4, 3, 2}]


enter image description here






share|improve this answer























  • This is precisely the functionality I need (thanks... +1), but I was hoping for the full code to be available, and (hopefully) clever and elegant.
    – David G. Stork
    Nov 30 at 22:01










  • @DavidG.Stork The full code is available (I linked to part of it), it is just not fully in Mathematica.
    – Szabolcs
    Nov 30 at 22:02












  • Thanks, but I need fully Mathematica code. Perhaps WRI will add this valuable functionality to its next release.
    – David G. Stork
    Nov 30 at 22:04






  • 4




    @David I accept that you want WL code, but could you explain why, just to satisfy my interest? People often refuse to use my package "because it's not built in". I do not understand why that is an issue. The package is polished, more robust than most, easy to install, and easy to uninstall without leaving traces. Other than for using the function in the cloud or in a FreeCDF (which is on the way out...) I do not see why having this functionality in a package (instead of built in) would be a problem.
    – Szabolcs
    Nov 30 at 22:07








  • 1




    Sure. I appreciate your wonderful coding efforts. However, in many cases I make CDF figures for class presentation and it is simpler to generate such figures without linking to libraries (especially $C$ or $C++$ libraries). Also, I understand and can thus modify Mathematica code better. Why not write all the code in Mathematica?
    – David G. Stork
    Nov 30 at 22:18













up vote
18
down vote










up vote
18
down vote









IGraph/M already has this built-in as IGSymmetricTree. You can specify the number of branches at each level.



enter image description here



IGSymmetricTree[
Range[2, 4],
DirectedEdges -> True,
GraphLayout -> "LayeredEmbedding"
]


enter image description here



The implementation is mostly in C (not Mathematica) and not from igraph this time. This is simply easier to implement procedurally, for which C is a good fit. This is why I did not do it in pure WL.



Here's another structure, with a different number of branches at each level.



IGSymmetricTree[{5, 4, 3, 2}]


enter image description here






share|improve this answer














IGraph/M already has this built-in as IGSymmetricTree. You can specify the number of branches at each level.



enter image description here



IGSymmetricTree[
Range[2, 4],
DirectedEdges -> True,
GraphLayout -> "LayeredEmbedding"
]


enter image description here



The implementation is mostly in C (not Mathematica) and not from igraph this time. This is simply easier to implement procedurally, for which C is a good fit. This is why I did not do it in pure WL.



Here's another structure, with a different number of branches at each level.



IGSymmetricTree[{5, 4, 3, 2}]


enter image description here







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 30 at 22:01

























answered Nov 30 at 21:56









Szabolcs

158k13430923




158k13430923












  • This is precisely the functionality I need (thanks... +1), but I was hoping for the full code to be available, and (hopefully) clever and elegant.
    – David G. Stork
    Nov 30 at 22:01










  • @DavidG.Stork The full code is available (I linked to part of it), it is just not fully in Mathematica.
    – Szabolcs
    Nov 30 at 22:02












  • Thanks, but I need fully Mathematica code. Perhaps WRI will add this valuable functionality to its next release.
    – David G. Stork
    Nov 30 at 22:04






  • 4




    @David I accept that you want WL code, but could you explain why, just to satisfy my interest? People often refuse to use my package "because it's not built in". I do not understand why that is an issue. The package is polished, more robust than most, easy to install, and easy to uninstall without leaving traces. Other than for using the function in the cloud or in a FreeCDF (which is on the way out...) I do not see why having this functionality in a package (instead of built in) would be a problem.
    – Szabolcs
    Nov 30 at 22:07








  • 1




    Sure. I appreciate your wonderful coding efforts. However, in many cases I make CDF figures for class presentation and it is simpler to generate such figures without linking to libraries (especially $C$ or $C++$ libraries). Also, I understand and can thus modify Mathematica code better. Why not write all the code in Mathematica?
    – David G. Stork
    Nov 30 at 22:18


















  • This is precisely the functionality I need (thanks... +1), but I was hoping for the full code to be available, and (hopefully) clever and elegant.
    – David G. Stork
    Nov 30 at 22:01










  • @DavidG.Stork The full code is available (I linked to part of it), it is just not fully in Mathematica.
    – Szabolcs
    Nov 30 at 22:02












  • Thanks, but I need fully Mathematica code. Perhaps WRI will add this valuable functionality to its next release.
    – David G. Stork
    Nov 30 at 22:04






  • 4




    @David I accept that you want WL code, but could you explain why, just to satisfy my interest? People often refuse to use my package "because it's not built in". I do not understand why that is an issue. The package is polished, more robust than most, easy to install, and easy to uninstall without leaving traces. Other than for using the function in the cloud or in a FreeCDF (which is on the way out...) I do not see why having this functionality in a package (instead of built in) would be a problem.
    – Szabolcs
    Nov 30 at 22:07








  • 1




    Sure. I appreciate your wonderful coding efforts. However, in many cases I make CDF figures for class presentation and it is simpler to generate such figures without linking to libraries (especially $C$ or $C++$ libraries). Also, I understand and can thus modify Mathematica code better. Why not write all the code in Mathematica?
    – David G. Stork
    Nov 30 at 22:18
















This is precisely the functionality I need (thanks... +1), but I was hoping for the full code to be available, and (hopefully) clever and elegant.
– David G. Stork
Nov 30 at 22:01




This is precisely the functionality I need (thanks... +1), but I was hoping for the full code to be available, and (hopefully) clever and elegant.
– David G. Stork
Nov 30 at 22:01












@DavidG.Stork The full code is available (I linked to part of it), it is just not fully in Mathematica.
– Szabolcs
Nov 30 at 22:02






@DavidG.Stork The full code is available (I linked to part of it), it is just not fully in Mathematica.
– Szabolcs
Nov 30 at 22:02














Thanks, but I need fully Mathematica code. Perhaps WRI will add this valuable functionality to its next release.
– David G. Stork
Nov 30 at 22:04




Thanks, but I need fully Mathematica code. Perhaps WRI will add this valuable functionality to its next release.
– David G. Stork
Nov 30 at 22:04




4




4




@David I accept that you want WL code, but could you explain why, just to satisfy my interest? People often refuse to use my package "because it's not built in". I do not understand why that is an issue. The package is polished, more robust than most, easy to install, and easy to uninstall without leaving traces. Other than for using the function in the cloud or in a FreeCDF (which is on the way out...) I do not see why having this functionality in a package (instead of built in) would be a problem.
– Szabolcs
Nov 30 at 22:07






@David I accept that you want WL code, but could you explain why, just to satisfy my interest? People often refuse to use my package "because it's not built in". I do not understand why that is an issue. The package is polished, more robust than most, easy to install, and easy to uninstall without leaving traces. Other than for using the function in the cloud or in a FreeCDF (which is on the way out...) I do not see why having this functionality in a package (instead of built in) would be a problem.
– Szabolcs
Nov 30 at 22:07






1




1




Sure. I appreciate your wonderful coding efforts. However, in many cases I make CDF figures for class presentation and it is simpler to generate such figures without linking to libraries (especially $C$ or $C++$ libraries). Also, I understand and can thus modify Mathematica code better. Why not write all the code in Mathematica?
– David G. Stork
Nov 30 at 22:18




Sure. I appreciate your wonderful coding efforts. However, in many cases I make CDF figures for class presentation and it is simpler to generate such figures without linking to libraries (especially $C$ or $C++$ libraries). Also, I understand and can thus modify Mathematica code better. Why not write all the code in Mathematica?
– David G. Stork
Nov 30 at 22:18










up vote
12
down vote













I don't know if you find this elegant. But I give it a try.



maxdepth = 5;
Graph[
Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, (i + 1)]],
Join[{{1}}, Partition[Accumulate[Range[maxdepth - 1]!], 2, 1] + ConstantArray[{1, 0}, maxdepth - 2]]
],
Range[2, Total[Range[maxdepth]!]]
}],
DirectedEdges -> True,
GraphLayout -> "BalloonEmbedding"
]


enter image description here



Edit



Out of curiosity, I adapted the algorithm above to produce also other symmetric trees.



SymmetricTree[branchlist_?(VectorQ[#, IntegerQ] &)] := 
Module[{levelnodecounts},
levelnodecounts = FoldList[#1 #2 &, 1, branchlist];
Graph[Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, branchlist[[i[[1]]]]]],
Join[
{{1}},
Partition[Accumulate[Most[levelnodecounts]], 2, 1] + ConstantArray[{1, 0}, Length[branchlist] - 1]
]
],
Range[2, 1 + Total[Rest[levelnodecounts]]]}],
DirectedEdges -> True
]
]


Regarding speed, it seems to be on par with IGSymmetricTree. Of course, I cannot provide such a detailed user interface as Szabolcs so I would suggest to use IGraphM whenever possible.



Edit 2



Adapting my (slow) code for fractal trees, here is another way to embedd the tree:



BoccoliEmbedding[branchlist_] := 
Module[{data0, data, θ, stem, thickness, s1, s2, f, F},
θ = Pi/4.;
s1 = 1/GoldenRatio // N;
s2 = 1/GoldenRatio // N;
stem = {0., 0., 1.};
thickness = 0.15;
data0 = {Join[
{{0., 0., 0.}},
{stem},
{{thickness, 1., 0.}},
Table[
RotationMatrix[2. k Pi/branchlist[[1]], {0, 0, 1}].{Cos[θ], 0.,Sin[θ]},
{k, 0, branchlist[[1]] - 1}]
]
};
f = {U, n} [Function] Table[
Join[
{U[[1]] + U[[2]]},
{U[[i]]},
{s2 U[[3]]},
Dot[
s1 Table[RotationMatrix[2. Pi j/n, U[[2]]].U[[i]], {j, 0, n - 1}],
RotationMatrix[{U[[i]], U[[2]]}]
]
],
{i, 4, Length[U]}];
F = {data, n} [Function] Join @@ (f[#, n] & /@ data);
data = Join @@ FoldList[F, data0, Join[Rest[branchlist], {1}]];
data[[All, 1]] + data[[All, 2]]
];


And this is how we apply it:



b = Range[2, 7];
plot = Graph[
EdgeList[SymmetricTree[b]],
VertexCoordinates -> BoccoliEmbedding[b]
]


enter image description here






share|improve this answer



















  • 1




    Elegant enough! (+1) GraphLayout -> "LayeredEmbedding" works fine for $4$ levels, but not $5$, so your layout choice is probably one of the best. Before I accept, let me wait to see if someone is clever with specifying vertex order or other approach.
    – David G. Stork
    Nov 30 at 21:59










  • Thanks for the wonderful coding... extremely helpful. I know it wasn't part of my original question, but I've been working on a three-dimensional graph embedding, using VertexCoordinates, in which each level $i$ is at a different (stacked) height and the vertices at each height are packed efficiently. This would be a very cool graphic, and interpretable for $n=7$ or possibly higher!
    – David G. Stork
    Dec 1 at 0:39

















up vote
12
down vote













I don't know if you find this elegant. But I give it a try.



maxdepth = 5;
Graph[
Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, (i + 1)]],
Join[{{1}}, Partition[Accumulate[Range[maxdepth - 1]!], 2, 1] + ConstantArray[{1, 0}, maxdepth - 2]]
],
Range[2, Total[Range[maxdepth]!]]
}],
DirectedEdges -> True,
GraphLayout -> "BalloonEmbedding"
]


enter image description here



Edit



Out of curiosity, I adapted the algorithm above to produce also other symmetric trees.



SymmetricTree[branchlist_?(VectorQ[#, IntegerQ] &)] := 
Module[{levelnodecounts},
levelnodecounts = FoldList[#1 #2 &, 1, branchlist];
Graph[Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, branchlist[[i[[1]]]]]],
Join[
{{1}},
Partition[Accumulate[Most[levelnodecounts]], 2, 1] + ConstantArray[{1, 0}, Length[branchlist] - 1]
]
],
Range[2, 1 + Total[Rest[levelnodecounts]]]}],
DirectedEdges -> True
]
]


Regarding speed, it seems to be on par with IGSymmetricTree. Of course, I cannot provide such a detailed user interface as Szabolcs so I would suggest to use IGraphM whenever possible.



Edit 2



Adapting my (slow) code for fractal trees, here is another way to embedd the tree:



BoccoliEmbedding[branchlist_] := 
Module[{data0, data, θ, stem, thickness, s1, s2, f, F},
θ = Pi/4.;
s1 = 1/GoldenRatio // N;
s2 = 1/GoldenRatio // N;
stem = {0., 0., 1.};
thickness = 0.15;
data0 = {Join[
{{0., 0., 0.}},
{stem},
{{thickness, 1., 0.}},
Table[
RotationMatrix[2. k Pi/branchlist[[1]], {0, 0, 1}].{Cos[θ], 0.,Sin[θ]},
{k, 0, branchlist[[1]] - 1}]
]
};
f = {U, n} [Function] Table[
Join[
{U[[1]] + U[[2]]},
{U[[i]]},
{s2 U[[3]]},
Dot[
s1 Table[RotationMatrix[2. Pi j/n, U[[2]]].U[[i]], {j, 0, n - 1}],
RotationMatrix[{U[[i]], U[[2]]}]
]
],
{i, 4, Length[U]}];
F = {data, n} [Function] Join @@ (f[#, n] & /@ data);
data = Join @@ FoldList[F, data0, Join[Rest[branchlist], {1}]];
data[[All, 1]] + data[[All, 2]]
];


And this is how we apply it:



b = Range[2, 7];
plot = Graph[
EdgeList[SymmetricTree[b]],
VertexCoordinates -> BoccoliEmbedding[b]
]


enter image description here






share|improve this answer



















  • 1




    Elegant enough! (+1) GraphLayout -> "LayeredEmbedding" works fine for $4$ levels, but not $5$, so your layout choice is probably one of the best. Before I accept, let me wait to see if someone is clever with specifying vertex order or other approach.
    – David G. Stork
    Nov 30 at 21:59










  • Thanks for the wonderful coding... extremely helpful. I know it wasn't part of my original question, but I've been working on a three-dimensional graph embedding, using VertexCoordinates, in which each level $i$ is at a different (stacked) height and the vertices at each height are packed efficiently. This would be a very cool graphic, and interpretable for $n=7$ or possibly higher!
    – David G. Stork
    Dec 1 at 0:39















up vote
12
down vote










up vote
12
down vote









I don't know if you find this elegant. But I give it a try.



maxdepth = 5;
Graph[
Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, (i + 1)]],
Join[{{1}}, Partition[Accumulate[Range[maxdepth - 1]!], 2, 1] + ConstantArray[{1, 0}, maxdepth - 2]]
],
Range[2, Total[Range[maxdepth]!]]
}],
DirectedEdges -> True,
GraphLayout -> "BalloonEmbedding"
]


enter image description here



Edit



Out of curiosity, I adapted the algorithm above to produce also other symmetric trees.



SymmetricTree[branchlist_?(VectorQ[#, IntegerQ] &)] := 
Module[{levelnodecounts},
levelnodecounts = FoldList[#1 #2 &, 1, branchlist];
Graph[Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, branchlist[[i[[1]]]]]],
Join[
{{1}},
Partition[Accumulate[Most[levelnodecounts]], 2, 1] + ConstantArray[{1, 0}, Length[branchlist] - 1]
]
],
Range[2, 1 + Total[Rest[levelnodecounts]]]}],
DirectedEdges -> True
]
]


Regarding speed, it seems to be on par with IGSymmetricTree. Of course, I cannot provide such a detailed user interface as Szabolcs so I would suggest to use IGraphM whenever possible.



Edit 2



Adapting my (slow) code for fractal trees, here is another way to embedd the tree:



BoccoliEmbedding[branchlist_] := 
Module[{data0, data, θ, stem, thickness, s1, s2, f, F},
θ = Pi/4.;
s1 = 1/GoldenRatio // N;
s2 = 1/GoldenRatio // N;
stem = {0., 0., 1.};
thickness = 0.15;
data0 = {Join[
{{0., 0., 0.}},
{stem},
{{thickness, 1., 0.}},
Table[
RotationMatrix[2. k Pi/branchlist[[1]], {0, 0, 1}].{Cos[θ], 0.,Sin[θ]},
{k, 0, branchlist[[1]] - 1}]
]
};
f = {U, n} [Function] Table[
Join[
{U[[1]] + U[[2]]},
{U[[i]]},
{s2 U[[3]]},
Dot[
s1 Table[RotationMatrix[2. Pi j/n, U[[2]]].U[[i]], {j, 0, n - 1}],
RotationMatrix[{U[[i]], U[[2]]}]
]
],
{i, 4, Length[U]}];
F = {data, n} [Function] Join @@ (f[#, n] & /@ data);
data = Join @@ FoldList[F, data0, Join[Rest[branchlist], {1}]];
data[[All, 1]] + data[[All, 2]]
];


And this is how we apply it:



b = Range[2, 7];
plot = Graph[
EdgeList[SymmetricTree[b]],
VertexCoordinates -> BoccoliEmbedding[b]
]


enter image description here






share|improve this answer














I don't know if you find this elegant. But I give it a try.



maxdepth = 5;
Graph[
Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, (i + 1)]],
Join[{{1}}, Partition[Accumulate[Range[maxdepth - 1]!], 2, 1] + ConstantArray[{1, 0}, maxdepth - 2]]
],
Range[2, Total[Range[maxdepth]!]]
}],
DirectedEdges -> True,
GraphLayout -> "BalloonEmbedding"
]


enter image description here



Edit



Out of curiosity, I adapted the algorithm above to produce also other symmetric trees.



SymmetricTree[branchlist_?(VectorQ[#, IntegerQ] &)] := 
Module[{levelnodecounts},
levelnodecounts = FoldList[#1 #2 &, 1, branchlist];
Graph[Transpose[{
Join @@ MapIndexed[
{x, i} [Function] Join @@ Transpose[ConstantArray[Range @@ x, branchlist[[i[[1]]]]]],
Join[
{{1}},
Partition[Accumulate[Most[levelnodecounts]], 2, 1] + ConstantArray[{1, 0}, Length[branchlist] - 1]
]
],
Range[2, 1 + Total[Rest[levelnodecounts]]]}],
DirectedEdges -> True
]
]


Regarding speed, it seems to be on par with IGSymmetricTree. Of course, I cannot provide such a detailed user interface as Szabolcs so I would suggest to use IGraphM whenever possible.



Edit 2



Adapting my (slow) code for fractal trees, here is another way to embedd the tree:



BoccoliEmbedding[branchlist_] := 
Module[{data0, data, θ, stem, thickness, s1, s2, f, F},
θ = Pi/4.;
s1 = 1/GoldenRatio // N;
s2 = 1/GoldenRatio // N;
stem = {0., 0., 1.};
thickness = 0.15;
data0 = {Join[
{{0., 0., 0.}},
{stem},
{{thickness, 1., 0.}},
Table[
RotationMatrix[2. k Pi/branchlist[[1]], {0, 0, 1}].{Cos[θ], 0.,Sin[θ]},
{k, 0, branchlist[[1]] - 1}]
]
};
f = {U, n} [Function] Table[
Join[
{U[[1]] + U[[2]]},
{U[[i]]},
{s2 U[[3]]},
Dot[
s1 Table[RotationMatrix[2. Pi j/n, U[[2]]].U[[i]], {j, 0, n - 1}],
RotationMatrix[{U[[i]], U[[2]]}]
]
],
{i, 4, Length[U]}];
F = {data, n} [Function] Join @@ (f[#, n] & /@ data);
data = Join @@ FoldList[F, data0, Join[Rest[branchlist], {1}]];
data[[All, 1]] + data[[All, 2]]
];


And this is how we apply it:



b = Range[2, 7];
plot = Graph[
EdgeList[SymmetricTree[b]],
VertexCoordinates -> BoccoliEmbedding[b]
]


enter image description here







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 days ago

























answered Nov 30 at 21:53









Henrik Schumacher

46.4k466133




46.4k466133








  • 1




    Elegant enough! (+1) GraphLayout -> "LayeredEmbedding" works fine for $4$ levels, but not $5$, so your layout choice is probably one of the best. Before I accept, let me wait to see if someone is clever with specifying vertex order or other approach.
    – David G. Stork
    Nov 30 at 21:59










  • Thanks for the wonderful coding... extremely helpful. I know it wasn't part of my original question, but I've been working on a three-dimensional graph embedding, using VertexCoordinates, in which each level $i$ is at a different (stacked) height and the vertices at each height are packed efficiently. This would be a very cool graphic, and interpretable for $n=7$ or possibly higher!
    – David G. Stork
    Dec 1 at 0:39
















  • 1




    Elegant enough! (+1) GraphLayout -> "LayeredEmbedding" works fine for $4$ levels, but not $5$, so your layout choice is probably one of the best. Before I accept, let me wait to see if someone is clever with specifying vertex order or other approach.
    – David G. Stork
    Nov 30 at 21:59










  • Thanks for the wonderful coding... extremely helpful. I know it wasn't part of my original question, but I've been working on a three-dimensional graph embedding, using VertexCoordinates, in which each level $i$ is at a different (stacked) height and the vertices at each height are packed efficiently. This would be a very cool graphic, and interpretable for $n=7$ or possibly higher!
    – David G. Stork
    Dec 1 at 0:39










1




1




Elegant enough! (+1) GraphLayout -> "LayeredEmbedding" works fine for $4$ levels, but not $5$, so your layout choice is probably one of the best. Before I accept, let me wait to see if someone is clever with specifying vertex order or other approach.
– David G. Stork
Nov 30 at 21:59




Elegant enough! (+1) GraphLayout -> "LayeredEmbedding" works fine for $4$ levels, but not $5$, so your layout choice is probably one of the best. Before I accept, let me wait to see if someone is clever with specifying vertex order or other approach.
– David G. Stork
Nov 30 at 21:59












Thanks for the wonderful coding... extremely helpful. I know it wasn't part of my original question, but I've been working on a three-dimensional graph embedding, using VertexCoordinates, in which each level $i$ is at a different (stacked) height and the vertices at each height are packed efficiently. This would be a very cool graphic, and interpretable for $n=7$ or possibly higher!
– David G. Stork
Dec 1 at 0:39






Thanks for the wonderful coding... extremely helpful. I know it wasn't part of my original question, but I've been working on a three-dimensional graph embedding, using VertexCoordinates, in which each level $i$ is at a different (stacked) height and the vertices at each height are packed efficiently. This would be a very cool graphic, and interpretable for $n=7$ or possibly higher!
– David G. Stork
Dec 1 at 0:39




















draft saved

draft discarded




















































Thanks for contributing an answer to Mathematica Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f187060%2felegant-implementation-of-factorial-tree-graph%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

AnyDesk - Fatal Program Failure

How to calibrate 16:9 built-in touch-screen to a 4:3 resolution?

QoS: MAC-Priority for clients behind a repeater