为了账号安全,请及时绑定邮箱和手机立即绑定

带有嵌套x变量的两行的轴标签(年份低于月份)

/ 猿问

带有嵌套x变量的两行的轴标签(年份低于月份)

摇曳的蔷薇 2019-11-28 12:45:57

我想在横轴上显示月份(缩写形式),并将相应的年份打印一次。我知道如何显示月份年份:


在此处输入图片说明


一年中不必要的重复会打乱标签。相反,我想要这样的东西:


在此处输入图片说明


除了年份将 在月份下方打印。


我在轴标签上方打印了年份,因为这是我能做的最好的事情。这是对annotate()功能的限制,如果该功能位于绘图区域之外,则会受到限制。我知道基于的可能解决方法annotate_custom(),但是我无法使它们与日期对象一起使用(我没有尝试将日期转换为数字并再次返回到日期,因为它看起来比希望的要复杂得多)


我想知道是否dup_axis()可以为此目的劫持新产品。如果可以将重复的轴发送到面板的另一侧,而不是将重复的轴发送到面板的另一侧,则可能只需要设置一个panel.grid.major消隐的轴并将标签设置为%b,另一个轴将panel.grid.minor消隐,标签设置为%Y。(另一个挑战是,年份标签将改为10月而不是1月)


这些问题是相关的。但是,据我所知,该annotate_custom()功能textGrob()与日期不能很好地配合使用。


我如何在ggplot2中的x轴下方添加注释


在ggplot2生成的情节下面显示文本


数据和基本代码如下:


    library("ggplot2")

    library("scales")

    ggplot(data = df, aes(x = Date, y = value)) + geom_line() +

        scale_x_date(date_breaks = "2 month", date_minor_breaks = "1 month", labels = date_format("%b %Y")) +

        xlab(NULL)


    ggplot(data = df, aes(x = Date, y = value)) + geom_line() +

        scale_x_date(date_minor_breaks = "2 month", labels = date_format("%b")) +   

        annotate(geom = "text", x = as.Date("1719-10-01"), y = 0, label = "1719") +

        annotate(geom = "text", x = as.Date("1720-10-01"), y = 0, label = "1720") +

        xlab(NULL)



    # data

    df <- structure(list(Date = structure(c(-91455, -91454, -91453, -91452, 

    -91451, -91450, -91448, -91447, -91446, -91445, -91444, -91443, 

    -91441, -91440, -91439, -91438, -91437, -91436, -91434, -91433, 

    -91431, -91430, -91429, -91427, -91426, -91425, -91424, -91423, 

    -91422, -91420, -91419, -91418, -91417, -91416, -91415, -91413, 

    -91412, -91411, -91410, -91409, -91408, -91406, -91405, -91404, 

    -91403, -91402, -91401, -91399, -91398, -91397, -91396, -91395, 

    -91394, -91392, -91391, -91390, -91389, -91388, -91387, -91385, 

    -91384, -91382, -91381, -91380, -91379, -91377, -91376, -91375, 

    -91374, -91373, -91372, -91371, -91370, -91369, -91368, -91367, 

    -91366, -91364, -91363, -91362, -91361, -91360, -91359, -91357, 

    -91356, -91355, -91354, -91353, -91352, -91350, -91349, -91348, 

    -91347, -91346, -91345, -91343, -91342, -91341, -91340, -91339, 


查看完整描述

3 回答

?
慕桂英4014372

下面的代码为添加年份标签提供了两种可能的选择。


选项1a:构面

您可以使用构面来标记年份。例如:


library(ggplot2)

library(lubridate)


ggplot(df, aes(Date, value)) +

  geom_line() +

  scale_x_date(date_labels="%b", date_breaks="month", expand=c(0,0)) +

  facet_grid(~ year(Date), space="free_x", scales="free_x", switch="x") +

  theme_bw() +

  theme(strip.placement = "outside",

        strip.background = element_rect(fill=NA,colour="grey50"),

        panel.spacing=unit(0,"cm"))


请注意,使用这种方法时,如果在年初或年底缺少日期(通过“丢失”,我的意思是这些日期中的行甚至没有出现在数据中),则x轴将开始于/结束于该年度数据中的第一个/最后一个日期,而不是从1月1日到12月31日。在这种情况下,您需要为缺少的日期添加行,并NA为value或插值value。此外,使用这种方法,在一年的12月31日到次年的1月1日之间没有空格或线条,因此每年都存在不连续性。


选项1b:构面+居中月份标签

解决@ AF7的评论。您可以通过在每个标签之前添加一些空格来使月份标签居中。但是您必须手动选择空格数,具体取决于打印到设备上时图形的物理尺寸。(可能有一种方法可以根据内部grob测量值以编程方式使标签居中,但我不确定该怎么做。)我还删除了较小的垂直网格线并减轻了几年之间的线条。


ggplot(df, aes(Date, value)) +

  geom_line() +

  scale_x_date(date_labels=paste(c(rep(" ",11), "%b"), collapse=""), 

               date_breaks="month", expand=c(0,0)) +

  facet_grid(~ year(Date), space="free_x", scales="free_x", switch="x") +

  theme_bw() +

  theme(strip.placement = "outside",

        strip.background = element_blank(),

        panel.grid.minor.x = element_blank(),

        panel.border = element_rect(colour="grey70"),

        panel.spacing=unit(0,"cm"))


选项2a:编辑x轴标签组

这是一种更复杂,更挑剔的方法(尽管可能比了解我的人更了解网格图形的结构和单位间距的人可以自动化),它避免了上述刻面方法的缺陷:


library(grid)


# Fake data with an extra year added for illustration

set.seed(2)

df = data.frame(Date=seq(as.Date("1718-03-01"),as.Date("1721-09-20"), by="1 day"))

df$value = cumsum(rnorm(nrow(df)))


# The plot we'll start with

p = ggplot(df, aes(Date, value)) +

  geom_vline(xintercept=as.numeric(df$Date[yday(df$Date)==1]), colour="grey60") +

  geom_line() +

  scale_x_date(date_labels="%b", date_breaks="month", expand=c(0,0)) +

  theme_bw() +

  theme(panel.grid.minor.x = element_blank()) +

  labs(x="")


现在,我们要在每年的六月和七月之间的下方和之间添加年份值。下面的代码通过修改x轴标签grob来做到这一点,并通过@SandyMuspratt 对此SO答案进行了改编。


# Get the grob

g <- ggplotGrob(p)


# Get the y axis

index <- which(g$layout$name == "axis-b")  # Which grob

xaxis <- g$grobs[[index]]   


# Get the ticks (labels and marks)

ticks <- xaxis$children[[2]]


# Get the labels

ticksB <- ticks$grobs[[2]]


# Edit x-axis label grob

# Find every index of Jun in the x-axis labels and add a newline and

# then a year label

junes = which(ticksB$children[[1]]$label == "Jun")

ticksB$children[[1]]$label[junes] = paste0(ticksB$children[[1]]$label[junes],

                                           "\n      ", unique(year(df$Date))) 


# Put the edited labels back into the plot

ticks$grobs[[2]] <- ticksB

xaxis$children[[2]] <- ticks

g$grobs[[index]] <- xaxis


# Draw the plot

grid.newpage()

grid.draw(g)


选项2b:编辑x轴标签grob并将月份标签居中

以下是对选项2a进行的唯一更改,以使月份标签居中,但是,再次,需要手动调整空格数。


# Make the edit

# Center the month labels between ticks

ticksB$children[[1]]$label = paste0(paste(rep(" ",7),collapse=""), ticksB$children[[1]]$label)


# Find every index of Jun in the x-axis labels and a year label

junes = grep("Jun", ticksB$children[[1]]$label)

ticksB$children[[1]]$label[junes] = paste0(ticksB$children[[1]]$label[junes], "\n      ", unique(year(df$Date))) 


查看完整回答
反对 2019-11-28
?
幕布斯5086720

如果您想尝试合并一个子标签,可以将其转换为grob。我在原始帖子中对此进行了编辑,以创建一个添加子标签并返回一个gtable对象的函数。请注意,sublabs输入的长度必须与x轴中断点的长度相同:


library(grid)

library(gtable)

library(gridExtra)


add_sublabs <- function(plot, sublabs){


  gg <- ggplotGrob(plot)


  axis_num <- which(gg$layout[,"name"] == "axis-b")


  xbreaks <- gg[["grobs"]][[axis_num]][["children"]][[2]][["grobs"]][[2]][["children"]][[1]]$x

  if(length(xbreaks) != length(sublabs)) stop("Sub-labels must be the same length as the x-axis breaks")


  to_breaks <- c(as.numeric(xbreaks),1)[which(!duplicated(sublabs, fromLast = TRUE))+1]

  sublabs_x <- diff(c(0,to_breaks))

  sublabs_labels <- sublabs[!duplicated(sublabs, fromLast = TRUE)]


  tg <- tableGrob(matrix(sublabs_labels, nrow = 1))

  tg$widths = unit(sublabs_x, attr(xbreaks,"unit"))


  pos <- gg$layout[axis_num,c("t","l")]


  gg2 <- gtable_add_rows(gg, heights = sum(tg$heights)+unit(4,"mm"), pos = pos$t)

  gg3 <- gtable_add_grob(gg2, tg, t = pos$t+1, l = pos$l)


  return(gg3)

}



#Plot and sublabels

p <- ggplot(data = df, aes(x = Date, y = value)) + geom_line() +

  scale_x_date(date_breaks = "2 month", date_minor_breaks = "1 month", labels = date_format("%b")) +

  xlab(NULL)

sublabs <- c(rep("1719",2),rep("1720",6))


#Draw

grid.draw(add_sublabs(p, sublabs))


查看完整回答
反对 2019-11-28
?
手掌心

我遇到了这个问题,可能我可以添加一个解决方案。通过使用简单条件,我们可以在每年的第一个显示月份中同时显示月份和年份。您可以玩date_breaks来从标签中删除1月,并且仍然可以使用。我正在使用month()和year()从lubridate。


library(tidyverse)

library(lubridate)


df %>% 

   ggplot(aes(Date, value)) +

   geom_line() +

   scale_x_date(date_breaks = "2 months", 

                labels = function(x) if_else(is.na(lag(x)) | !year(lag(x)) == year(x), 

                                             paste(month(x, label = TRUE), "\n", year(x)), 

                                             paste(month(x, label = TRUE))))


查看完整回答
反对 2019-11-28
  • 3 回答
  • 0 关注
  • 181 浏览

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信