Generate the data specifying a flametree
flametree_grow( seed = 286, time = 6, scale = c(0.6, 0.8, 0.9), angle = c(-10, 10, 20), split = 2, trees = 1, seg_col = spark_linear(tree = 2, time = 1), seg_wid = spark_decay(time = 0.3, multiplier = 5, constant = 0.1), shift_x = spark_random(multiplier = 3), shift_y = spark_nothing() )
seed | Integer seed for the random number generator |
---|---|
time | Number of generations to run the iterative process |
scale | Vector of possible values for the "size rescaling" at each iteration |
angle | Vector of possible angle changes (in degrees) at each iteration |
split | Number of splits at each time point |
trees | Number of trees to generate |
seg_col | Spark function to control the segment colour |
seg_wid | Spark function to control the segment width |
shift_x | Spark function to control horizontal jitter |
shift_y | Spark function to control vertical jitter |
The output of flametree_grow()
` is a tibble with the following
columns: coord_x
, coord_y
, id_tree
, id_time
,
id_path
, id_leaf
, id_pathtree
, id_step
,
seg_deg
, seg_len
, seg_col
, and seg_wid
. Each
row in the tibble specifies a single point: every curved segment is defined
by three such rows.
The two "coord" columns are numeric variables that specify the location of
the point itself. The "id" columns are used as indicators of various kinds.
The id_tree
column contains numbers specifying which tree each point
belongs to, and similarly the id_time
column is a numeric identifier
that specifies the time point at which the point was generated (i.e., the
iteration of the generative process). The id_step
column contains
a number (0, 1, or 2) indicating whether the point is the first point, the
midpoint, or the end point of the relevant curved segment in a tree. In
addition, there are two identifier columns used to denote the segments
themselves. The id_path
column is numeric, and assigns value 1 to
the "first" segment (i.e., the lowest part of the tree trunk) for every
tree, with values increasing numerically for each subsequent segment. Values
for id_path
will uniquely identify a segment within a tree, but when
multiple trees are generated there will be multiple segments that have the
same id_path
value. If a unique identifier across trees is needed,
use the id_pathtree
column, which is a character vector constructed
by pasting the id_path
and id_tree
values into a string, with
an underscore as the separator character.
In addition to the two coordinate columns and the six identifier columns,
the data generated by flametree_grow()
contains four "seg" columns
that are intended to map onto different visual characteristics of a plot.
The seg_deg
column specifies the orientation of the segment, whereas
seg_len
denotes the length of the segment, seg_col
specifies
the colour (as a numeric value that could be interpreted by a palette), and
seg_wid
specifies the width of the segment. Note that this information
use used differently by the flametree_plot()
function, depending on
what style of plot is generated.
Generative art created with flametree is a visualisation of a data
structure created by calling flametree_grow()
. The underlying
algorithm is an iterative branching process: each tree starts out as a single
vertical segment, to which multiple new segments are added at the end of the
first iteration. Over multiple iterations this creates a tree-like structure.
The user can control how this iterative process unfolds. By setting the
seed
argument the random number generator is reset using
set.seed()
. The trees
argument specifies the number of trees
to create using this process, the time
argument specifies how many
iterations of the branching process will be run (at least two), and the
split
argument specifies how many new segments (at least two) will be
created each time abranching occurs.
When a new segment is created, its size and orientation are controlled by the
scale
and angle
arguments. The scale
argument takes a
vector of at least two positive numbers. One of these numbers is selected at
random whenever a new segment is created, and the length of the new segment
is equal to the length of the "parent" segment from which it was created,
multiplied by this scaling factor. The orientation of the new segment is
controlled by the angle argument in an analogous way. Every time a new
segment is generated, one of these angles (interpreted in degrees, not
radians) is selected at random. The orientation of the new segment is equal
to the orientation of the parent segment plus the sampled angle. Like the
scale
argument, angle
must contain at least two values.
The remaining arguments (seg_col
, seg_wid
, shift_x
,
and shift_y
) all take functions as their input, and are used to
control how the colours (seg_col
) and width (seg_wid
) of the
segments are created, as well as the horizontal (shift_x
) and
vertical (shift_y
) displacement of the trees are generated. Functions
passed to these arguments take four inputs: coord_x
, coord_y
,
id_tree
, and id_time
. Any function that takes
these variables as input can be used for this purpose. However, as a
convenience, four "spark" functions are provided that can be used to create
functions that are suitable for this purpose: spark_linear()
,
spark_decay()
, spark_random()
, and spark_nothing()
.
These functions are documented in their own help files. To give an example,
the default behaviour of flametree_grow()
adds a random horizontal
displacement to each tree to give the impression of multiple trees growing
side by side. To suppress this horizontal displacement, set
shift_x = spark_nothing()
.
# flametree data structure with default parameters flametree_grow() #> # A tibble: 381 × 12 #> coord_x coord_y id_tree id_time id_path id_leaf id_pathtree id_step seg_deg #> <dbl> <dbl> <int> <int> <int> <lgl> <chr> <int> <dbl> #> 1 -1.11 0 1 1 1 FALSE 1_1 0 90 #> 2 -1.11 0.5 1 1 1 FALSE 1_1 1 90 #> 3 -1.11 1 1 1 1 FALSE 1_1 2 90 #> 4 -1.11 1 1 2 2 FALSE 1_2 0 80 #> 5 -1.11 1.3 1 2 2 FALSE 1_2 1 80 #> 6 -1.00 1.59 1 2 2 FALSE 1_2 2 80 #> 7 -1.11 1 1 2 3 FALSE 1_3 0 100 #> 8 -1.11 1.45 1 2 3 FALSE 1_3 1 100 #> 9 -1.26 1.89 1 2 3 FALSE 1_3 2 100 #> 10 -1.00 1.59 1 3 4 FALSE 1_4 0 90 #> # … with 371 more rows, and 3 more variables: seg_len <dbl>, seg_col <dbl>, #> # seg_wid <dbl> # setting time = 10 runs the generative process # longer resulting in a table with more rows flametree_grow(time = 10) #> # A tibble: 6,141 × 12 #> coord_x coord_y id_tree id_time id_path id_leaf id_pathtree id_step seg_deg #> <dbl> <dbl> <int> <int> <int> <lgl> <chr> <int> <dbl> #> 1 1.22 0 1 1 1 FALSE 1_1 0 90 #> 2 1.22 0.5 1 1 1 FALSE 1_1 1 90 #> 3 1.22 1 1 1 1 FALSE 1_1 2 90 #> 4 1.22 1 1 2 2 FALSE 1_2 0 80 #> 5 1.22 1.3 1 2 2 FALSE 1_2 1 80 #> 6 1.33 1.59 1 2 2 FALSE 1_2 2 80 #> 7 1.22 1 1 2 3 FALSE 1_3 0 100 #> 8 1.22 1.45 1 2 3 FALSE 1_3 1 100 #> 9 1.07 1.89 1 2 3 FALSE 1_3 2 100 #> 10 1.33 1.59 1 3 4 FALSE 1_4 0 90 #> # … with 6,131 more rows, and 3 more variables: seg_len <dbl>, seg_col <dbl>, #> # seg_wid <dbl> # default behaviour is to randomly displace trees # by random horizontal perturbation: to switch this # off use the spark_nothing() function flametree_grow(shift_x = spark_nothing()) #> # A tibble: 381 × 12 #> coord_x coord_y id_tree id_time id_path id_leaf id_pathtree id_step seg_deg #> <dbl> <dbl> <int> <int> <int> <lgl> <chr> <int> <dbl> #> 1 0 0 1 1 1 FALSE 1_1 0 90 #> 2 0 0.5 1 1 1 FALSE 1_1 1 90 #> 3 0 1 1 1 1 FALSE 1_1 2 90 #> 4 0 1 1 2 2 FALSE 1_2 0 80 #> 5 1.84e-17 1.3 1 2 2 FALSE 1_2 1 80 #> 6 1.04e- 1 1.59 1 2 2 FALSE 1_2 2 80 #> 7 0 1 1 2 3 FALSE 1_3 0 100 #> 8 2.76e-17 1.45 1 2 3 FALSE 1_3 1 100 #> 9 -1.56e- 1 1.89 1 2 3 FALSE 1_3 2 100 #> 10 1.04e- 1 1.59 1 3 4 FALSE 1_4 0 90 #> # … with 371 more rows, and 3 more variables: seg_len <dbl>, seg_col <dbl>, #> # seg_wid <dbl>