首页 > 解决方案 > 使用 gnuplot 重新缩放树的图

问题描述

我在 gnuplot 中使用以下代码从不同的输入中绘制一棵树。

### tree diagram with gnuplot
reset session

#ID  Parent   Name   Colors   shape


# put datablock into strings
IDs = Parents = Names = Colors = Shape = ""
set table $Dummy
    plot "tmp.dat" u (IDs = IDs.strcol(1)." "): \
             (Parents = Parents.strcol(2)." "): \
             (Names = Names.strcol(3)." "): \
             (Colors = Colors.strcol(4)." "): \
             (Shape = Shape.strcol(5)." ") w table
unset table

# Top node has no parent ID "NaN"
Start(n) = int(sum [i=1:words(Parents)] (word(Parents,i) eq "NaN" ? int(word(IDs,i)) : 0))

# get list index by ID
ItemIdx(s,n) = n == n ? (tmp=NaN, sum [i=1:words(s)] ((word(s,i)) == n ? (tmp=i,0) : 0), tmp) : NaN

# get parent of ID n
Parent(n) = word(Parents,ItemIdx(IDs,n))

# get level of ID n, recursive function
Level(n) = n == n ? Parent(n)>0 ? Level(Parent(n))-1 : 0 : NaN

# get number of children of ID n
ChildCount(n) = int(sum [i=1:words(Parents)] (word(Parents,i)==n))

# Create child list of ID n
ChildList(n) = (Ch = " ", sum [i=1:words(IDs)] (word(Parents,i)==n ? (Ch = Ch.word(IDs,i)." ",1) : (Ch,0) ), Ch )

# m-th child of ID n
Child(n,m) = word(ChildList(n),m)

# List of leaves, recursive function
LeafList(n) = (LL="", ChildCount(n)==0 ? LL=LL.n." " : sum [i=1:ChildCount(n)] 
(LL=LL.LeafList(Child(n,i)), 0),LL)

# create list of all leaves
LeafAll = LeafList(Start(0))

# get x-position of ID n, recursive function
XPos(n) = ChildCount(n) == 0 ? ItemIdx(LeafAll,n) : (sum [i=1:ChildCount(n)](XPos(Child(n,i))))/(ChildCount(n))

# create the tree datablock for plotting
set print $Tree
do for [j=1:words(IDs)] {
    n = int(word(IDs,j))
    print sprintf("% 3d % 7.2f % 4d % 5s % 8s", n, XPos(n), Level(n), word(Names,j), word(Colors,j))
}
set print
print $Tree

# get x and y distance from ID n to its parent
dx(n) = XPos(Parent(int(n))) - XPos(int(n))
dy(n) = Level(Parent(int(n))) - Level(int(n))

unset border
unset tics
set offsets 0.25, 0.25, 0.25, 0.25

array shape[words(IDs)]         # pointtype 6 = circle, pointtype 4 = square
array color[words(IDs)] 
do for [i=1:words(IDs)] { 
 color[i] = int(word(Colors,i))
 shape[i] = int(word(Shape,i)) 
 print sprintf("color[%2d] = %d",i,color[i])
}

plot $Tree u 2:3:(dx($1)):(dy($1)) w vec nohead ls -1 not,\
    "" u 2:3:(shape[$1]+1):(color[$1]) w p pt variable ps 6 lc rgb variable not, \
    "" u 2:3:(shape[$1]) w p pt variable ps 6 lw 1.5 lc rgb "black" not, \
    "" u 2:3:4 w labels offset 0,0.1 center not

### end of code

在此处输入图像描述

对于像这样的小数据集,输出效果很好

  1    2.00    0 y_{45} 0xFE1034
  2    1.00   -1     - 0x118C4B
  3    2.99   -1 y_{37} 0xFE1034
  4    2.00   -2     - 0xC6C1C1
  5    3.98   -2 y_{13} 0xFE1034
  6    3.00   -3     - 0x118C4B
  7    4.97   -3 y_{14} 0xFE1034
  8    4.00   -4     - 0x118C4B
  9    5.94   -4 y_{20} 0xFE1034
 10    5.00   -5     - 0xC6C1C1
 11    6.88   -5 y_{27} 0xFE1034
 12    6.00   -6     - 0xC6C1C1
 13    7.75   -6 y_{41} 0xFE1034
 14    7.00   -7     - 0xC6C1C1
 15    8.50   -7 y_{54} 0xFE1034
 16    8.00   -8     - 0xC6C1C1
 17    9.00   -8     - 0xC6C1C1

但是,对于较大的数据集,树变得狭窄,节点重叠,看起来很丑。

在此处输入图像描述

此外,当像下面这样有几百个以上的节点时,我得到一个堆栈溢出错误并且没有出现绘图。错误来自这一行

LeafAll = LeafList(Start(0))

对此的任何帮助将不胜感激。

1 NaN y_{295} 0xFE1034 6 
2 1 x_{0} 0x33B2FF 6 
3 1 y_{1285} 0xFE1034 6 
4 2 - 0xC6C1C1 8 
5 2 - 0xC6C1C1 8 
6 3 x_{3} 0x33B2FF 6 
7 3 y_{18} 0xFE1034 6 
8 6 - 0xC6C1C1 8 
9 6 - 0xC6C1C1 8 
10 7 x_{13} 0x33B2FF 6 
11 7 y_{21} 0xFE1034 6 
12 10 - 0xC6C1C1 8 
13 10 - 0xC6C1C1 8 
14 11 x_{10} 0x33B2FF 6 
15 11 y_{50} 0xFE1034 6 
16 14 - 0xC6C1C1 8 
17 14 - 0xC6C1C1 8 
18 15 - 0x118C4B 4 
19 15 y_{62} 0xFE1034 6 
20 19 - 0xC6C1C1 8 
21 19 y_{48} 0xFE1034 6 
22 21 x_{41} 0x33B2FF 6 
23 21 y_{1839} 0xFE1034 6 
24 22 - 0xC6C1C1 8 
25 22 - 0xC6C1C1 8 
26 23 - 0xC6C1C1 8 
27 23 y_{44} 0xFE1034 6 
28 27 x_{12} 0x33B2FF 6 
29 27 y_{15} 0xFE1034 6 
30 28 - 0xC6C1C1 8 
31 28 - 0xC6C1C1 8 
32 29 x_{58} 0x33B2FF 6 
33 29 y_{127} 0xFE1034 6 
34 32 - 0xC6C1C1 8 
35 32 - 0xC6C1C1 8 
36 33 - 0xC6C1C1 8 
37 33 y_{60} 0xFE1034 6 
38 37 - 0xC6C1C1 8 
39 37 y_{1825} 0xFE1034 6 
40 39 - 0xC6C1C1 8 
41 39 y_{1878} 0xFE1034 6 
42 41 - 0xC6C1C1 8 
43 41 y_{33} 0xFE1034 6 
44 43 - 0xC6C1C1 8 
45 43 y_{3} 0xFE1034 6 
46 45 - 0xC6C1C1 8 
47 45 y_{1435} 0xFE1034 6 
48 47 - 0xC6C1C1 8 
49 47 y_{218} 0xFE1034 6 
50 49 - 0xC6C1C1 8 
51 49 y_{20} 0xFE1034 6 
52 51 - 0xC6C1C1 8 
53 51 y_{13} 0xFE1034 6 
54 53 - 0xC6C1C1 8 
55 53 y_{47} 0xFE1034 6 
56 55 - 0xC6C1C1 8 
57 55 y_{2321} 0xFE1034 6 
58 57 - 0xC6C1C1 8 
59 57 y_{28} 0xFE1034 6 
60 59 - 0xC6C1C1 8 
61 59 y_{52} 0xFE1034 6 
62 61 - 0xC6C1C1 8 
63 61 y_{2410} 0xFE1034 6 
64 63 - 0xC6C1C1 8 
65 63 y_{1751} 0xFE1034 6 
66 65 - 0xC6C1C1 8 
67 65 y_{186} 0xFE1034 6 
68 67 - 0xC6C1C1 8 
69 67 y_{1850} 0xFE1034 6 
70 69 - 0xC6C1C1 8 
71 69 y_{491} 0xFE1034 6 
72 71 - 0xC6C1C1 8 
73 71 y_{23} 0xFE1034 6 
74 73 - 0xC6C1C1 8 
75 73 y_{0} 0xFE1034 6 
76 75 x_{52} 0x33B2FF 6 
77 75 y_{1110} 0xFE1034 6 
78 76 - 0xC6C1C1 8 
79 76 - 0xC6C1C1 8 
80 77 - 0xC6C1C1 8 
81 77 y_{57} 0xFE1034 6 
82 81 - 0xC6C1C1 8 
83 81 y_{12} 0xFE1034 6 
84 83 - 0xC6C1C1 8 
85 83 y_{1269} 0xFE1034 6 
86 85 - 0xC6C1C1 8 
87 85 y_{1278} 0xFE1034 6 
88 87 - 0x118C4B 4 
89 87 y_{63} 0xFE1034 6 
90 89 - 0xC6C1C1 8 
91 89 y_{1338} 0xFE1034 6 
92 91 - 0xC6C1C1 8 
93 91 y_{1271} 0xFE1034 6 
94 93 - 0xC6C1C1 8 
95 93 y_{41} 0xFE1034 6 
96 95 - 0xC6C1C1 8 
97 95 y_{65} 0xFE1034 6 
98 97 - 0x118C4B 4 
99 97 y_{1630} 0xFE1034 6 
100 99 - 0xC6C1C1 8 
101 99 y_{2068} 0xFE1034 6 
102 101 - 0xC6C1C1 8 
103 101 y_{2532} 0xFE1034 6 
104 103 - 0xC6C1C1 8 
105 103 y_{1760} 0xFE1034 6 
106 105 - 0xC6C1C1 8 
107 105 y_{188} 0xFE1034 6 
108 107 - 0xC6C1C1 8 
109 107 y_{2405} 0xFE1034 6 
110 109 - 0xC6C1C1 8 
111 109 y_{1867} 0xFE1034 6 
112 111 - 0xC6C1C1 8 
113 111 y_{1482} 0xFE1034 6 
114 113 - 0xC6C1C1 8 
115 113 y_{79} 0xFE1034 6 
116 115 - 0xC6C1C1 8 
117 115 y_{11} 0xFE1034 6 
118 117 - 0xC6C1C1 8 
119 117 y_{5226} 0xFE1034 6 
120 119 - 0xC6C1C1 8 
121 119 y_{354} 0xFE1034 6 
122 121 - 0xC6C1C1 8 
123 121 y_{2748} 0xFE1034 6 
124 123 - 0xC6C1C1 8 
125 123 y_{27} 0xFE1034 6 
126 125 - 0xC6C1C1 8 
127 125 y_{426} 0xFE1034 6 
128 127 - 0xC6C1C1 8 
129 127 y_{12571} 0xFE1034 6 
130 129 - 0xC6C1C1 8 
131 129 y_{5089} 0xFE1034 6 
132 131 - 0xC6C1C1 8 
133 131 y_{2490} 0xFE1034 6 
134 133 - 0xC6C1C1 8 
135 133 y_{1752} 0xFE1034 6 
136 135 - 0xC6C1C1 8 
137 135 y_{1874} 0xFE1034 6 
138 137 - 0xC6C1C1 8 
139 137 y_{370} 0xFE1034 6 
140 139 - 0xC6C1C1 8 
141 139 y_{1453} 0xFE1034 6 
142 141 - 0xC6C1C1 8 
143 141 y_{2756} 0xFE1034 6 
144 143 - 0xC6C1C1 8 
145 143 y_{545} 0xFE1034 6 
146 145 - 0xC6C1C1 8 
147 145 y_{36} 0xFE1034 6 
148 147 - 0xC6C1C1 8 
149 147 y_{2409} 0xFE1034 6 
150 149 - 0xC6C1C1 8 
151 149 y_{96} 0xFE1034 6 
152 151 - 0xC6C1C1 8 
153 151 y_{82} 0xFE1034 6 
154 153 - 0xC6C1C1 8 
155 153 y_{1788} 0xFE1034 6 
156 155 - 0xC6C1C1 8 
157 155 y_{2812} 0xFE1034 6 
158 157 - 0xC6C1C1 8 
159 157 y_{10357} 0xFE1034 6 
160 159 - 0xC6C1C1 8 
161 159 y_{1801} 0xFE1034 6 
162 161 - 0xC6C1C1 8 
163 161 y_{55} 0xFE1034 6 
164 163 - 0xC6C1C1 8 
165 163 y_{2868} 0xFE1034 6 
166 165 - 0xC6C1C1 8 
167 165 y_{453} 0xFE1034 6 
168 167 - 0xC6C1C1 8 
169 167 y_{31} 0xFE1034 6 
170 169 - 0xC6C1C1 8 
171 169 y_{1281} 0xFE1034 6 
172 171 - 0xC6C1C1 8 
173 171 y_{17} 0xFE1034 6 
174 173 - 0xC6C1C1 8 
175 173 y_{1748} 0xFE1034 6 
176 175 - 0xC6C1C1 8 
177 175 y_{58} 0xFE1034 6 
178 177 - 0xC6C1C1 8 
179 177 y_{2420} 0xFE1034 6 
180 179 - 0xC6C1C1 8 
181 179 y_{7128} 0xFE1034 6 
182 181 - 0xC6C1C1 8 
183 181 y_{11164} 0xFE1034 6 
184 183 - 0xC6C1C1 8 
185 183 y_{1820} 0xFE1034 6 
186 185 - 0xC6C1C1 8 
187 185 y_{1713} 0xFE1034 6 
188 187 - 0xC6C1C1 8 
189 187 y_{387} 0xFE1034 6 
190 189 - 0xC6C1C1 8 
191 189 y_{5253} 0xFE1034 6 
192 191 - 0xC6C1C1 8 
193 191 y_{1699} 0xFE1034 6 
194 193 - 0xC6C1C1 8 
195 193 - 0xC6C1C1 8

标签: gnuplot

解决方案


gnuplot 评估堆栈的深度上限为 250,以防止递归失控。为了增加你必须编辑源代码并重新编译程序。如果你真的想这样做,相关的定义在这里:

[gnuplot-5.2.8/src] grep -n -A 3 -B 3 STACK_DEPTH eval.h
44-
45-#include <stdio.h>           /* for FILE* */
46-
47:#define STACK_DEPTH 250              /* maximum size of the execution stack */
48-#define MAX_AT_LEN 150               /* max number of entries in action table */
49-
50-/* These are used by add_action() to index the subroutine list ft[] in eval.c */

我没有仔细研究您的递归算法,但我认为可以重新排序评估,以便自下而上而不是自上而下计算子树信息。在那个方向上,它可能成为纯粹的迭代而不是递归下降。

另一方面,您还说较大的树不适合单个地块。因此,另一种方法可能是将树拆分为既适合页面又不超过堆栈深度的深度。然后为每个被截断的节点重新启动该过程,并用箭头或注释或其他指示标记该节点,例如“子树在图 1b 中继续”。在这里,我手工扭曲了你的大图来展示这个想法 在此处输入图像描述


推荐阅读