使用annotation_logticks或替代方法在轴线外侧显示对数刻度小刻度线

Mas*_*onK 6 r ggplot2

Comments_logticks() 是一个很棒的小函数,它向对数刻度轴添加小刻度线,如下所示

默认情况下,该函数在绘图的面板区域内部绘制刻度。例如,如果在 y 轴上,刻度线出现在轴线的右侧;如果在 x 轴上,刻度线出现在轴线上方。

来自 ggplot2 网站的示例

我发现对于大多数绘图情况来说,这种默认设置是不可取的。到目前为止,我还没有找到一种简单的方法来让这些小刻度显示在出现常规 ggplot2 刻度的面板区域的外部。例如,y 轴出现在线条的左侧而不是右侧。有没有一个简单的解决方案?

对于在主要刻度之间插入值很重要的绘图情况,将这些值显示在常规 ggplot2 标签和刻度通常出现的左侧将是一个非常好的选择。我还没有找到一个不涉及剪切或完全放弃annotation_logticks()的解决方案,而且我还没有成功地简单地使用刻度线长度的负值。

这是直接来自 ggplot2 网站示例的代码:

a <- ggplot(msleep, aes(bodywt, brainwt)) +
 geom_point(na.rm = TRUE) +
 scale_x_log10(
   breaks = scales::trans_breaks("log10", function(x) 10^x),
   labels = scales::trans_format("log10", scales::math_format(10^.x))
 ) +
 scale_y_log10(
   breaks = scales::trans_breaks("log10", function(x) 10^x),
   labels = scales::trans_format("log10", scales::math_format(10^.x))
 ) +
 theme_bw()

a + annotation_logticks()
Run Code Online (Sandbox Code Playgroud)

我正在寻找一个简单地将刻度翻转到轴线另一侧的结果。

Jus*_*eon 6

我找到了一种简洁的方法来解决这个问题,尽管这个解决方案的刻度长度与annotation_logticks()

logticks <- function(datavar,type) {

  minimum <- 1/10^abs(floor(log10(min(datavar, na.rm=TRUE))))
  maximum <- 1*10^abs(floor(log10(max(datavar, na.rm=TRUE)))+1)
  multiple <- floor(log10(maximum/minimum))

  yourtickvector <- c()

  if (type=="breaks") {

    yourtickvector <- c(minimum)

    for (x in seq(0,multiple)) {

      andadd <- seq(minimum*10^x,minimum*10^(x+1),minimum*10^x)[-1]

      yourtickvector <- c(yourtickvector,andadd)

    }

  } else if (type=="labels") {

    for (x in seq(0,multiple)) {

      andadd <- c(minimum*10^x,rep("",8))

      yourtickvector <- c(yourtickvector,andadd)

    }

    yourtickvector <- c(yourtickvector,minimum*10^multiple)

  }

  return(yourtickvector)

}

# only changed the breaks / label fields below to call the above function

a <- ggplot(msleep, aes(bodywt, brainwt)) +
  geom_point(na.rm = TRUE) +
  scale_x_log10(
    breaks = logticks(msleep$bodywt,"breaks"),
    labels = logticks(msleep$bodywt,"labels")
  ) +
  scale_y_log10(
    breaks = logticks(msleep$brainwt,"breaks"),
    labels = logticks(msleep$brainwt,"labels")
  ) +
  theme_bw()

a
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


mat*_*fee 4

据我所知,是的,但有点恶心。总而言之::

b <- a + 
  # reverse ticks
  annotation_logticks(short=unit(-0.1, "cm"), mid=unit(-0.2, "cm"), long=unit(-0.3,"cm")) +
  # remove clipping
  coord_cartesian(clip="off") +
  # add space between ticks and labels
  theme(axis.text.x=element_text(margin = margin(t = 10)), axis.text.y=element_text(margin = margin(r = 10)))

# get the limits of the panel in data coordinates
bb <- ggplot_build(b)$layout$panel_params[[1]]
# draw a white rectangle to cover up the additional tick marks, gross
# the coordinates are actually in powers of 10 of the data
b +
  annotation_custom(
    grob=rectGrob(gp=gpar(col=NA)),
    # the min values are -100 ie "something very large and negative"
    # the max values are the bottom-left corner of the plot plus a tiny
    #  fudge factor to cover up the stubs of the ticks (gross)
    xmin=-100, xmax=min(ab$x.range) + 0.01,
    ymax=min(ab$y.range) + 0.01, ymin=-100
  )
Run Code Online (Sandbox Code Playgroud)

产量

在此输入图像描述

你必须捏造 中的 0.01s 和 -100s annotation_custom


annotation_logticks如果你在控制台中查看,它有

layer(data = dumy_data(), # more stuff,
      geo = GeomLogticks, # lots more stuff
Run Code Online (Sandbox Code Playgroud)

ggplot2:::GeomLogticks(它不是导出函数,因此:::需要检查它的三元组)显示具有各种函数的对象来绘制刻度线。一些试验和错误表明,ggplot2:::GeomLogticks$draw_panel该函数似乎可以完成所有工作。看起来这个函数创建了一个数据框,其中包含每个单独刻度的 xstart、xend、ystart、yend 坐标(!)。

例如该函数主体的片段

    if (grepl("l", sides)) {
        ticks$y_l <- with(data, segmentsGrob(y0 = unit(yticks$y, 
            "native"), y1 = unit(yticks$y, "native"), x0 = unit(yticks$start, 
            "cm"), x1 = unit(yticks$end, "cm"), gp = gpar(col = alpha(colour, 
            alpha), lty = linetype, lwd = size * .pt)))
    }
Run Code Online (Sandbox Code Playgroud)

由此看来,我们可以只提供负长度annotation_logticks

a2 <- a + annotation_logticks(short=unit(-0.1, "cm"), mid=unit(-0.2, "cm"), long=unit(-0.3,"cm"))
a2
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这实际上不起作用,如果你用力眯着眼睛,你可以看到所有刻度线的残端。看起来刻度线绘制正确,但它们被面板区域剪切。(如果您暂时关闭面板边框,a2 + theme(panel.border=element_rect(fill=NA, color=NA))您可以看到这种情况)。

要关闭剪辑,你可以这样做+ coord_cartesian(clip='off')

a3 <- a2 + coord_cartesian(clip='off')
a3
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

正如在参数中提到的?coord_cartesianclip这可能会导致“意外的结果”——刻度被定义为比数据更大的区域(我认为它们是 10 的幂,所以如果最小的数据点是幂的一半) 10 时,它仍然会一直计算到下一个较低的幂),因此延伸到左下角之外。

解决此问题的一个粗略方法是在图表的左下部分(面板外部/边距中)绘制一个矩形以覆盖刻度线。annotation_custom这样做但需要数据坐标中的坐标。当使用像这样的对数刻度时,坐标是 10 的幂,因此例如“10^-4”是坐标 -4。

因此,为了绘制矩形来掩盖多余的标记,我们需要将左下角基本设置在负无穷大(图形的左下角),并将右上角设置在X/Y 轴上的最小值处

annotation_custom我们想要rectGrob画一个矩形。默认情况下它有白色背景,但我们禁用黑色边框gpar(col=NA)xmin我们将和坐标设置ymin为 -100(本质上是非常大的负数;-Inf意味着“最低轴值”)。我们可以将xmaxymax坐标设置为最低的轴值,这-Inf对我们来说就足够了。

a3 +
   annotation_custom(
    grob=rectGrob(gp=gpar(col=NA)),
    xmin=-100, xmax=-Inf,
    ymax=-Inf, ymin=-100
  )
Run Code Online (Sandbox Code Playgroud)

对我来说,这并不能完全掩盖额外的刻度线,留下恼人的小点。

在此输入图像描述

我真的希望xmaxymax能够-Inf + a little bit覆盖整个刻度线。但要做到这一点,我们不能-Inf再用作“轴下限”的简写,我们必须使用显式访问它们

bb <- ggplot_build(b)$layout$panel_params[[1]]
# bb$x.range, bb$y.range
Run Code Online (Sandbox Code Playgroud)

然后我们修改上面的内容

a4 <- a3 +
   annotation_custom(
    grob=rectGrob(gp=gpar(col=NA)),
    xmin=-100, xmax=min(ab$x.range) + 0.01,
    ymax=min(ab$y.range) + 0.01, ymin=-100
  )
a4
Run Code Online (Sandbox Code Playgroud)

(我通过反复试验发现了 0.01,这不太好)。

现在一切正常,只是 X 轴和 Y 轴标签碰到了刻度线。要添加标签和刻度线之间的间距,请使用

a5 <- a4 + theme(axis.text.x=element_text(margin = margin(t = 10)),
      axis.text.y=element_text(margin = margin(r = 10)))
a5
Run Code Online (Sandbox Code Playgroud)

其中这些是以像素为单位的边距(您可以更改单位,请参阅?margin

产生您首先看到的图片。也许您可以将其设为一个函数,允许用户修改各种模糊因子(-100、+ 0.01 和 10 像素的边距)。