绘图区域外部的ggplot2注解_滴答声 [英] ggplot2 annotation_ticks on the outside of the plot region

查看:85
本文介绍了绘图区域外部的ggplot2注解_滴答声的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找到一种优雅的方法来在使用ggplot2创建的绘图上插入小刻度线.我发现了一个几乎可以实现我想要的功能: https://rdrr.io/github/hrbrmstr/ggalt/src/R/annotation_ticks.r

I try to find an elegant way to insert minor ticks on plots created with ggplot2. I found a function which does almost exactly what I want: https://rdrr.io/github/hrbrmstr/ggalt/src/R/annotation_ticks.r

只有一个缺点:刻度线(如annotation_logticks中所示)绘制在绘图区域内.我需要它们在外面.

There is only one drawback: the ticks, like in annotation_logticks, are drawn inside the plot region. I need them to be on the outside.

一个解决方案可能是对刻度长度使用负值.当我这样做时,刻度线消失了.我认为这是由于ggplot2的默认剪裁操作所致,该操作会阻止在绘图区域(?)之外进行绘图(另请参见

A solution could be to use negative values for the tick-length. When I do so, the ticks disappear. I assume, that this is due to the default clipping action of ggplot2, which supresses plotting outside the plot region (?) (see also log ticks on the outer side of axes (annotation_logticks), where the clipping is turned off which - unfortunately - leads to ticks exceeding the plot-range).

所以:是否有一个选项可以修改annotation_ticks-函数以便在绘图区域的外部中产生刻度线,仅覆盖绘图的范围?理想情况下,应将此功能整合到annotate_ticks-函数中(我不想保存然后重新布置图;我宁愿一步建立最终图).

So: is there an option to modify the annotation_ticks - function in order to produce ticks outside of the plot region, only covering the range of the plot? Ideally, this functionality should by incorporated in the annotate_ticks - function (I don't want to save and then re-arrange the plot; I'd rather build my final plot in one step).

推荐答案

我找到了一种令人满意的解决方案,用于适应annotation_ticks函数.如果我们只是简单地从您发布的链接中复制粘贴代码,则可以在GeomTicks ggproto对象的末尾附近进行以下小的调整:

I've found a sort of satisfactory solution to adapting the annotation_ticks function. If we'd simply copy-paste the code from the link you've posted, we can make the following small adjustment near the end in the GeomTicks ggproto object:

GeomTicks <- ggproto(
  "GeomTicks", Geom,
  # ...
  # all the rest of the code
  # ...
    gTree(children = do.call("gList", ticks), cl = "ticktrimmer") # Change this line
  },
  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = 1)
)

然后,我们可以编写一个小函数,通过在网格包中劫持S3泛型makeContent,简单地裁剪在绘图之前触发的刻度之外的刻度线:

Then we can write a small function that simply clips the ticks that are outside the range that gets triggered just before drawing by hijacking the S3 generic makeContent in the grid package:

library(grid)

makeContent.ticktrimmer <- function(x) {
  # Loop over segment grobs
  x$children <- lapply(x$children, function(m) {
    # convert positions to values
    x0 <- convertX(m$x0, "npc", valueOnly = T)
    x1 <- convertX(m$x1, "npc", valueOnly = T)
    y0 <- convertY(m$y0, "npc", valueOnly = T)
    y1 <- convertY(m$y1, "npc", valueOnly = T)

    # check if values are outside 0-1
    if (length(unique(x0)) == 1) {
      keep <- y0 >= 0 & y0 <= 1 & y1 >= 0 & y1 <= 1
    } else if (length(unique(y0)) == 1) {
      keep <- x0 >= 0 & x0 <= 1 & x1 >= 0 & x1 <= 1
    } else {
      keep <- TRUE
    }

    # Trim the segments
    m$x0 <- m$x0[keep]
    m$y0 <- m$y0[keep]
    m$x1 <- m$x1[keep]
    m$y1 <- m$y1[keep]
    m
  })
  x
}

现在我们可以绘制:

g <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
  geom_point(aes(colour = Species)) +
  annotation_ticks(long = -1 * unit(0.3, "cm"),
                   mid = -1 * unit(0.2, "cm"),
                   short = -1 * unit(0.1, "cm")) +
  coord_cartesian(clip = "off")

除了将左侧的第一个刻度打得有些怪异之外,这似乎还算合理.

Besides the first tick on the left being slightly weirdly placed, this seems to work reasonably.

这是一种代码的快速重构,可用于本机的次要休息时间,而不是从头计算次要休息时间.用户功能:

Here is a quick refactoring of the code to work with the native minor breaks instead of calculating minor breaks de novo. The user function:

annotation_ticks <- function(sides = "b",
                             scale = "identity",
                             scaled = TRUE,
                             ticklength = unit(0.1, "cm"),
                             colour = "black",
                             size = 0.5,
                             linetype = 1,
                             alpha = 1,
                             color = NULL,
                             ticks_per_base = NULL,
                             ...) {
  if (!is.null(color)) {
    colour <- color
  }

  # check for invalid side
  if (grepl("[^btlr]", sides)) {
    stop(gsub("[btlr]", "", sides), " is not a valid side: b,t,l,r are valid")
  }

  # split sides to character vector
  sides <- strsplit(sides, "")[[1]]

  if (length(sides) != length(scale)) {
    if (length(scale) == 1) {
      scale <- rep(scale, length(sides))
    } else {
      stop("Number of scales does not match the number of sides")
    }
  }

  base <- sapply(scale, function(x) switch(x, "identity" = 10, "log10" = 10, "log" = exp(1)), USE.NAMES = FALSE)

  if (missing(ticks_per_base)) {
    ticks_per_base <- base - 1
  } else {
    if ((length(sides) != length(ticks_per_base))) {
      if (length(ticks_per_base) == 1) {
        ticks_per_base <- rep(ticks_per_base, length(sides))
      } else {
        stop("Number of ticks_per_base does not match the number of sides")
      }
    }
  }

  delog <- scale %in% "identity"

  layer(
    data = data.frame(x = NA),
    mapping = NULL,
    stat = StatIdentity,
    geom = GeomTicks,
    position = PositionIdentity,
    show.legend = FALSE,
    inherit.aes = FALSE,
    params = list(
      base = base,
      sides = sides,
      scaled = scaled,
      ticklength = ticklength,
      colour = colour,
      size = size,
      linetype = linetype,
      alpha = alpha,
      ticks_per_base = ticks_per_base,
      delog = delog,
      ...
    )
  )
}

ggproto对象:

The ggproto object:

GeomTicks <- ggproto(
  "GeomTicks", Geom,
  extra_params = "",
  handle_na = function(data, params) {
    data
  },

  draw_panel = function(data,
                        panel_scales,
                        coord,
                        base = c(10, 10),
                        sides = c("b", "l"),
                        scaled = TRUE,
                        ticklength = unit(0.1, "cm"),
                        ticks_per_base = base - 1,
                        delog = c(x = TRUE, y = TRUE)) {
    ticks <- list()

    for (s in 1:length(sides)) {
      if (grepl("[b|t]", sides[s])) {

        xticks <- panel_scales$x.minor

        # Make the grobs
        if (grepl("b", sides[s])) {
          ticks$x_b <- with(
            data,
            segmentsGrob(
              x0 = unit(xticks, "npc"),
              x1 = unit(xticks, "npc"),
              y0 = unit(0, "npc"),
              y1 = ticklength,
              gp = gpar(
                col = alpha(colour, alpha),
                lty = linetype,
                lwd = size * .pt
              )
            )
          )
        }
        if (grepl("t", sides[s])) {
          ticks$x_t <- with(
            data,
            segmentsGrob(
              x0 = unit(xticks, "npc"),
              x1 = unit(xticks, "npc"),
              y0 = unit(1, "npc"),
              y1 = unit(1, "npc") - ticklength,
              gp = gpar(
                col = alpha(colour, alpha),
                lty = linetype,
                lwd = size * .pt
              )
            )
          )
        }
      }


      if (grepl("[l|r]", sides[s])) {

        yticks <- panel_scales$y.minor

        # Make the grobs
        if (grepl("l", sides[s])) {
          ticks$y_l <- with(
            data,
            segmentsGrob(
              y0 = unit(yticks, "npc"),
              y1 = unit(yticks, "npc"),
              x0 = unit(0, "npc"),
              x1 = ticklength,
              gp = gpar(
                col = alpha(colour, alpha),
                lty = linetype, lwd = size * .pt
              )
            )
          )
        }
        if (grepl("r", sides[s])) {
          ticks$y_r <- with(
            data,
            segmentsGrob(
              y0 = unit(yticks, "npc"),
              y1 = unit(yticks, "npc"),
              x0 = unit(1, "npc"),
              x1 = unit(1, "npc") - ticklength,
              gp = gpar(
                col = alpha(colour, alpha),
                lty = linetype,
                lwd = size * .pt
              )
            )
          )
        }
      }
    }
    gTree(children = do.call("gList", ticks))
  },
  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = 1)
)

绘图:

ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
  geom_point(aes(colour = Species)) +
  annotation_ticks(ticklength = -1 * unit(0.1, "cm"),
                   side = "b") +
  coord_cartesian(clip = "off")

这篇关于绘图区域外部的ggplot2注解_滴答声的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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