2011-04-13 54 views
6

我想在Mathematica中绘制一个“分解树”。在Mathematica中绘制分解树的最简单方法是什么?

我有一个函数f需要一个对象,并返回该对象的所有组件作为列表。对于这个问题的目的,我们只是分解数学表达式如下(我的实际f依赖外部数据库分解不同种类的对象,所以我不能轻易地张贴):

f[e_?AtomQ] := {} 
f[e_] := List @@ e 

我想创建一个树状图,显示一个对象如何递归分解,继续应用f。对于上面的特定示例f,我们应该得到与TreeForm的输出非常相似的内容,不同之处在于应在每个节点处显示完整表达式(而不是仅显示一个头)。节点的子节点将成为f返回的组件。

请注意,元素可以像这样在分解树中重复,但不会在TreePlot的输出中重复元素,因为它与图形一起工作。一个想法是产生了独特的“内部名称”为每个节点,构建一个图形,并用TreePlot,将其设置为显示节点的实际形式,而不是他们的“内部名称”

回答

9

这个怎么样?

tf[x_] := f[x] /. {{} :> x, r_ :> x @@ tf /@ r} 

example usage

如果任何条款都不是惰性的,这种 “简单”(?)的做法是行不通的。

+0

的hackish的方式,但它是那种简单的解决方案,我希望的。我分解的对象被存储为字符串,所以非常适合(无意外评估)。 – Szabolcs 2011-04-13 23:37:01

+0

你能否建议一种与此解决方案兼容的方式来更改节点的字体? (需要显示默认字体中不存在的字形) – Szabolcs 2011-05-05 10:36:36

+1

@Szabolcs您可以使用'TreeForm'的'VertexRenderingFunction'选项来完全控制节点的外观, 'VertexRenderingFunction - >(Inset [Framed [Style [#2,FontFamily - >“Webdings”],Background-> LightYellow],#1]&)'。 – WReach 2011-05-05 14:32:57

4

我不知道它回答你的问题,但这里是我将如何实现基本的TreeForm:

decompose[expr_?AtomQ] := expr 
decompose[expr_] := Block[{lev = Level[expr, {1}]}, 
    Sow[Thread[expr -> lev]]; decompose /@ lev;] 

treeForm[expr_] := Reap[decompose[expr]][[-1, 1]] // Flatten 

然后:

enter image description here

编辑 ÿ如果你是对的,这不是一棵树。为了使它成为一棵树,每个表达都应该带着它的位置。有点像这样:

ClearAll[treePlot, node, decompose2]; 
SetAttributes[{treePlot, node, decompose2}, HoldAll]; 
decompose2[expr_] /; AtomQ[Unevaluated[expr]] := node[expr]; 
decompose2[expr_] := Module[{pos, list}, 
    pos = SortBy[ 
    Position[Unevaluated[expr], _, {0, Infinity}, Heads -> False], 
    Length]; 
    list = Extract[Unevaluated[expr], pos, node]; 
    list = MapThread[Append, {list, pos}]; 
    ReplaceList[ 
    list, {___, node[e1_, p1_], ___, node[e2_, p2_], ___} /; 
    Length[p2] == Length[p1] + 1 && 
     Most[p2] == p1 :> (node[e1, p1] -> node[e2, p2])] 
    ] 

然后

treePlot2[expr_] := 
Module[{data = decompose2[a^2 + Subscript[b, 2] + 3 c], gr, vlbls}, 
    gr = Graph[data]; 
    vlbls = Table[vl -> (HoldForm @@ {vl[[1]]}), {vl, VertexList[gr]}]; 
    Graph[data, VertexLabels -> vlbls, ImagePadding -> 50] 
    ] 

enter image description here

+0

你的情节是不是一个真正的树,作为_both_'a^2'和'b_2'具有指向标2.同一节点上的边缘而这也正是挑战(为什么我提到,也许是为了使用它的必要节点的“内部名称”):我需要在每一步都进行分支,并且允许元素在树中重复。我们应该在这里有两个标记为'2'的节点,一个从'a^2'分支,另一个从'b_2'分支。 – Szabolcs 2011-04-13 13:09:57

+0

@Szabolcs请参阅编辑我的回应 – Sasha 2011-04-13 17:44:48

+0

这是辉煌的代码,但有一个小错误。 treeplot2函数应为:Module [{data = decompose2 [expr],gr,vlbls}, gr = Graph [data]; vlbls =表[vl - >(HoldForm @@ {vl [[1]]}),{v1,VertexList [gr]}]; 图[数据,VertexLabels - > vlbls,ImagePadding - > 50] ], – mathlawguy 2013-01-20 15:52:25

相关问题