You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取ggplot中stat_ellipse椭圆最远点坐标并绘制过该点直线?

问题:如何绘制经过ggplot椭圆最远两点的直线

我有一段用stat_ellipse绘制椭圆的代码:

df %>% 
  select(starts_with("WindSpeed"), starts_with("Humidity")) %>%
  na.omit() %>%
  mutate(WindSpeed = (WindSpeed9am+WindSpeed3pm)/2,
         Humidity = (Humidity9am+Humidity3pm)/2) %>%
  ggplot(aes(x = WindSpeed, y = Humidity)) +
  geom_point(alpha = .4) +
  stat_ellipse(size = 2, color = "blue") + 
  geom_abline(intercept = 83, slope = -1.4, size = 2, color = "blue")

运行后得到的图像:
原代码输出图像

我想绘制一条经过该椭圆上最远两点的直线,该怎么实现?


编辑:尝试过的方法但结果不符合预期

我尝试用car::dataEllipse获取椭圆点,代码如下:

k <- df %>% 
  select(starts_with("WindSpeed"), starts_with("Humidity")) %>%
  na.omit() %>%
  mutate(WindSpeed = (WindSpeed9am+WindSpeed3pm)/2,
         Humidity = (Humidity9am+Humidity3pm)/2) %>%
  select(WindSpeed, Humidity) %>%
  as.matrix() %>%
  car::dataEllipse(draw = F)

k <- k$`0.5` %>% data.frame()
distances <- dist(k)
max_distance_index <- which.max(distances)
distance_matrix <- as.matrix(distances)
row_index <- row(distance_matrix)[max_distance_index]
col_index <- col(distance_matrix)[max_distance_index]
farthest_points <- k[c(row_index, col_index), ]

a <- farthest_points[1,]
b <- farthest_points[2,]
m <- (b[2]-a[2])/(b[1]-a[1])
int <- a[2]-m*a[1]

把计算出的斜率m和截距int加到ggplot后,结果不符合预期:
尝试后的结果图像


解决方案

问题出在两个椭圆的参数不匹配:stat_ellipse默认绘制的是置信度为95%(即level=0.95)的椭圆,而你用car::dataEllipse取的是k$0.5``,也就是置信度50%的椭圆,两者完全不是同一个椭圆,自然计算出的直线不对。

另外,直接计算椭圆点对的距离效率较低,也可以通过椭圆的几何性质直接找到长轴端点——这是椭圆上距离最远的两个点。

正确步骤

方法1:对齐car::dataEllipse的置信度

修改代码,把k$0.5换成`k$`0.95,确保和stat_ellipse的置信度一致:

# 数据预处理和椭圆点提取
k <- df %>% 
  select(starts_with("WindSpeed"), starts_with("Humidity")) %>%
  na.omit() %>%
  mutate(WindSpeed = (WindSpeed9am+WindSpeed3pm)/2,
         Humidity = (Humidity9am+Humidity3pm)/2) %>%
  select(WindSpeed, Humidity) %>%
  as.matrix() %>%
  car::dataEllipse(draw = F, levels=0.95)  # 指定与stat_ellipse一致的置信度

k <- k$`0.95` %>% data.frame()
distances <- dist(k)
max_distance_index <- which.max(distances)
distance_matrix <- as.matrix(distances)
row_index <- row(distance_matrix)[max_distance_index]
col_index <- col(distance_matrix)[max_distance_index]
farthest_points <- k[c(row_index, col_index), ]

# 计算直线参数
a <- farthest_points[1,]
b <- farthest_points[2,]
m <- (b[2]-a[2])/(b[1]-a[1])
int <- a[2]-m*a[1]

# 绘图
df %>% 
  select(starts_with("WindSpeed"), starts_with("Humidity")) %>%
  na.omit() %>%
  mutate(WindSpeed = (WindSpeed9am+WindSpeed3pm)/2,
         Humidity = (Humidity9am+Humidity3pm)/2) %>%
  ggplot(aes(x = WindSpeed, y = Humidity)) +
  geom_point(alpha = .4) +
  stat_ellipse(size = 2, color = "blue") + 
  geom_abline(intercept = int, slope = m, size = 2, color = "red")

方法2:通过几何性质直接计算(更高效)

椭圆的长轴是数据协方差矩阵最大特征值对应的特征向量方向,长轴端点就是均值加减(最大特征值的平方根 * 对应特征向量)乘以椭圆的缩放系数(对应置信度的卡方分位数)。

library(ggplot2)
library(dplyr)

# 预处理数据
data_processed <- df %>% 
  select(starts_with("WindSpeed"), starts_with("Humidity")) %>%
  na.omit() %>%
  mutate(WindSpeed = (WindSpeed9am+WindSpeed3pm)/2,
         Humidity = (Humidity9am+Humidity3pm)/2) %>%
  select(WindSpeed, Humidity)

# 计算均值和协方差矩阵
mu <- colMeans(data_processed)
cov_mat <- cov(data_processed)

# 特征值分解,找到长轴方向
eig <- eigen(cov_mat)
max_eig_val <- max(eig$values)
max_eig_vec <- eig$vectors[, which.max(eig$values)]

# 对应95%置信度的缩放系数(自由度2的卡方分布0.95分位数的平方根)
scale_factor <- sqrt(qchisq(0.95, df=2))

# 计算长轴的两个端点(最远两点)
point1 <- mu + scale_factor * sqrt(max_eig_val) * max_eig_vec
point2 <- mu - scale_factor * sqrt(max_eig_val) * max_eig_vec

# 计算直线参数
m <- (point2[2] - point1[2])/(point2[1] - point1[1])
int <- point1[2] - m * point1[1]

# 绘图
ggplot(data_processed, aes(x = WindSpeed, y = Humidity)) +
  geom_point(alpha = .4) +
  stat_ellipse(size = 2, color = "blue") + 
  geom_abline(intercept = int, slope = m, size = 2, color = "red") +
  # 可选:标记最远两点
  geom_point(aes(x=point1[1], y=point1[2]), color="red", size=3) +
  geom_point(aes(x=point2[1], y=point2[2]), color="red", size=3)

错误原因总结

stat_ellipse默认level=0.95,而car::dataEllipse默认生成0.5、0.9、0.95三个置信度的椭圆,你取了0.5的那组点,相当于找的是内部小椭圆的最远点,和图中蓝色大椭圆完全无关,所以直线位置不符合预期。


内容的提问来源于stack exchange,提问作者Rootsyl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 00:22:50