R图指定时间刻度线的数量 - 时间/日期相当于漂亮

发布于 2024-11-18 10:44:43 字数 967 浏览 2 评论 0原文

我想知道在 x 轴上绘制时间时如何绘制更多刻度线。

基本上,相当于漂亮的时间。很明显,它不能很好地处理时间,因为它使用 1、2、5 和 10 的因子。对于时间,人们可能需要例如小时、半小时……

plot(as.POSIXct(x,origin="1960-01-01"),y,type="l",xlab="Time")

给出的刻度线确实太少且间隔很宽。

zoox<-zoo(y,as.POSIXct(stats$Time,origin="1960-01-01"))
plot(zoox)

给出相同的。

谢谢

编辑:

只是为了澄清(到目前为止答案没有解决我的问题):我正在寻找的是一个类似于日期的函数,例如一个函数,它需要开始日期、结束日期、刻度数,并输出刻度的位置。也就是说,我很清楚可以绘制小时,绘制分钟,以及其他什么,但是相当自动化数字的刻度距离,并且日期的结果函数应该自行决定是否使用天,小时,分钟,秒、毫秒、微秒、30 分钟、500 微秒、5 秒等间隔。无论如何,这就是 Pretty 对数字的作用。

EDIT2:

这是我当前用来决定时间轴格式的函数(请注意,这不适用于日期):

mydiff <- end-start
if(mydiff>1800) {
    axis.POSIXct(1,xrange,format="%H:%M")
} else if(mydiff>30) {
    axis.POSIXct(1,xrange,format="%H:%M:%S")
} else if(mydiff>0.5) {
    axis.POSIXct(1,xrange,format="%H:%M:%OS3")
} else
    axis.POSIXct(1,xrange,format="%H:%M:%OS6")
}

我没有增加刻度线的函数,所以我使用默认的刻度线数量

I was wondering how I could plot more tick marks when plotting time on the x-axis.

Basically, a time equivalent to pretty. Pretty obviously doesn't work so well with times, as it uses factors of 1,2,5 and 10. For time one probably wants e.g. hours, half hours, ...

plot(as.POSIXct(x,origin="1960-01-01"),y,type="l",xlab="Time")

gives really too few and widely spaced tickmarks.

zoox<-zoo(y,as.POSIXct(stats$Time,origin="1960-01-01"))
plot(zoox)

gives the same.

Thanks

EDIT:

Just to clarify (so far answers don't address my issue): What I am looking for is a function like pretty for dates, e.g. a function, that takes a start date, an end date, a number of ticks, and outputs the location of the ticks. That is, I am well aware it is possible to plot hours, to plot minutes, and what else, but pretty automates the tick distance for numbers, and a resulting function for dates should decide by itself whether to use days, hours, minutes, second, milliseconds, microseconds, 30 minutes, 500 micros, 5 seconds, etc. intervals. That is what pretty does for numbers, anyway.

EDIT2:

This is the function I currently use to decide the format for the time axis (note that this doesn't work for dates):

mydiff <- end-start
if(mydiff>1800) {
    axis.POSIXct(1,xrange,format="%H:%M")
} else if(mydiff>30) {
    axis.POSIXct(1,xrange,format="%H:%M:%S")
} else if(mydiff>0.5) {
    axis.POSIXct(1,xrange,format="%H:%M:%OS3")
} else
    axis.POSIXct(1,xrange,format="%H:%M:%OS6")
}

I don't have a function that increase tick marks, so I use the default number of tick marks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

傲娇萝莉攻 2024-11-25 10:44:43

通过一个可重现的示例,

set.seed(1)
x <- as.POSIXct(sort(sample(100000, 100)), origin="1960-01-01")
y <- rpois(100, 5)
plot(x, y, type = "l", xlab = "Time")

我们可以使用 axis.POSIXct() 函数(也可以使用 Axis() S3 通用函数)来添加自定义轴情节。这里的要点是,您(用户)可以完全控制刻度线的绘制位置以及它们的标签方式,如果默认值不适合您,您只需要多努力一点即可。

首先,我们绘制数据,但禁止绘制 x 轴:

plot(x, y, type = "l", xlab = "Time", xaxt = "n")

接下来,我将在每小时开始时添加一个主要刻度线。为此,我创建了一个日期时间序列,

  1. 系列中第一个观察的舍入小时,
  2. 进行观察的最后一个小时的结束时间(使用 ceiling() 将我们移至下一小时),
  3. 以 1 小时(by = "1 hour")为单位递增序列。

该序列被提供给 axis.POSIXct()at 参数。如果不阅读 ?axis.POSIXct?par ,其余部分应该很容易理解

## add axis tick at each hour:
axis.POSIXct(side = 1, x = x,
             at = seq(from = round(x[1], "hours"),
                      to = x[1] + ceiling(difftime(tail(x, 1), head(x, 1), 
                                                   units = "hours")),
                      by = "1 hour"),
             las = 2)

结果图如下所示:

在此处输入图像描述

为了显示更精细的控制,我现在在每个半小时位置添加小刻度线,但抑制这些刻度线的注释(通过 label code> argument) 并让小刻度更短(通过图形参数tcl)。请注意 seq() 方法的 by 参数如何获取指定间隔的数值

## add minor ticks at 30 min intervals to above plot
axis.POSIXct(side = 1, x = x,
             at = seq(from = round(x[1], "hours"),
                      to = x[1] + ceiling(difftime(tail(x, 1), head(x, 1), 
                                                   units = "hours")),
                       by = "30 mins"),
             las = 2, tcl = -0.2, labels = FALSE)

现在的图如下所示:

在此处输入图像描述

您可以添加自己的标签,而不是 axis.POSIXct 函数提供的标签。如果您想这样做,那么我们应该将 seq() 的输出分配给一个对象,然后我们可以在该对象上使用 format() 函数。例如:

plot(x, y, type = "l", xlab = "Time", xaxt = "n")
tseq <- seq(from = round(x[1], "hours"),
            to = x[1] + ceiling(difftime(tail(x, 1), head(x, 1), 
                                         units = "hours")),
            by = "1 hour")
axis.POSIXct(side = 1, x = x, at = tseq,
             labels = format(tseq, format = "%H:%M"), las = 2)

结果图如下所示:

在此处输入图像描述

format() 返回格式化日期时间的字符串。您可以将 paste() 粘贴到您想要的任何其他内容上,或者查看可用于格式化 ?strftime 中的日期时间对象的其他占位符

Using a reproducible example

set.seed(1)
x <- as.POSIXct(sort(sample(100000, 100)), origin="1960-01-01")
y <- rpois(100, 5)
plot(x, y, type = "l", xlab = "Time")

we can make use of the axis.POSIXct() function (one could also use the Axis() S3 generic as well) to add a custom axis to the plot. The main point here is that you, the user, are in full control of where ticks are draw and how they are labelled, you just need to work a little harder if the defaults don;t work for you.

First we plot the data but suppress drawing of the x-axis:

plot(x, y, type = "l", xlab = "Time", xaxt = "n")

Next I will add a major tick mark at the start of each hour. For this I create a sequence of datetimes that goes

  1. from the rounded hour of the first observation in the series,
  2. to the end of the last hour in which an observation was made (using ceiling() to move us on to the next hour),
  3. incrementing the sequence in 1 hour (by = "1 hour") units.

This sequence is supplied to the the at argument of axis.POSIXct(). The rest should be easy to follow if not read ?axis.POSIXct and ?par

## add axis tick at each hour:
axis.POSIXct(side = 1, x = x,
             at = seq(from = round(x[1], "hours"),
                      to = x[1] + ceiling(difftime(tail(x, 1), head(x, 1), 
                                                   units = "hours")),
                      by = "1 hour"),
             las = 2)

The resulting figure looks like this:

enter image description here

To show finer control, I now add minor tick marks at each half-hour location, but suppress the annotation of those ticks (via the labels argument) and also make the minor ticks shorter (via graphics parameter tcl). Notice how the seq() method's by argument can take a numeric amount of the stated interval

## add minor ticks at 30 min intervals to above plot
axis.POSIXct(side = 1, x = x,
             at = seq(from = round(x[1], "hours"),
                      to = x[1] + ceiling(difftime(tail(x, 1), head(x, 1), 
                                                   units = "hours")),
                       by = "30 mins"),
             las = 2, tcl = -0.2, labels = FALSE)

The plot now looks like this:

enter image description here

You can add your own labels rather than the ones that the axis.POSIXct function comes up with. If you want to do this, then we should assign the output from seq() to an object that we can then use the format() function on. For example:

plot(x, y, type = "l", xlab = "Time", xaxt = "n")
tseq <- seq(from = round(x[1], "hours"),
            to = x[1] + ceiling(difftime(tail(x, 1), head(x, 1), 
                                         units = "hours")),
            by = "1 hour")
axis.POSIXct(side = 1, x = x, at = tseq,
             labels = format(tseq, format = "%H:%M"), las = 2)

The resulting plot is shown below:

enter image description here

format() returns a character string of the formatted datetime. You can paste() on anything else you want or look at the other placeholders that can be used to format datetime objects in ?strftime

夏日浅笑〃 2024-11-25 10:44:43

axis.POSIXct() 已经很难猜测轴的合适漂亮值,所以我将从破解它开始。目前,它在内部依赖于将 pretty() 应用于日期时间的某些函数。它使用 pretty() 的默认值,因此您可以修改该函数以添加 nmin.n 参数,这会增加选择了漂亮的标记。

将 axis.POSIXct() 复制到您自己的函数/文件(为其指定一个新名称)。在定义中添加 nmin.n 参数,默认值可能比 pretty() 函数使用的值更大。并将其传递给每个进行的 pretty() 调用。

尝试一下。如果它工作得相当好,那么您可以执行 fixInNamespace(axis.POSIXct) 对实际函数进行相同的更改,以便在调用它的所有绘图上使用它。

PS 这是一个可能的 hack

function (side, x, at, format, labels = TRUE, n = 5, ...) {
  mat <- missing(at) || is.null(at)
  if (!mat) 
    x <- as.POSIXct(at)
  else x <- as.POSIXct(x)
  range <- par("usr")[if (side%%2) 
    1L:2L
    else 3L:4L]
  d <- range[2L] - range[1L]
  z <- c(range, x[is.finite(x)])
  attr(z, "tzone") <- attr(x, "tzone")
  if (d < 1.1 ) {
    sc <- 0.001
    if (missing(format)) 
      format <- "%H:%M:%OS6"
  }
  else if (d < 1.1 * 30) {
    sc <- 1
    if (missing(format)) 
      format <- "%H:%M:%OS3"
  }
  else if (d < 1.1 * 60) {
    sc <- 1
    if (missing(format)) 
      format <- "%H:%M:%S"
  }
  else if (d < 1.1 * 30 * 60) {
    sc <- 60
    if (missing(format)) 
      format <- "%H:%M:%S"
  }
  else if (d < 1.1 * 60 * 60) {
    sc <- 60
    if (missing(format)) 
      format <- "%H:%M"
  }
  else if (d < 1.3 * 60 * 60 * 24) {
    sc <- 60 * 60
    if (missing(format)) 
      format <- "%H:%M"
  }
  else if (d < 2 * 60 * 60 * 24) {
    sc <- 60 * 60
    if (missing(format)) 
      format <- "%a %H:%M"
  }
  else if (d < 7 * 60 * 60 * 24) {
    sc <- 60 * 60 * 24
    if (missing(format)) 
      format <- "%a"
  }
  else {
    sc <- 60 * 60 * 24
  }
  if (d < 60 * 60 * 24 * 50) {
    zz <- pretty(z/sc,n=n)
    z <- zz * sc
    z <- .POSIXct(z, attr(x, "tzone"))
    if (sc == 60 * 60 * 24) 
      z <- as.POSIXct(round(z, "days"))
    if (missing(format)) 
      format <- "%b %d"
  }
  else if (d < 1.1 * 60 * 60 * 24 * 365) {
    z <- .POSIXct(z, attr(x, "tzone"))
    zz <- as.POSIXlt(z)
    zz$mday <- zz$wday <- zz$yday <- 1
    zz$isdst <- -1
    zz$hour <- zz$min <- zz$sec <- 0
    zz$mon <- pretty(zz$mon,n=n)
    m <- length(zz$mon)
    M <- 2 * m
    m <- rep.int(zz$year[1L], m)
    zz$year <- c(m, m + 1)
    zz <- lapply(zz, function(x) rep(x, length.out = M))
    zz <- .POSIXlt(zz, attr(x, "tzone"))
    z <- as.POSIXct(zz)
    if (missing(format)) 
      format <- "%b"
  }
  else {
    z <- .POSIXct(z, attr(x, "tzone"))
    zz <- as.POSIXlt(z)
    zz$mday <- zz$wday <- zz$yday <- 1
    zz$isdst <- -1
    zz$mon <- zz$hour <- zz$min <- zz$sec <- 0
    zz$year <- pretty(zz$year,n=n)
    M <- length(zz$year)
    zz <- lapply(zz, function(x) rep(x, length.out = M))
    z <- as.POSIXct(.POSIXlt(zz))
    if (missing(format)) 
      format <- "%Y"
  }
  if (!mat) 
    z <- x[is.finite(x)]
  keep <- z >= range[1L] & z <= range[2L]
  z <- z[keep]
  if (!is.logical(labels)) 
    labels <- labels[keep]
  else if (identical(labels, TRUE)) 
    labels <- format(z, format = format)
  else if (identical(labels, FALSE)) 
    labels <- rep("", length(z))
  axis(side, at = z, labels = labels, ...)
}

与原始函数的差异可以在此处查看

axis.POSIXct() already works quite hard to guess suitable pretty values for the axis, so I would start by hacking that. At the moment, it relies internally on using pretty() applied to the some function of the datetimes. It uses the defaults for pretty() so you could hack the function to add an n or min.n argument which would increase the number of pretty marks selected.

Copy axis.POSIXct() to your own function/file (give it a new name). Add a n or min.n argument to the definition, probably with larger values as defaults than those used by the pretty() function. And pass that to each of the pretty() calls that is made.

Try it out. If it works reasonably well, then you can do fixInNamespace(axis.POSIXct) to make the same changes to the actual function so it gets used on all plots for which it is called.

P.S. Here is a possible hack

function (side, x, at, format, labels = TRUE, n = 5, ...) {
  mat <- missing(at) || is.null(at)
  if (!mat) 
    x <- as.POSIXct(at)
  else x <- as.POSIXct(x)
  range <- par("usr")[if (side%%2) 
    1L:2L
    else 3L:4L]
  d <- range[2L] - range[1L]
  z <- c(range, x[is.finite(x)])
  attr(z, "tzone") <- attr(x, "tzone")
  if (d < 1.1 ) {
    sc <- 0.001
    if (missing(format)) 
      format <- "%H:%M:%OS6"
  }
  else if (d < 1.1 * 30) {
    sc <- 1
    if (missing(format)) 
      format <- "%H:%M:%OS3"
  }
  else if (d < 1.1 * 60) {
    sc <- 1
    if (missing(format)) 
      format <- "%H:%M:%S"
  }
  else if (d < 1.1 * 30 * 60) {
    sc <- 60
    if (missing(format)) 
      format <- "%H:%M:%S"
  }
  else if (d < 1.1 * 60 * 60) {
    sc <- 60
    if (missing(format)) 
      format <- "%H:%M"
  }
  else if (d < 1.3 * 60 * 60 * 24) {
    sc <- 60 * 60
    if (missing(format)) 
      format <- "%H:%M"
  }
  else if (d < 2 * 60 * 60 * 24) {
    sc <- 60 * 60
    if (missing(format)) 
      format <- "%a %H:%M"
  }
  else if (d < 7 * 60 * 60 * 24) {
    sc <- 60 * 60 * 24
    if (missing(format)) 
      format <- "%a"
  }
  else {
    sc <- 60 * 60 * 24
  }
  if (d < 60 * 60 * 24 * 50) {
    zz <- pretty(z/sc,n=n)
    z <- zz * sc
    z <- .POSIXct(z, attr(x, "tzone"))
    if (sc == 60 * 60 * 24) 
      z <- as.POSIXct(round(z, "days"))
    if (missing(format)) 
      format <- "%b %d"
  }
  else if (d < 1.1 * 60 * 60 * 24 * 365) {
    z <- .POSIXct(z, attr(x, "tzone"))
    zz <- as.POSIXlt(z)
    zz$mday <- zz$wday <- zz$yday <- 1
    zz$isdst <- -1
    zz$hour <- zz$min <- zz$sec <- 0
    zz$mon <- pretty(zz$mon,n=n)
    m <- length(zz$mon)
    M <- 2 * m
    m <- rep.int(zz$year[1L], m)
    zz$year <- c(m, m + 1)
    zz <- lapply(zz, function(x) rep(x, length.out = M))
    zz <- .POSIXlt(zz, attr(x, "tzone"))
    z <- as.POSIXct(zz)
    if (missing(format)) 
      format <- "%b"
  }
  else {
    z <- .POSIXct(z, attr(x, "tzone"))
    zz <- as.POSIXlt(z)
    zz$mday <- zz$wday <- zz$yday <- 1
    zz$isdst <- -1
    zz$mon <- zz$hour <- zz$min <- zz$sec <- 0
    zz$year <- pretty(zz$year,n=n)
    M <- length(zz$year)
    zz <- lapply(zz, function(x) rep(x, length.out = M))
    z <- as.POSIXct(.POSIXlt(zz))
    if (missing(format)) 
      format <- "%Y"
  }
  if (!mat) 
    z <- x[is.finite(x)]
  keep <- z >= range[1L] & z <= range[2L]
  z <- z[keep]
  if (!is.logical(labels)) 
    labels <- labels[keep]
  else if (identical(labels, TRUE)) 
    labels <- format(z, format = format)
  else if (identical(labels, FALSE)) 
    labels <- rep("", length(z))
  axis(side, at = z, labels = labels, ...)
}

Differences to the original function can be seen here

赠意 2024-11-25 10:44:43

我倾向于使用函数 axis.POSIXct 和/或函数 cut.POSIXt。假设您的日期向量是 time,而您的值向量与 x 相关:

plot(time,x,xaxt="n")
axis.POSIXct(side=1,at=seq(min(time),max(time),by="week"),format="%d-%m") #For instance

并且,更进一步,使用 cut.POSIXt

plot(time,x,xaxt="n")
axis.POSIXct(side=1,at=cut(time, breaks="week"),format="%d-%m")

I tend to use function axis.POSIXct and/or function cut.POSIXt. Let's say your vector of date is time and your vector of value associated x:

plot(time,x,xaxt="n")
axis.POSIXct(side=1,at=seq(min(time),max(time),by="week"),format="%d-%m") #For instance

And, going further, with cut.POSIXt:

plot(time,x,xaxt="n")
axis.POSIXct(side=1,at=cut(time, breaks="week"),format="%d-%m")
孤独难免 2024-11-25 10:44:43

抑制绘图中轴可用的默认值(axes = FALSE,或单个轴)并使用函数 axis 来详细说明您想要的轴(特别是 at 参数) )。请参阅?轴

plot(cars, axes = FALSE)
axis( 1, at = c(5,6,7,10,11,12,21,22,23) )

Suppress the defaults available for the axis in plot ( axes = FALSE, or individual axis) and use the function axis to detail what you want for the axis (specifically the at argument). see ?axis

plot(cars, axes = FALSE)
axis( 1, at = c(5,6,7,10,11,12,21,22,23) )
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文