library(fractalforest)
This vignette presents some features of the
fractalforest
package for customizing fractal trees.
Install developer version.
# install.packages('devtools')
library(devtools)
install_github('sergiocostafh/fractalforest')
Load fractalforest package.
library(fractalforest)
The fractalforest package uses the Lindenmayer system (L-system) to
generate fractal trees. By applying recursive production rules, the
package simulates natural branching patterns, allowing for the creation
of realistic and customizable tree structures.
We will start by defining the L-system rules for constructing a simple
binary tree, and then we will go into the details.
<- data.frame(inp = c("0", "1"),
binary_tree_rules out = c("1[-0]+0", "1"), stringsAsFactors = FALSE)
Use the iterate_lsystem
function to build the string
based on the rules (rules
), the axiom (init
)
and the number of iterations (n
).
<- iterate_lsystem(init = "0", rules = binary_tree_rules, n = 5)
tree_string
tree_string#> [1] "1[-1[-1[-1[-1[-0]+0]+1[-0]+0]+1[-1[-0]+0]+1[-0]+0]+1[-1[-1[-0]+0]+1[-0]+0]+1[-1[-0]+0]+1[-0]+0]+1[-1[-1[-1[-0]+0]+1[-0]+0]+1[-1[-0]+0]+1[-0]+0]+1[-1[-1[-0]+0]+1[-0]+0]+1[-1[-0]+0]+1[-0]+0"
Build the tree data.frame from the string, and visualize the output.
<- build_tree(string = tree_string, angle = 15)
tree head(tree)
#> # A tibble: 6 × 5
#> from_x to_x from_y to_y type
#> <dbl> <dbl> <dbl> <dbl> <chr>
#> 1 0 1.04e-17 0 0.170 branch
#> 2 1.04e-17 4.39e- 2 0.170 0.333 branch
#> 3 4.39e- 2 1.29e- 1 0.333 0.480 branch
#> 4 1.29e- 1 2.49e- 1 0.480 0.600 branch
#> 5 2.49e- 1 3.95e- 1 0.600 0.685 branch
#> 6 3.95e- 1 5.59e- 1 0.685 0.729 leaf
Visualize the tree.
plot_tree(tree)
To set the rules, the following characters are recognized:
“+” Turn by positive angle.
“-” Turn by negative angle.
“[” Save current position and heading.
”]” Restore saved position and heading (allows one to go back).
“)” Reduces length and diameters of branches.
“(” Increment length and diameters of branches.
Any other characters in the rule string will be recognized as “a move
forward, drawing as you go” instruction. This means that they must be
declared in the inp
column of the rules data frame, and
also its corresponding substitution rule (out
column).
The following example demonstrates the use of parentheses to reduce/increase branch lengths.
<- data.frame(inp = c("0", "1"),
binary_tree_rules out = c("1[-(0)]+(0)", "1"), stringsAsFactors = FALSE)
<- iterate_lsystem(init = "0", rules = binary_tree_rules, n = 5)
tree_string <- build_tree(string = tree_string, angle = 15)
tree plot_tree(tree)
iterate_lsystem
functionThe n
argument controls the number of iterations do
build the plant. A large n
value can be time and memory
consuming, so be careful.
library(ggplot2)
library(patchwork)
library(dplyr)
<- lapply(1:8,
trees_n function(x) {
iterate_lsystem(init = '0', rules = binary_tree_rules, n = x) %>%
build_tree(string = ., angle = 15) %>%
plot_tree()+
labs(title = paste0('n = ', x))
})
wrap_plots(trees_n, nrow = 2, heights = c(1,1))
Below are some other rules for simulating plants with different morphologies.
<- data.frame(inp = c("0", "1"),
alternate_bush_rules out = c("1[+1][--(0)]+1-1[+++(0)]-(0)", "1"), stringsAsFactors = FALSE)
<- iterate_lsystem(init = "0", rules = alternate_bush_rules, n = 6)
tree_string <- build_tree(string = tree_string, angle = 10) %>%
tree1 plot_tree()+
labs(title = 'alternate tree')
<- data.frame(inp = c("0", "1"),
arrow_weed_rules out = c("1[+(0)][-(0)](10)", "1"), stringsAsFactors = FALSE)
<- iterate_lsystem(init = "0", rules = arrow_weed_rules, n = 6)
tree_string <- build_tree(string = tree_string, angle = 30) %>%
tree2 plot_tree()+
labs(title = 'arrow weed')
<- data.frame(inp = c("0", "1"),
twiggy_weed_rules out = c("1[-(0)]1[-(0)]+(0)", "1"), stringsAsFactors = FALSE)
<- iterate_lsystem(init = "0", rules = twiggy_weed_rules, n = 6)
tree_string <- build_tree(string = tree_string, angle = 25) %>%
tree3 plot_tree()+
labs(title = 'twiggy weed')
+ tree2 + tree3 tree1
The fractalforest package has some predefined models for constructing
fractal trees from L-system rules. These models can be accessed from the
fractal_tree_model
function. The function takes a mandatory
argument (tree_model
) and an optional one
(n_iter
) that controls the number of iterations for string
construction.
There are 10 pre-implemented tree templates, as follows (default
n_iter
between parentheses):
-1 or “binary_tree” (6);
-2 or “alternate_tree” (5);
-3 or “arrow_weed” (5);
-4 or “twiggy_weed” (5);
-5 or “stochastic_fuzzy_weed” (4);
-6 or “crooked_binary_tree” (6);
-7 or “crooked_alternate_tree” (5);
-8 or “crooked_arrow_weed” (5);
-9 or “crooked_twiggy_weed” (5);
-10 or “crooked_stochastic_fuzzy_weed” (4).
fractal_tree_model(5) %>%
build_tree() %>%
plot_tree()
The crooked models add random tortuosity to the tree models. For this to
take effect, it is necessary to set the
randomness = TRUE
argument in the build_tree
function.
All predefined tree models are presented below.
build_tree
functionThe purpose of this function is to build a data frame that contains
the coordinate matrix and some other information about the plant, such
as the differentiation between branches and leaves and the diameters
along the branches.
The h_reduction
parameter in the build_tree
function, controls the reduction factor of the length.
<- build_tree(string = tree_string, angle = 15, h_reduction = .7) %>%
tree1 plot_tree()+
labs(title = 'h_reduction = .7')
<- build_tree(string = tree_string, angle = 15) %>%
tree2 plot_tree()+
labs(title = 'h_reduction = .61803 (default)')
<- build_tree(string = tree_string, angle = 15, h_reduction = .5) %>%
tree3 plot_tree()+
labs(title = 'h_reduction = .5')
+ tree2 + tree3 tree1
The randomness
argument, as the name suggests, allows
one to apply randomness to the angles and lengths of the plant. It must
be set to TRUE
if its effects are desired The amount of
randomness can be controlled by the angle_cv
and
length_cv
arguments, which define the angle and length
variation coefficients, respectively. By default, these two arguments
are set to 0.1,
<- build_tree(string = tree_string, angle = 15, randomness = TRUE) %>%
tree1 plot_tree()+
labs(title = 'length_cv = .1 (default)')
<- build_tree(string = tree_string, angle = 15, randomness = TRUE, length_cv = .5) %>%
tree2 plot_tree()+
labs(title = 'length_cv = .5')
<- build_tree(string = tree_string, angle = 15, randomness = TRUE) %>%
tree3 plot_tree()+
labs(title = 'angle_cv = .1 (default)')
<- build_tree(string = tree_string, angle = 15, randomness = TRUE, angle_cv = .5) %>%
tree4 plot_tree()+
labs(title = 'angle_cv = .5')
+ tree2) / (tree3 + tree4) (tree1
It’s possible to set the plant height setting the height
parameter in the build_tree
function. It will affect the
resulting coordinates in the output.
To visualize the y axis with the height measure, ggplot2
functions can be used together with plot_tree
function.
<- build_tree(string = tree_string, angle = 15, height = 10)
tree plot_tree(tree)+
labs(x = '', y = 'Height (m)')+
theme_bw()
As well as the height
, in the build_tree
function it is possible to define the diameter
of branches,
whose reduction is defined by the parentheses in the rules declared in
the iterate_lsystem
function, in the same way as lengths.
The argument d_reduction
controls the reduction factor for
the diameters.
The density of leaves in the tree crown can be customized by the
leaf_size
argument.
<- build_tree(string = tree_string, angle = 15, height = 10, diameter = 20) %>%
p1 plot_tree(d_col = diameter)+
labs(title = 'leaf_size = NULL (default)')
<- build_tree(string = tree_string, angle = 15, height = 10, diameter = 20, leaf_size = 10) %>%
p2 plot_tree(d_col = diameter,)+
labs(title = 'leaf_size = 10')
<- build_tree(string = tree_string, angle = 15, height = 10, diameter = 20, leaf_size = 20) %>%
p3 plot_tree(d_col = diameter)+
labs(title = 'leaf_size = 20')
+ p2 + p3 p1
plot_tree
functionThis function was implemented on top of ggplot2
and for
this reason it can be used together with several functions of the
package.
To visualize the diameters along the plant, the diameter column must be
declared in the d_col
argument.
<- build_tree(string = tree_string, angle = 15, height = 5, diameter = 7, d_reduction = .7) %>%
tree1 plot_tree(d_col = diameter)+
labs(title = 'd_reduction = .7')
<- build_tree(string = tree_string, angle = 15, height = 5, diameter = 7) %>%
tree2 plot_tree(d_col = diameter)+
labs(title = 'd_reduction = .61803 (default)')
<- build_tree(string = tree_string, angle = 15, height = 5, diameter = 7, d_reduction = .5) %>%
tree3 plot_tree(d_col = diameter)+
labs(title = 'd_reduction = .5')
+ tree2 + tree3 tree1
Colors can be used to differentiate leaves and branches, by declaring
the leaf_color
and branch_color
arguments. The
build_tree
function identifies as leaves all the branches
positioned at the ends of the plant. This information is stored in the
“type” column, which can be used to assign colors.
library(patchwork)
<- iterate_lsystem(init = "0", rules = binary_tree_rules, n = 10)
tree_string <- build_tree(string = tree_string, angle = 15, height = 10, diameter = 20)
tree
plot_tree(tree, d_col = diameter, branch_color = 'lightsalmon4', leaf_color = 'darkgreen')