对数刻度在轴外的小刻度线,带有注解_logticks或替代方法

时间:2019-01-15 01:03:18

标签: r ggplot2

annotation_logticks()是一个很棒的小函数,它在对数刻度轴as shown here上添加了较小的刻度线。

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

example from ggplot2 website

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

对于需要在主要刻度线之间进行插值的绘图情况,将其显示在常规ggplot2标签和刻度线的左侧通常是一个很好的选择。我还没有找到一种解决方案,该解决方案不涉及完全剪切或放弃注解_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()

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

3 个答案:

答案 0 :(得分:1)

据我所知,是的,但是有点毛病。 TLDR ::

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
  )

收益

enter image description here

您必须在annotation_custom中加上0.01和-100。


如果您在控制台中查看annotation_logticks,则它具有

layer(data = dumy_data(), # more stuff,
      geo = GeomLogticks, # lots more stuff

ggplot2:::GeomLogticks(它不是导出函数,因此要检查的三元组:::)显示了一个具有各种功能的对象,它们可以绘制刻度线。反复试验表明,ggplot2:::GeomLogticks$draw_panel似乎是完成所有工作的函数。看起来,此函数使数据框具有每个刻度(!)的xstart,xend,ystart,¥ d坐标。

例如该功能主体的摘要

    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)))
    }

据此,我们似乎可以为annotation_logticks提供负长度

a2 <- a + annotation_logticks(short=unit(-0.1, "cm"), mid=unit(-0.2, "cm"), long=unit(-0.3,"cm"))
a2

enter image description here

这实际上并没有用,如果您斜视一下就可以看到所有刻度线的存根。看来勾号已正确绘制,但它们已被面板区域裁剪。 (如果您暂时关闭面板边框a2 + theme(panel.border=element_rect(fill=NA, color=NA)),则会看到这种情况。)

要关闭剪辑,您可以执行+ coord_cartesian(clip='off')

a3 <- a2 + coord_cartesian(clip='off')
a3

enter image description here

?coord_cartesian中针对clip参数所述,这可能会导致“意外的结果”-刻度线的定义区域大于数据区域(我认为它们的整数幂为10,因此,如果最小的数据点是10的幂的一半,它仍然会一直向下计算到下一个较低的幂),因此应扩展到左下角之外。

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

因此,要绘制矩形以掩盖多余的标记,我们需要使左下角基本上位于负无穷大处(图形的左下角),并且使右上角具有 minimum (最小)。 em>在X / Y轴上的值。

annotation_custom中,我们希望rectGrob绘制一个矩形。默认情况下,它的背景为白色,但黑色边框则可以使用gpar(col=NA)禁用。我们将xminymin的坐标设置为-100(本质上是非常大且为负的坐标; -Inf的意思是“最低轴值”)。我们可以将xmaxymax坐标设置为最低轴值,-Inf将为我们做这件事。

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

对我来说,这并没有掩盖多余的刻度线,只留下令人讨厌的小点。

enter image description here

我真的希望xmaxymax-Inf + a little bit,以掩盖整个刻度线。但是要做到这一点,我们不能再使用-Inf作为“轴下限”的简写,我们必须使用

显式地访问它们。
bb <- ggplot_build(b)$layout$panel_params[[1]]
# bb$x.range, bb$y.range

然后我们修改上面的

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

(我通过反复试验发现了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

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

产生您首先看到的图片。 您也许可以使其功能正常化,允许用户修改各种软糖系数(-100,+ 0.01和10像素的边距)。

答案 1 :(得分:0)

我找到了一种整齐的方法来解决此问题,尽管此解决方案的记号长度与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

enter image description here

答案 2 :(得分:0)

我意识到,如果您希望coord_cartesian工作,则需要先在scale命令中设置“中断”,“限制”和“标签”:

scale_y_log10(breaks = c(0.1, 1, 10, 100, 1000, 10000,100000),limits = c(0.1,100000),labels=c(0.1, 1, 10, 100, 1000, 10000, "100000")) +
  annotation_logticks(sides = "l", outside = T, short = unit(0.05, "cm"),mid = unit(0.05, "cm"),long = unit(0.2, "cm"))+
  coord_cartesian(clip = "off")

ticks outside