简体   繁体   English

如何(更容易)在 ggplot2 中创建漂亮的 x 轴刻度(即 pi/2, pi, 3pi/2, ...)?

[英]How can one (easier) create nice x-axis ticks (i.e. pi/2, pi, 3pi/2, ...) in ggplot2?

I would like to create a plot, where one can see an alternative ticking of the x-axis, eg pi/2, pi, 3pi/2, etc. So far, this works for me only with a rather unhandy code (look at the lines where I create pi.halfs , pi.fulls and merge them later into vec.expr ):我想创建一个图,在那里人们可以看到 x 轴的替代刻度,例如 pi/2、pi、3pi/2 等。到目前为止,这仅适用于我的一个相当不方便的代码(看看我创建pi.halfspi.fulls并稍后将它们合并到vec.expr ):

require (ggplot2)

# Create vectors: breaks and corresponding labels as multiples of pi/2
vec.breaks <- seq(from = pi/2, to = 7*pi/2, by = pi/2)
pi.halfs <- c(paste(expression(pi), "/2"),
  paste(seq(from = 3, to = 21, by = 2), "*" , expression(pi), "/2"))
pi.fulls <- c(paste(expression(pi)),
  paste(seq(from = 2, to = 11, by = 1), "*" , expression(pi)))
vec.expr <- parse(text = c(rbind(pi.halfs, pi.fulls)))[1:7]

# Create some time and signal
time <- seq(from = 0, to = 4*pi, by = 0.01)
signal <- sin(time)
df <- data.frame(time,signal)

# Now plot the signal with the new x axis labels
fig <- ggplot(data = df, aes(x = time, y = signal)) +
          geom_line() +
          scale_x_continuous(breaks=vec.breaks, labels=vec.expr)
print(fig)

... resulting in ... ... 导致 ...

输出图

Is anyone aware of an easier approach, where one can change the base of some x-axis labeling in ggplot2, eg like here from decimals to multiples of pi?有没有人知道一种更简单的方法,可以在 ggplot2 中更改某些 x 轴标签的基数,例如这里从小数到 pi 的倍数? Are there any nice packages, that I missed so far?有没有什么好的包,我到目前为止错过了? I found some duplicates of this question, but only in other languages...我发现了这个问题的一些重复,但仅限于其他语言......

You are looking for the scales package, which lets you create arbitrary formatting functions for scales and also has a number of helpful formatting functions already built in. Looking through the scales package help, I was surprised not to find a radian scale, but you should be able to create one using math_formatter() .您正在寻找scales包,它允许您为比例创建任意格式化函数,并且还内置了许多有用的格式化函数。查看 scales 包帮助,我很惊讶没有找到弧度比例,但您应该能够使用math_formatter()创建一个。 This code gets the same results, though not with the fractions.这段代码得到相同的结果,但不是分数。

library(ggplot2)
library(scales)

time <- seq(from = 0, to = 4*pi, by = 0.01)
signal <- sin(time)
df <- data.frame(time,signal)

pi_scales <- math_format(.x * pi, format = function(x) x / pi)

fig <- ggplot(data = df, aes(x = time, y = signal)) +
  geom_line() +
  scale_x_continuous(labels = pi_scales, breaks = seq(pi / 2, 7 * pi / 2, pi / 2))

print(fig)

在 x 轴上用 pi 绘图

Here is a function to make fractional labels (maybe a little clunky).这是一个制作分数标签的函数(可能有点笨重)。 It uses fractions from MASS package and allows you to change the multiplier you want to use on the x-axis.它使用MASS包中的fractions ,并允许您更改要在 x 轴上使用的乘数。 You just pass it a symbol (ie. "pi").您只需向它传递一个符号(即“pi”)。 If the symbol has a value, the ticks will be scaled by width*value, otherwise just by width.如果符号有值,刻度将按宽度*值缩放,否则仅按宽度缩放。

# Now plot the signal with the new x axis labels
p <- ggplot(data = df, aes(x = time, y = signal)) +
          geom_line()

## Convert x-ticks to fractional x-ticks with a symbol multiplier
fracAx <- function(p, symbol, width=0.5) {
    require(MASS)                                                 # for fractions
    val <- tryCatch(eval(parse(text=symbol)), error=function(e) 1)
    info <- ggplot_build(p)
    xrange <- info[[2]]$ranges[[1]]$x.range/val                   # get the x-range of figure
    vec.breaks <- seq(floor(xrange[1]), ceiling(xrange[2]), by=width)
    fracs <- strsplit(attr(fractions(vec.breaks), "fracs"), "/")  # convert to fractions
    labels <- sapply(fracs, function(i)
        if (length(i) > 1) { paste(i[1], "*", symbol, "/", i[2]) }
        else { paste(i, "*", symbol) })
    p + scale_x_continuous(breaks=vec.breaks*val, labels=parse(text=labels))
}
## Make the graph with pi axis
fracAx(p, "pi")

在此处输入图片说明

## Make the graph with e axis, for example
e <- exp(1)
fracAx(p, "e")

在此处输入图片说明

## Make the graph with a symbol that has no value
fracAx(p, "theta", width=2)

在此处输入图片说明

Based on the other answers here I was able to piece together some functions which implement a general radians format that can be used independently of mucking about with the internals of ggplot2 objects.基于这里的其他答案,我能够将一些实现通用radians格式的函数拼凑在一起,这些函数可以独立使用而ggplot2对象的内部ggplot2

numerator <- function(x) {
  f = attr(x, "fracs")
  s <- as.integer(sign(x))
  ifelse(is.finite(x), as.integer(stringr::str_extract(f, "^[^/]*")), s)
}

denominator <- function(x) {
  f = attr(x, "fracs")
  s <- as.integer(sign(x))
  ratio <- str_detect(f, "/")
  d <- as.integer(stringr::str_extract(f, "[^/]*$"))
  ifelse(is.finite(x), ifelse(ratio, d, 1L), 0L)
}

char_sign <- function(x) {
  s <- sign(x)
  ifelse(s == 1, "+",
         ifelse(s == -1, "-", ""))
}

#' Convert value to radians formatting
radians <- function(x) {
  y = x/pi
  f = suppressWarnings(MASS::as.fractions(y))
  n = suppressWarnings(numerator(f))
  d = suppressWarnings(denominator(f))
  s <- char_sign(x)
  o <- vector(mode = "character", length = length(x))
  o <- ifelse(d == 0 & n != 0, paste0(s, "∞"), o)
  o <- ifelse(n == 0 & d != 0, "0", o)
  o <- ifelse(n != 0 & d != 0, paste0(n, "π/", d), o)
  o <- ifelse(n == 1 & d != 0, paste0("π/", d), o)
  o <- ifelse(n == -1 & d == 1, paste0(s, "π"), o)
  o <- ifelse(n == -1 & d != 0 & d != 1, paste0(s, "π/", d), o)
  o <- ifelse(d == 1 & n != 0 & abs(n) != 1, paste0(n, "π"), o)
  o <- ifelse(n == d & is.finite(n), "π", o)
  o
}

Here it is in use:这里正在使用:


```r
time <- seq(from = 0, to = 4*pi, by = 0.01)
signal <- sin(time)
df <- data.frame(time,signal)

ggplot(df, aes(time, signal)) +
  geom_line() +
  scale_x_continuous(labels = trans_format(radians, force),
                     breaks = seq(0, 4*pi, pi/2))

正弦函数的弧度格式输出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM