-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrandom_trees_presentation.Rmd
201 lines (169 loc) · 11.3 KB
/
random_trees_presentation.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
---
title: Random Trees Presentation
author: Sean Gilligan
output: github_document
---
## Fractals
Fractals are mathematical objects made from simple recursive processes that produce potentially infinite identical patterns across many different scales. Many fractals appear in nature. The website <a href="http://thescienceexplorer.com/nature/8-stunning-fractals-found-nature">The Science Explorer</a> provides some examples which I have reproduced below. The package I've written allows for the production of fractal trees, both deterministic and with some added randomness in a couple domains. It also allows for gif production to make trees that sway in the wind.
<img src="http://thescienceexplorer.com/sites/thescienceexplorer.com/files/styles/content_image__large/public/5528521705_10f298b94b_o.jpg?itok=clSGioOp×tamp=1467736739" width="420"> <img src="http://thescienceexplorer.com/sites/thescienceexplorer.com/files/styles/content_image__large/public/793px-NautilusCutawayLogarithmicSpiral.jpg?itok=LhtsZKs5×tamp=1467736970" width="420"> <img src="http://thescienceexplorer.com/sites/thescienceexplorer.com/files/styles/content_image__large/public/800px-Angelica_flowerhead_showing_pattern.JPG?itok=tfzWXhd9×tamp=1467737100" width="420"> <img src="http://thescienceexplorer.com/sites/thescienceexplorer.com/files/styles/content_image__large/public/blog/800px-Flickr_-_cyclonebill_-_Romanesco.jpg?itok=DW5Pu9-H×tamp=1467736305" width="420">
```{r, message = F, warning = F}
devtools::load_all()
```
## Deterministic Trees
<pre><code>
<b>basic_deterministic_trees</b>(splits = 3, length = 2, scale_length = T, length_scale = 1.4, children = 2,
start_angle = 0, angle = pi/(splits/2 + 1), scale_angle = T, angle_scale = sqrt(1.272018), thickness = 2,
scale_thickness = T, thickness_scale = 1.61803, taper = T, man_lengths = 0, man_angles = 0,
man_split_thickness = 0, man_begin_thick = 0, man_end_thick = 0, man_children = 0, sib_ratio = 0,
title = NA, plot = T, datadump = F)
</code></pre>
<pre><code>
<b>splits</b> : (int) Indicates number of levels beyond starting branch.
<b>length</b> : (dbl) Indicates length of a branch.
<b>scale_length</b> : (lgl) Indicates if lengths should be scaled at each new level.
<b>length_scale</b> : (dbl) Indicates rate in which branch lengths shorten at each level.
<b>children</b> : (int) Indicates number of new branches at each new level.
<b>start_angle</b> : (dbl) Indicates angle in radians of starting branch, measured ccw from
the +y direction.
<b>angle</b> : (dbl) Indicates angle in radian between each branch at a split.
<b>scale_angle</b> : (lgl) Indicates if branch split angles should be scaled at each new level.
<b>angle_scale</b> : (lgl) Indicates rate at which angles should decrease
<b>thickness</b> : (dbl) Indicates thickness of a branch.
<b>scale_thickness</b> : (lgl) Indicates if thickness should should shrink at each new level
<b>thickness_scale</b> : (dbl) Indicates rate in which branch thicknesses should shrink
<b>taper</b> : (lgl) Indicates if branches should taper.
<b>man_lengths</b> : Manually select branch length for starting branch and branches at each level.
<b>man_angles</b> : Manually select angles between branches at each split by level.
<b>man_split_thickness</b> : Manually select thickness of each branch at each split in order.
<b>man_begin_thick</b> : Manually select starting thickness by level.
<b>man_end_thick</b> : Manually select ending thickness.
<b>man_children</b> : Manually select number of branches at split by level.
<b>sib_lgth_ratio</b> : Only works if equal number of children at each split. Vector indicates
relative size of children at each split.
<br>
<b>title</b> : (chr) Optional title for output tree.
<b>plot</b> : (lgl) Default to T for plotting
<b>datadump</b> : (lgl) Default to F. Set to T get relevant data.
</code></pre>
#### Testing "splits" input with others set to default
```{r, message = F, warning = F}
par(mfrow=c(2,3), mar=c(1,1,1,1))
deterministic_tree(splits = 1, title = "splits = 1")
deterministic_tree(splits = 2, title = "splits = 2")
deterministic_tree(title = "default splits = 3")
deterministic_tree(splits = 4, title = "splits = 4")
deterministic_tree(splits = 5, title = "splits = 5")
deterministic_tree(splits = 6, title = "splits = 6")
```
#### Test "children" and "man_children" with others set to default
```{r}
par(mfrow=c(2,2), mar=c(1,1,1,1))
deterministic_tree(children = 1, title = "children = 1")
deterministic_tree(title = "default children = 2")
deterministic_tree(children = 3, title = "children = 3")
deterministic_tree(children = 4, title = "children = 4")
```
```{r}
par(mfrow=c(2,2), mar=c(1,1,1,1))
deterministic_tree(man_children = c(2,3,4), title = "man_children = c(4,3,2)")
deterministic_tree(man_children = c(3,2,3), title = "man_children = c(3,2,3)")
# Having "man_children" length =/= "splits" changes "splits" to length.
deterministic_tree(man_children = 4, title = "man_children = 4")
deterministic_tree(man_children = c(3,3,3,3,3), title = "man_children = c(3,3,3,3,3)")
```
#### The role of tapering and scaling at each split for "splits = 5"
```{r}
par(mfrow=c(2,3), mar=c(1,1,1,1))
deterministic_tree(splits = 5, title = "all = T")
deterministic_tree(splits = 5, taper = F, title = "scale_thickness = T, taper = F")
deterministic_tree(splits = 5, scale_thickness = F, taper = F, title = "scale_thickness = F, taper = F")
deterministic_tree(splits = 5, scale_length = F, title = "scale_length = F")
deterministic_tree(splits = 5, scale_angle = F, title = "scale_angle = F")
```
#### Explore "sib_lgth_ratio" which determines relative length of children at each split
```{r}
par(mfrow=c(2,3), mar=c(1,1,1,1))
deterministic_tree(splits = 8, sib_lgth_ratio = c(1,2), title = "splits = 8, sib_ratio = c(1,2)")
deterministic_tree(splits = 6, sib_lgth_ratio = c(1,2,1), title = "splits = 6, sib_ratio = c(1,2,1)")
deterministic_tree(splits = 5, sib_lgth_ratio = c(1,2,2,1), title = "splits = 5, sib_ratio = c(1,2,2,1)")
deterministic_tree(splits = 5, sib_lgth_ratio = c(2,1,1,2), title = "splits = 5, sib_ratio = c(1,2,2,1)")
deterministic_tree(splits = 6, sib_lgth_ratio = c(1,2,3), title = "splits = 6, sib_ratio = c(1,2,3)")
deterministic_tree(splits = 6, sib_lgth_ratio = c(2,1,2), title = "splits = 6, sib_ratio = c(1,2,3)")
```
#### Explore "trunk_scale". It simply shrinks the starter branch. Other arguments: "splits = 6, angle_scale = 1.25, sib_lgth_ratio = c(1,5,1)"
```{r}
par(mfrow=c(1,3), mar=c(1,1,1,1))
deterministic_tree(splits = 6, angle_scale = 1.25, sib_lgth_ratio = c(1,5,1), title = "default: trunk_scale = 1")
deterministic_tree(splits = 6, trunk_scale = 0.75, angle_scale = 1.25, sib_lgth_ratio = c(1,5,1), title = "trunk_scale = 0.75")
deterministic_tree(splits = 6, trunk_scale = 0.25, angle_scale = 1.25, sib_lgth_ratio = c(1,4,1), title = "trunk_scale = 0.25")
```
## The Nature of Code - Daniel Shiffman
Chapter 9 of Daniel Shiffman's <a hreg="https://natureofcode.com/book/chapter-8-fractals/">book</a> discusses fractals and random/deterministic trees. It was the main inspiration for this project, and part of my goal was to be able to casually reproduce some of the examples he provides. I do so below.
#### Daniel's trees:
<img src="nature_of_code_examples_files/ch08_ex06a.png">
<img src="nature_of_code_examples_files/ch08_ex06b.png">
<img src="nature_of_code_examples_files/ch08_ex06c.png">
#### My trees:
```{r}
par(mfrow=c(1,3), mar=c(1,1,1,1))
deterministic_tree(splits = 8, children = 2, angle = 9*pi/12, scale_angle = F,
scale_thickness = F, taper = F, thickness = 0.5, length_scale = 1.5)
deterministic_tree(splits = 8, children = 2, angle = pi/4, scale_angle = F,
scale_thickness = F, taper = F, thickness = 0.5, length_scale = 1.5)
deterministic_tree(splits = 8, children = 2, angle = pi/20, scale_angle = F,
scale_thickness = F, taper = F, thickness = 0.5, length_scale = 1.5)
```
## Random Trees
Essentially the same as <code>deterministic_trees()</code> but adds a few additional arguments.
<pre><code>
<b>random_angles</b> : (lgl) Toggles angle noise on/off. Random values currently chosen
via sampling from normal distribution.
<b>angle_variance</b> : (dbl) Indicates base variance for angle noise. By default "set" to
zero be given value based on other inputs. In particular by (angles[2]/4)^2,
where angles[2] is the angle between branches at the first split.
<b>random_lengths</b> : (lgl) Toggles length noise on/off. Random values currently chosen via
sampling from normal distribution.
<b>length_variance</b> : (dbl) Indicates base variance for length noise. By default "set" to
zero be given value later based on other inputs. In particular by lengths[1]/24,
where lengths[1] is the length of the starting branch.
</code></pre>
The effects look admittedly better for some tree specifications than others.
```{r}
titles <- rep(c("both = F", "random_angles = T", "random_lengths = T", "both = T"), each = 4)
ras <- rep(c(F,F,F,F,T,T,T,T), 2)
rls <- c(rep(F,8),rep(T,8))
```
#### splits = 8, children = 2, angle = pi/4, scale_angle = F, length_scale = 1.4
```{r, fig.height = 5}
par(mfrow=c(4,4), mar=c(1,1,1,1))
for(i in 1:16){
random_tree(splits = 8, children = 2, angle = pi/4, scale_angle = F, length_scale = 1.4, random_angles = ras[i], random_lengths = rls[i], title = titles[i])
}
```
#### splits = 6, trunk_scale = 0.75, angle_scale = 1.25, sib_ratio = c(1,3,1)
```{r, fig.height = 5}
par(mfrow=c(4,4), mar=c(1,1,1,1))
for(i in 1:16){
random_tree(splits = 6, trunk_scale = 0.5, angle_scale = 1.25, sib_lgth_ratio = c(1,3,1), random_angles = ras[i], random_lengths = rls[i], title = titles[i])
}
```
## Animating Trees
Both functions above allow the user to store the output data of the tree for potential later modification. The function <code>swaying_tree()</code> takes this data dump as an input with a couple randomness variables to simulate wind patterns in the form of a random field of to create a GIF of a "swaying" tree. The images for the GIF file are stored locally before being deleted upon GIF formation.
```{r, message = F, warning = F}
fractal_tree <- random_tree(splits = 8, children = 2, angle = pi/4, scale_angle = F, random_angles = T,
random_lengths = T, length_scale = 1.4, plot = F, datadump = T)
```
This code lives in the function <code>swaying_tree()</code>, with exception of the plotting.
```{r}
model <- RandomFields::RMexp(var = 0.02, scale = 0.4)
branch_count <- sum(cumprod(fractal_tree$fun_variables$children)) + 1
x <- seq(0, 10, length.out = 100)
y <- seq(0, 10, length.out = branch_count)
simu <- suppressMessages(as.matrix(RandomFields::RFsimulate(model, x, y, grid=TRUE)))
raster::plot(raster::raster(simu))
```
An example input and possible GIF.
```{r}
filename <- swaying_tree(fractal_tree, var = 0.02, scale = 0.4, return_filename = T)
```
<center><img src="swaying_trees/`r noquote(filename)`"></center>