Skip to content

Latest commit

 

History

History
257 lines (202 loc) · 12.1 KB

random_trees_presentation.md

File metadata and controls

257 lines (202 loc) · 12.1 KB

Random Trees Presentation

Sean Gilligan

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 The Science Explorer 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.

devtools::load_all()

Deterministic Trees


basic_deterministic_trees(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)

splits                 : (int) Indicates number of levels beyond starting branch. 
length                 : (dbl) Indicates length of a branch. 
scale_length           : (lgl) Indicates if lengths should be scaled at each new level. 
length_scale           : (dbl) Indicates rate in which branch lengths shorten at each level. 
children               : (int) Indicates number of new branches at each new level. 
start_angle            : (dbl) Indicates angle in radians of starting branch, measured ccw from 
                               the +y direction. 
angle                  : (dbl) Indicates angle in radian between each branch at a split. 
scale_angle            : (lgl) Indicates if branch split angles should be scaled at each new level. 
angle_scale            : (lgl) Indicates rate at which angles should decrease 
thickness              : (dbl) Indicates thickness of a branch. 
scale_thickness        : (lgl) Indicates if thickness should should shrink at each new level 
thickness_scale        : (dbl) Indicates rate in which branch thicknesses should shrink 
taper                  : (lgl) Indicates if branches should taper. 

man_lengths            : Manually select branch length for starting branch and branches at each level. 
man_angles             : Manually select angles between branches at each split by level. 
man_split_thickness    : Manually select thickness of each branch at each split in order. 
man_begin_thick        : Manually select starting thickness by level. 
man_end_thick          : Manually select ending thickness. 
man_children           : Manually select number of branches at split by level. 
sib_lgth_ratio         : Only works if equal number of children at each split. Vector indicates 
                         relative size of children at each split. 

title : (chr) Optional title for output tree. plot : (lgl) Default to T for plotting datadump : (lgl) Default to F. Set to T get relevant data.

Testing “splits” input with others set to default

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

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")

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”

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

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)”

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 book 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:

My trees:

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 deterministic_trees() but adds a few additional arguments.


random_angles             : (lgl) Toggles angle noise on/off. Random values currently chosen 
                             via sampling from normal distribution.
angle_variance            : (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.
random_lengths            : (lgl) Toggles length noise on/off. Random values currently chosen via 
                             sampling from normal distribution.
length_variance           : (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.

The effects look admittedly better for some tree specifications than others.

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

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)

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 swaying_tree() 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.

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 swaying_tree(), with exception of the plotting.

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.

filename <- swaying_tree(fractal_tree, var = 0.02, scale = 0.4, return_filename = T)