三角形内的热图 [英] Heatmap within a triangle

查看:130
本文介绍了三角形内的热图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下示例:

triangle_lines <- data.frame(
  X   = c(0,0,1,1,0.5,0.5),
  Y   = c(0,0,0,0,1,  1),
  grp = c(1,2,1,3,2,3)
)

df <- 
  matrix(c(c(0.2,0.5,0.8), c(0.3,0.5,0.1), c(1,5,10)), ncol=3) %>%
  as.data.frame()
colnames(df) <- c("x","y", "amount")

ggplot(df, aes(x=x, y=y)) +
  geom_point(aes(colour = amount)) +
  geom_line(data=triangle_lines, aes(X, Y, group = grp)) +
  theme_void() 

我们有三个值: x 坐标, y 坐标和确定散点颜色值的 amount .这些点的间距不相等.

We have three values: the x coordinates, the y coordinates, and amount that decides the colour values of the scatter points. The points are not equally spaced apart.

我还有一个三角形.我试图仅在此三角形内创建一个梯度热图 ,用基于 df $ amount 的热图颜色填充整个三角形.知道如何解决这个问题吗?

Also, I have a triangle. I am attempting to create a gradient heatmap inside this triangle only, filling the entire triangle with heatmap colours based on df$amount. Any idea how to solve this?

P.S.虽然我仅在此处举例说明三个点,但在实际应用中此图将具有数十个或数百个点.

P.S. While I am exemplifying with only three points here, this plot will have tens or hundreds of points in real applications.

推荐答案

不是最干净的解决方案,但可以.

Not the cleanest solution, but it works.

首先,我们启动一个空列表.

First we initiate an empty list.

然后,我们创建一个lambda值序列,每个轴一个,用于在该比例尺上的两个点之间(即介于0和1之间)创建加权平均值.在此示例中,每个轴有101个lambda,创建了101 ^ 2次迭代.

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.

然后我们用 sp :: point.in.polygon 检查生成的坐标是否在三角形内.请注意,此方法不仅适用于三角形,还适用于更多形状,因此该解决方案通常适用于多种形状.

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.

如果从lambda值生成的坐标位于多边形内部,则我们将计算从该坐标到 df 中每个坐标的距离.请注意,我们将 sqrt(2)减去距离,因为距离越小,该点应承受的重量就越大.因此,我们采用最大距离( sqrt(2))并减去该距离. sqrt(2)不是必须设置的确定数字,但是它确实可以防止出现负值.其他值可以提供其他结果.

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.

下一步,我们对距离进行缩放,以使它们的总和为1.这允许我们创建一个加权平均值,该平均值在 amount 中定义.

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((df$x - point[1])^2 + (df$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")

这篇关于三角形内的热图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆