在ggplot2(R)中使用coord_polar()时在任意两点之间绘制直线 [英] draw straight line between any two point when using coord_polar() in ggplot2 (R)

查看:114
本文介绍了在ggplot2(R)中使用coord_polar()时在任意两点之间绘制直线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个绘图,我使用极坐标.现在,我想使用 geom_segment()使用直箭头向该绘图添加一些注释.但是,当我使用 coord_polar()时,正如预期的那样,这些段也将转换为极坐标系.当然,这是适当的行为,但是我想在绘图中添加一些直角箭头(在笛卡尔意义上).我怎样才能最好地做到这一点.这两个问题让我很接近,但没有到那为止(

  p1 + coord_polar() 

解决方案

恐怕这会比第一次出现时更加痛苦.本质上,您必须为这些段编写一种新的面板绘制方法,而忽略坐标系是否是线性的.为此,您可以基于 GeomSegment $ draw_panel 执行以下操作:

 库(tidyverse)geom_segment_straight<-function(...){层<-geom_segment(...)new_layer<-ggproto(NULL,层)old_geom<-new_layer $ geomgeom<-ggproto(NULL,old_geom,draw_panel = function(data,panel_params,coord,箭头= NULL,arrow.fill = NULL,lineend =对接",linejoin =圆形",na.rm = FALSE){数据<-ggplot2 ::: remove_missing(数据,na.rm = na.rm,c("x","y","xend","yend",线型",尺寸",形状"))如果(ggplot2 ::: empty(data)){返回(zeroGrob())}坐标<-坐标$ transform(数据,panel_params)#xend和yend需要分别转换,因为coord无法理解结束<-transform(data,x = xend,y = yend)结束<-coord $ transform(结束,panel_params)arrow.fill<-如果(!is.null(arrow.fill))arrow.fill else coords $ colourreturn(grid :: segmentsGrob(coords $ x,coords $ y,ends $ x,ends $ y,default.units ="native",gp = grid :: gpar(col = alpha(coords $ colour,coords $ alpha),填充= alpha(arrow.fill,coords $ alpha),lwd = coords $ size * .pt,lty = coords $ linetype,lineend = lineend,linejoin = linejoin),箭头=箭头))})new_layer $ geom<-geom返回(new_layer)} 

然后,您可以像使用其他任何几何图形一样使用它.

  ggplot()+geom_tile(data = df,aes(x = x,y = y,填充= d))+ylim(c(-2,5))+geom_segment_straight(aes(x ="o",y = -1,xend ="z",日币= 3),箭头=箭头(长度=单位(0.2,厘米"))),col ="red",大小= 2)+coord_polar() 

geom_curve()

以下是应用于 geom_curve()的相同技巧:

  geom_curve_polar<-函数(...){层<-geom_curve(...)new_layer<-ggproto(NULL,层)old_geom<-new_layer $ geomgeom<-ggproto(NULL,old_geom,draw_panel = function(data,panel_params,coord,曲率= 0.5,角度= 90,ncp = 5箭头= NULL,arrow.fill = NULL,lineend =对接",linejoin =圆形",na.rm = FALSE){数据<-ggplot2 ::: remove_missing(数据,na.rm = na.rm,c("x","y","xend","yend",线型",尺寸",形状"))如果(ggplot2 ::: empty(data)){返回(zeroGrob())}坐标<-坐标$ transform(数据,panel_params)结束<-transform(data,x = xend,y = yend)结束<-coord $ transform(结束,panel_params)arrow.fill<-如果(!is.null(arrow.fill))arrow.fill else coords $ colour返回(grid :: curveGrob(coords $ x,coords $ y,ends $ x,ends $ y,default.units ="native",gp = grid :: gpar(col = alpha(coords $ colour,coords $ alpha),填充= alpha(arrow.fill,coords $ alpha),lwd = coords $ size * .pt,lty = coords $ linetype,lineend = lineend,linejoin = linejoin),曲率=曲率,角度=角度,ncp = ncp,square = FALSE,squareShape = 1,拐点= FALSE,open = TRUE,箭头=箭头))})new_layer $ geom<-geom返回(new_layer)} 

在将 geom_segment_straight()替换为 geom_curve_polar()后,以上代码产生了以下图:

小注释:这种制作新几何图形的方法是快速而又肮脏的方法.如果计划正确执行此操作,则应分别编写构造函数和ggproto类.

I have a plot for which I use polar coordinates. Now I would like to add some annotations to this plot, using straight arrows using geom_segment(). However, when I use coord_polar(), as expected these segments get transformed to the polar coordinate system too. That is, of course, the appropriate behaviour, but I would like to add some straight arrows (in the cartesian sense) to the plot. How can I best do that. These two questions, got me close, but not there (R: How to combine straight lines of polygon and line segments with polar coordinates? and Add line segments to histogram in ggplot2 with radar coordinates). For the solution for my plot, I cannot use coord_radar instead.

This works without coord_polar, but not with

library(tidyverse)
df <- tibble(x = rep(letters,  each = 5),
             y = rep(1:5, 26),
             d =  rnorm(26 * 5))


p1 <- ggplot() +
  geom_tile(data = df,
            aes(x = x,
                y = y,
                fill = d)) +
  ylim(c(-2, 5)) +
  geom_segment(
    aes(
      x = "o",
      y = -1,
      xend = "z",
      yend = 3
    ),
    arrow = arrow(length = unit(0.2, "cm")),
    col = "red",
    size = 2
  ) 
p1

p1 + coord_polar()

解决方案

This is going to be a bit more of a pain than it might first appear, I'm afraid. Essentially, you'd have to write a new panel drawing method for the segments that ignores whether a coord system is linear or not. To do so, you can do the following, based on GeomSegment$draw_panel:

library(tidyverse)

geom_segment_straight <- function(...) {
  layer <- geom_segment(...)
  new_layer <- ggproto(NULL, layer)
  old_geom <- new_layer$geom
  geom <- ggproto(
    NULL, old_geom,
    draw_panel = function(data, panel_params, coord, 
                          arrow = NULL, arrow.fill = NULL,
                          lineend = "butt", linejoin = "round",
                          na.rm = FALSE) {
      data <- ggplot2:::remove_missing(
        data, na.rm = na.rm, c("x", "y", "xend", "yend", 
                               "linetype", "size", "shape")
      )
      if (ggplot2:::empty(data)) {
        return(zeroGrob())
      }
      coords <- coord$transform(data, panel_params)
      # xend and yend need to be transformed separately, as coord doesn't understand
      ends <- transform(data, x = xend, y = yend)
      ends <- coord$transform(ends, panel_params)
      
      arrow.fill <- if (!is.null(arrow.fill)) arrow.fill else coords$colour
      return(grid::segmentsGrob(
        coords$x, coords$y, ends$x, ends$y,
        default.units = "native", gp = grid::gpar(
          col = alpha(coords$colour, coords$alpha),
          fill = alpha(arrow.fill, coords$alpha),
          lwd = coords$size * .pt,
          lty = coords$linetype,
          lineend = lineend,
          linejoin = linejoin
        ),
        arrow = arrow
      ))
      
    }
  )
  new_layer$geom <- geom
  return(new_layer)
}

Then you can use it like any other geom.

ggplot() +
  geom_tile(data = df,
            aes(x = x,
                y = y,
                fill = d)) +
  ylim(c(-2, 5)) +
  geom_segment_straight(
    aes(
      x = "o",
      y = -1,
      xend = "z",
      yend = 3
    ),
    arrow = arrow(length = unit(0.2, "cm")),
    col = "red",
    size = 2
  ) + 
  coord_polar()

EDIT: geom_curve()

Here is the same trick applied to geom_curve():

geom_curve_polar <- function(...) {
  layer <- geom_curve(...)
  new_layer <- ggproto(NULL, layer)
  old_geom <- new_layer$geom
  geom <- ggproto(
    NULL, old_geom,
    draw_panel = function(data, panel_params, coord, 
                          curvature = 0.5, angle = 90, ncp = 5,
                          arrow = NULL, arrow.fill = NULL,
                          lineend = "butt", linejoin = "round",
                          na.rm = FALSE) {
      data <- ggplot2:::remove_missing(
        data, na.rm = na.rm, c("x", "y", "xend", "yend", 
                               "linetype", "size", "shape")
      )
      if (ggplot2:::empty(data)) {
        return(zeroGrob())
      }
      coords <- coord$transform(data, panel_params)
      ends <- transform(data, x = xend, y = yend)
      ends <- coord$transform(ends, panel_params)
      
      arrow.fill <- if (!is.null(arrow.fill)) arrow.fill else coords$colour
      return(grid::curveGrob(
        coords$x, coords$y, ends$x, ends$y,
        default.units = "native", gp = grid::gpar(
          col = alpha(coords$colour, coords$alpha),
          fill = alpha(arrow.fill, coords$alpha),
          lwd = coords$size * .pt,
          lty = coords$linetype,
          lineend = lineend,
          linejoin = linejoin
        ),
        curvature = curvature, angle = angle, ncp = ncp,
        square = FALSE, squareShape = 1, inflect = FALSE, open = TRUE,
        arrow = arrow
      ))
      
    }
  )
  new_layer$geom <- geom
  return(new_layer)
}

The above yields the following plot after replacing geom_segment_straight() with geom_curve_polar():

Small note: this way of making new geoms is the quick and dirty way of doing it. If you plan to do it properly, you should write the constructors and ggproto classes separately.

这篇关于在ggplot2(R)中使用coord_polar()时在任意两点之间绘制直线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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