I have a df
that contains coordinates to create a square:
library(ggplot2)
df = data.frame(xmin = 1, xmax = 3, ymin = 10, ymax = 15)
ggplot(df)
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), fill = "green")
Now, I want to have a function, when it is given df
, it adds new rows to the df
, with 5 scaled versions of the original square, showing like this:
This means, the area of the green coloured squares in the new square(s) corresponds to the 5/9 of the original square.
I also want to make it recursively, so that, given the df
with scaled version (5 squares, like in the second image) it gives:
and so on.
CodePudding user response:
Using a recursive approach you could do:
square5 <- function(xmin, xmax, ymin, ymax) {
x <- data.frame(
xmin = c(0, rep(1/3, 3), 2/3),
xmax = c(0, rep(1/3, 3), 2/3) 1/ 3,
ymin = c(1/3, 0, 1/3, 2/3, 1/3),
ymax = c(1/3, 0, 1/3, 2/3, 1/3) 1/ 3
)
x[c("xmin", "xmax")] <- lapply(x[c("xmin", "xmax")], scales::rescale, to = c(xmin, xmax), from = c(0, 1))
x[c("ymin", "ymax")] <- lapply(x[c("ymin", "ymax")], scales::rescale, to = c(ymin, ymax), from = c(0, 1))
return(x)
}
df = data.frame(xmin = 1, xmax = 3, ymin = 10, ymax = 15)
df1 <- purrr::reduce(seq(5), function(x, n) purrr::pmap_df(x, square5), .init = df)
library(ggplot2)
ggplot(df1)
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), fill = "green", color = "darkgreen", size = .5)
CodePudding user response:
With these three functions:
generate_rects <- function(x1, x2, y1, y2, depth = 1) {
wid <- x2 - x1
hgt <- y2 - y1
data.frame(xmin = x1 c(0, wid/3, wid/3, wid/3, wid * 2/3),
xmax = x2 - c(2/3 * wid, wid/3, wid/3, wid/3, 0),
ymin = y1 c(hgt/3, 0, hgt/3, hgt * 2/3, hgt/3),
ymax = y2 - c(hgt/3, hgt * 2/3, hgt/3, 0, hgt/3),
depth = depth 1)
}
expand_rects <- function(df) {
d <- max(df$depth)
rbind(df, do.call(rbind,
apply(df[which(df$depth == d), ], 1, function(x) {
generate_rects(x[1], x[2], x[3], x[4], d)
})))
}
branch_rects <- function(df, depth) {
while(max(df$depth) < depth) df <- expand_rects(df)
df[df$depth == depth,]
}
We can plot any level of branching we want (in practice more than 8 levels of branching is difficult to see and takes too long to calculate), but it is extremely straightforward to use
Depth 2
df = data.frame(xmin = 1, xmax = 3, ymin = 10, ymax = 15, depth = 1)
ggplot(branch_rects(df, 2))
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
fill = "green", color = "green4")
Depth 3
ggplot(branch_rects(df, 3))
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
fill = "green", color = "green4")
Depth 4
ggplot(branch_rects(df, 4))
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
fill = "green", color = "green4")
Depth 8
ggplot(branch_rects(df, 8))
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
fill = "green", color = "green4")
CodePudding user response:
I inserted a column scale
that indicates the scaling level:
library(data.table) # mostly for rbindlist
fScale <- function(dt) {
dt2 <- dt[scale == last(dt$scale)]
xscale <- (dt2$xmax[1] - dt2$xmin[1])/3
yscale <- (dt2$ymax[1] - dt2$ymin[1])/3
xmin <- rep(dt2$xmin, each = 5) c(0, rep(xscale, 3), 2*xscale)
ymin <- rep(dt2$ymin, each = 5) c(yscale, 0, yscale, 2*yscale, yscale)
rbindlist(
list(
dt,
data.table(
scale = dt2$scale[1] 1,
xmin = xmin,
xmax = xmin xscale,
ymin = ymin,
ymax = ymin yscale
)
)
)
}
df <- data.table(scale = 1, xmin = 1, xmax = 3, ymin = 10, ymax = 15)
for (i in 1:3) print(df <- fScale(df))
#> scale xmin xmax ymin ymax
#> 1: 1 1.000000 3.000000 10.00000 15.00000
#> 2: 2 1.000000 1.666667 11.66667 13.33333
#> 3: 2 1.666667 2.333333 10.00000 11.66667
#> 4: 2 1.666667 2.333333 11.66667 13.33333
#> 5: 2 1.666667 2.333333 13.33333 15.00000
#> 6: 2 2.333333 3.000000 11.66667 13.33333
#> scale xmin xmax ymin ymax
#> 1: 1 1.000000 3.000000 10.00000 15.00000
#> 2: 2 1.000000 1.666667 11.66667 13.33333
#> 3: 2 1.666667 2.333333 10.00000 11.66667
#> 4: 2 1.666667 2.333333 11.66667 13.33333
#> 5: 2 1.666667 2.333333 13.33333 15.00000
#> 6: 2 2.333333 3.000000 11.66667 13.33333
#> 7: 3 1.000000 1.222222 12.22222 12.77778
#> 8: 3 1.222222 1.444444 11.66667 12.22222
#> 9: 3 1.222222 1.444444 12.22222 12.77778
#> 10: 3 1.222222 1.444444 12.77778 13.33333
#> 11: 3 1.444444 1.666667 12.22222 12.77778
#> 12: 3 1.666667 1.888889 10.55556 11.11111
#> 13: 3 1.888889 2.111111 10.00000 10.55556
#> 14: 3 1.888889 2.111111 10.55556 11.11111
#> 15: 3 1.888889 2.111111 11.11111 11.66667
#> 16: 3 2.111111 2.333333 10.55556 11.11111
#> 17: 3 1.666667 1.888889 12.22222 12.77778
#> 18: 3 1.888889 2.111111 11.66667 12.22222
#> 19: 3 1.888889 2.111111 12.22222 12.77778
#> 20: 3 1.888889 2.111111 12.77778 13.33333
#> 21: 3 2.111111 2.333333 12.22222 12.77778
#> 22: 3 1.666667 1.888889 13.88889 14.44444
#> 23: 3 1.888889 2.111111 13.33333 13.88889
#> 24: 3 1.888889 2.111111 13.88889 14.44444
#> 25: 3 1.888889 2.111111 14.44444 15.00000
#> 26: 3 2.111111 2.333333 13.88889 14.44444
#> 27: 3 2.333333 2.555556 12.22222 12.77778
#> 28: 3 2.555556 2.777778 11.66667 12.22222
#> 29: 3 2.555556 2.777778 12.22222 12.77778
#> 30: 3 2.555556 2.777778 12.77778 13.33333
#> 31: 3 2.777778 3.000000 12.22222 12.77778
#> scale xmin xmax ymin ymax
#> scale xmin xmax ymin ymax
#> 1: 1 1.000000 3.000000 10.00000 15.00000
#> 2: 2 1.000000 1.666667 11.66667 13.33333
#> 3: 2 1.666667 2.333333 10.00000 11.66667
#> 4: 2 1.666667 2.333333 11.66667 13.33333
#> 5: 2 1.666667 2.333333 13.33333 15.00000
#> ---
#> 152: 4 2.777778 2.851852 12.40741 12.59259
#> 153: 4 2.851852 2.925926 12.22222 12.40741
#> 154: 4 2.851852 2.925926 12.40741 12.59259
#> 155: 4 2.851852 2.925926 12.59259 12.77778
#> 156: 4 2.925926 3.000000 12.40741 12.59259