Not the cleanest solution, but it works.
First we initiate an empty list.
Then we create a sequence of lambda values, one for each axis, that is used to create a weighted average between two points on that scale (namely, between 0 and 1). In this example, there are 101 lambdas per axis, creating 101^2 iterations.
We then check if the coordinate generated lies inside the triangle with sp::point.in.polygon
. Note that this method applies to more shapes than just a triangle, so this solution is general for multiple shapes.
If the coordinate generated from the lambda values lies inside the polygon, then we calculate the distances from this coordinate to every coordinate in df
. Note that we take sqrt(2)
minus the distance because the lower the distance, the more weight that point should carry. Hence, we take the maximum distance (sqrt(2)
) and subtract the distance. sqrt(2)
is not a definite number that must be set, but it does prevent negative values. Other values provide other results.
In the next step, we scale the distances so that they sum to 1. That allows us to create a weighted average, which is defined in amount
.
After running the loops, we bind the lists into a data frame and create the plot.
To ensure that the edges are smooth, we make somewhat thick white lines that have rounded edges.
gradient_list <- list()
for (lambda_x in seq(0,1,by=0.01)) {
for (lambda_y in seq(0,1,by=0.01)) {
x_value <- lambda_x*0 + (1-lambda_x)*1
y_value <- lambda_y*0 + (1-lambda_y)*1
inside_polygon <- sp::point.in.polygon(x_value, y_value, triangle_lines$X, triangle_lines$Y) %>% as.logical()
if (inside_polygon) {
point <- c(x_value, y_value)
distances <- sqrt(2) - sqrt((scatters$x - point[1])^2 + (scatters$y - point[2])^2)
weighted_distances <- distances/sum(distances)
amount <- sum(weighted_distances * df$z)
gradient_list <- append(gradient_list, list(c(point, amount)))
}
}
}
gradient_df <- do.call(rbind, gradient_list) %>% as.data.frame()
colnames(gradient_df) <- c("x","y","amount")
ggplot(gradient_df, aes(x=x, y=y)) +
geom_point(aes(colour = amount), size=2) +
theme_void() +
geom_line(data=triangle_lines, aes(X, Y, group = grp), size=3, colour="white", lineend="round")