I have a data.frame
containing 4 points, which creates a triangle when connected using geom_path
:
library(ggplot2)
triangle = data.frame(x = c(0, 0.5, 1, 0),
y = c(0, 0.5, 0, 0))
ggplot(triangle, aes(x, y))
geom_path()
Now, I want to create a new data.frame
(based on triangle
), that has 4 points (e.g. xmin
, xmax
, ymin
, ymax
) that creates squares from the sides of the triangle (hence, this data.frame
will have 3 rows (for each square) and 4 columns (for each point).
Here is an example:
Is it possible to do it without hard-coding the sides of the squares?
CodePudding user response:
Since the squares will be at an angle, you probably need the output to be in terms of x, y co-ordinates of the vertices. This just requires a bit of trig. The following function takes a vector of x, y points representing a closed triangle and returns a data frame of the vertices of the squares on each side:
make_squares <- function(x, y) {
x1 <- x[-4]
x2 <- x[-1]
xdiff <- (x2 - x1)
y1 <- y[-4]
y2 <- y[-1]
ydiff <- (y2 - y1)
lengths <- sqrt(xdiff^2 ydiff^2)
angles <- atan2(ydiff, xdiff)
x3 <- x2 - sin(angles) * lengths
x4 <- x1 - sin(angles) * lengths
y3 <- y2 cos(angles) * lengths
y4 <- y1 cos(angles) * lengths
df <- data.frame(x = round(c(x1, x2, x3, x4, x1), 3),
y = round(c(y1, y2, y3, y4, y1), 3),
square = rep(1:3, 5))
`row.names<-`(df[order(df$square),], NULL)
}
The output looks like this:
make_squares(triangle$x, triangle$y)
#> x y square
#> 1 0.0 0.0 1
#> 2 0.5 0.5 1
#> 3 0.0 1.0 1
#> 4 -0.5 0.5 1
#> 5 0.0 0.0 1
#> 6 0.5 0.5 2
#> 7 1.0 0.0 2
#> 8 1.5 0.5 2
#> 9 1.0 1.0 2
#> 10 0.5 0.5 2
#> 11 1.0 0.0 3
#> 12 0.0 0.0 3
#> 13 0.0 -1.0 3
#> 14 1.0 -1.0 3
#> 15 1.0 0.0 3
And you can use it in your plot like this:
ggplot(triangle, aes(x, y))
geom_path()
geom_polygon(data = make_squares(triangle$x, triangle$y),
aes(group = square), fill = "green4", color = "black")
coord_equal()