Created
July 24, 2018 17:12
-
-
Save AdamSpannbauer/284f2376a5458557d509e2aefe6096c6 to your computer and use it in GitHub Desktop.
Create/Draw a Binary Fractal Tree with plotly in R
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Create/Draw a Binary Fractal Tree | |
library(plotly) | |
# basic strucure for line shape in plotly | |
base_line = list( | |
type = "line", | |
line = list(color = "black"), | |
xref = "x", | |
yref = "y", | |
x0 = NA, | |
x1 = NA, | |
y0 = NA, | |
y1 = NA | |
) | |
# create a plotly line shape given start and end coords | |
create_line = function(p1, p2) { | |
base_line[['x0']] = p1[1] | |
base_line[['y0']] = p1[2] | |
base_line[['x1']] = p2[1] | |
base_line[['y1']] = p2[2] | |
return(base_line) | |
} | |
# create line segment from (0, 0) to (0, len) to be trunk of fractal tree | |
create_trunk = function(len = 1) { | |
l = create_line(c(0, 0), c(0, len)) | |
return(list(points = c(0, len), | |
branches = list(l))) | |
} | |
# creates end point of line segment to satisfy length and | |
# angle inputs from given start coord | |
gen_end_point = function(xy, len = 5, theta = 45) { | |
dy = sin(theta) * len | |
dx = cos(theta) * len | |
newx = xy[1] + dx | |
newy = xy[2] + dy | |
return(c(newx, newy)) | |
} | |
# create a single branch of fractal tree | |
# returns branch endpoint coords and a plotly line shape to represent branch | |
branch = function(xy, angle_in, delta_angle, len) { | |
end_point = gen_end_point(xy, len = len, theta = angle_in + delta_angle) | |
line_shape = create_line(xy, end_point) | |
return(list(points=end_point, branches=list(line_shape))) | |
} | |
# helper function to aggregate branch objects into single branch object | |
collect_branches = function(branch1, branch2) { | |
collected_points = rbind(branch1$points, branch2$points) | |
collected_branches = c(branch1$branches, branch2$branches) | |
return(list(points=collected_points, branches=collected_branches)) | |
} | |
# recursively create fractal tree branches | |
create_branches = function(xy, | |
angle_in = pi / 2, | |
delta_angle = pi / 8, | |
len = 1, | |
min_len = 0.01, | |
len_decay = 0.2) { | |
if (len < min_len) { | |
return(NULL) | |
} else { | |
branch_left = branch(xy, angle_in, delta_angle, len) | |
subranches_left = create_branches(branch_left$points, | |
angle_in = angle_in + delta_angle, | |
delta_angle = delta_angle, | |
len = len * len_decay, | |
min_len = min_len, | |
len_decay = len_decay) | |
branches_left = collect_branches(branch_left, subranches_left) | |
branch_right = branch(xy, angle_in, -delta_angle, len) | |
subranches_right = create_branches(branch_right$points, | |
angle_in = angle_in - delta_angle, | |
delta_angle = delta_angle, | |
len = len * len_decay, | |
min_len = min_len, | |
len_decay = len_decay) | |
branches_right = collect_branches(branch_right, subranches_right) | |
return(collect_branches(branches_left, branches_right)) | |
} | |
} | |
# create and draw binary fractal tree | |
draw_fractal_tree = function(trunk_len=10, | |
delta_angle = pi / 8, | |
len_decay=0.7, | |
min_len=0.25) { | |
trunk = create_trunk(trunk_len) | |
branches = create_branches(trunk$points, | |
delta_angle =delta_angle, | |
len = trunk_len * len_decay, | |
min_len = min_len, | |
len_decay = len_decay) | |
tree = collect_branches(trunk, branches) | |
tree_points_df = as.data.frame(tree$points) | |
names(tree_points_df) = c('x', 'y') | |
null_axis = list( | |
title = '', | |
zeroline = FALSE, | |
showline = FALSE, | |
showticklabels = FALSE, | |
showgrid = FALSE | |
) | |
plot_ly( | |
tree_points_df, | |
x = ~ x, | |
y = ~ y, | |
type = 'scatter', | |
mode = 'markers', | |
color = ~ x, | |
colors = 'Spectral', | |
hoverinfo = "none", | |
showlegend = FALSE | |
) %>% | |
layout(shapes = tree$branches, | |
xaxis = null_axis, | |
yaxis = null_axis) %>% | |
hide_colorbar() %>% | |
config(displayModeBar = FALSE) | |
} | |
# example usage/output | |
draw_fractal_tree(delta_angle = pi / 2) | |
draw_fractal_tree(delta_angle = pi / 4) | |
draw_fractal_tree(delta_angle = pi / 8) | |
draw_fractal_tree(delta_angle = pi / 16) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example output