在R和ggplot2中,绘制linessegment很容易,但绘制射线更难.我想知道是否存在在两个点之间绘制射线的解决方案;一个定义为原点(下面代码显示的图形中的红点),光线通过第二个点(下面代码显示的图形中的黑点).以下是我为此编写的一段代码:

require(dplyr)
require(ggplot)

set.seed(123)
n <- 4

dat <-
  data.frame(
  X = rnorm(n),
  Y = rnorm(n))

centroid <- 
  dat %>%
  dplyr::summarise(across(c(X,Y), mean))

ggplot(data = dat, aes(X,Y)) +
  geom_point() +
  geom_point(data = centroid, aes(X, Y), col = "red") +
  geom_segment(x = centroid$X, y = centroid$Y,
               xend = dat$X, yend = dat$Y)

go 年也开设了一个类似的话题:ggplot - how to draw rays?个,但它并不完全符合我的担忧,因为我想避免三角学,我想让这个问题自动化.

我们非常欢迎任何帮助、建议或替代解决方案.

推荐答案

你可以编写你自己的geom,就像他们在另一个问题中所做的那样.这是另一个可能的解决方案

geom_ray <- function(mapping = NULL, data = NULL,
                        ...,
                     na.rm = FALSE,
                     show.legend = NA) {
  
  layer(
    data = data,
    mapping = mapping,
    stat = StatIdentity,
    geom = GeomRay,
    position = PositionIdentity,
    show.legend = show.legend,
    inherit.aes = FALSE,
    params = rlang::list2(
      na.rm = na.rm,
      ...
    )
  )
}

GeomRay <- ggproto("GeomRay", Geom,
    draw_panel = function(data, panel_params, coord, lineend = "butt") {
      ranges <- coord$backtransform_range(panel_params)
      
      if (coord$clip == "on" && coord$is_linear()) {
        # Ensure the line extends well outside the panel to avoid visible line
        # ending for thick lines
        ranges$x <- ranges$x + c(-1, 1) * diff(ranges$x)
      }

      slope <- (data$towardy - data$y)/(data$towardx - data$x)
      intercept <- data$y - data$x*slope
      data$x    <- data$x
      data$y    <- data$y
      data$xend    <- ifelse(data$towardx > data$x, 
                             ranges$x[2],
                             ranges$x[1]
      )
      data$yend <- ifelse(data$towardx > data$x, 
                          ranges$x[2] * slope + intercept,
                          ranges$x[1] * slope + intercept
                          )
      
      GeomSegment$draw_panel(ggplot2:::unique0(data), panel_params, coord, lineend = lineend)
    },
    
    default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA),
    required_aes = c("x", "y", "towardx", "towardy"),
    
    draw_key = draw_key_abline,
    
    rename_size = TRUE,
    
    check_constant_aes = FALSE
)

这个代码基本上直接从ggplot::geom_abline代码改编而来.

在此设置中,xy是希望光线开始的位置,然后towardxtowardy是希望光线指向的方向.因此,对于您的数据,您可以这样使用它

ggplot(data = dat, aes(X,Y)) +
  geom_point() +
  geom_point(data = centroid, aes(X, Y), col = "red") +
  geom_ray(x = centroid$X, y = centroid$Y,
               aes(towardx = X, towardy = Y))

which produces enter image description here

R相关问答推荐

使用gggplot 2在R中重新调整面板和y轴文本大小

R形式的一维数字线/箱形图样式图表

编码变量a、b、c以匹配来自另一个数据点的变量x

更改绘图上的x轴断点,而不影响风险?

如何从R中的字符串元素中减go 一个数字?

我不能在docker中加载sf

bslib::card_header中的shine::downloadButton,图标而不是文本

在连续尺度上转置标签[瀑布图,R]

根据文本字符串中的值粘贴新列

将文件保存到新文件夹时,切换r设置以不必创建目录

打印XTS对象

ComplexHEAT:使用COLUMN_SPLIT时忽略COLUMN_ORDER

正则表达式在第二个管道和第二个T之后拆分R中的列

在R中使用列表(作为tibble列)进行向量化?

在ggplot2上从多个数据框创建复杂的自定义图形

R中治疗序列的相对时间指数

如何显示准确的p值而不是<;0.001*?

为什么不能使用lApply在包装函数中调用子集

如何在R中创建这些列?

使用nls()函数的非线性模型的半正态图