ggplot2:添加次要x标签(以下月份的年份)

时间:2019-05-28 10:17:29

标签: r ggplot2 timeserieschart

我的问题与:Axis labels on two lines with nested x variables (year below months)

但是,我的数据看起来有些不同。

library(dplyr)

set.seed(122)
df <- as_tibble(rlnorm(1260, meanlog = 0.06, sdlog = 0.20))

df$month <- rep(c("Jan", "Feb", "Mär", "Apr", "Mai", "Jun", 
      "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"), 5, each=21)

df$year <- rep(c("Year 1", "Year 2", "Year 3", "Year 4", "Year 5" ), 1, each=252)

我希望折线图也看起来像这样,但是如果可能的话,也不要垂直线:

enter image description here

2 个答案:

答案 0 :(得分:1)

library(tidyverse)

#data:
set.seed(122)
df <- as_tibble(rlnorm(1260, meanlog = 0.06, sdlog = 0.20))
#> Warning: Calling `as_tibble()` on a vector is discouraged, 
#> because the behavior is likely to change in the future. 
#> Use `tibble::enframe(name = NULL)` instead.

df$month <- rep(c("Jan", "Feb", "Mär", "Apr", "Mai", "Jun", 
                  "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"), 5, each=21)

df$year <- rep(c("Year 1", "Year 2", "Year 3", "Year 4", "Year 5" ), 1, each=252)

#solution:
month_lab <- rep(unique(df$month), length(unique(df$year)))

year_lab <- unique(df$year)

df %>%
  as.data.frame() %>%
  rename(price = 1) %>% 
  mutate(rnames = rownames(.)) %>% 
  ggplot(aes(x = as.numeric(rnames), y = price, 
             group = year)) +
  geom_line() +
  labs(title = "Stock Price Chart", y = "Price", x = "date") +
  scale_x_continuous(breaks = seq(1, 1260, by = 21), 
                     labels = month_lab, expand = c(0,0)) +
  facet_grid(~year, space="free_x", scales="free_x", switch="x") +
  theme(strip.placement = "outside",
        strip.background = element_rect(fill=NA,colour="grey50"),
        panel.spacing=unit(0,"cm"))

![](https://i.imgur.com/QnCsmNd.png)

reprex package(v0.3.0)于2019-05-28创建

答案 1 :(得分:0)

我可以想到两种方法,每种方法各有利弊:

数据准备:

library(dplyr)
library(tibble)
library(lubridate)
library(scales)
library(ggplot2)

set.seed(122)
df <- as_tibble(rlnorm(1260, meanlog = 0.06, sdlog = 0.20))
df$month <- rep(month.abb, 5, each=21)
df$year <- rep(c("Year 1", "Year 2", "Year 3", "Year 4", "Year 5"), 1, each=252)

# We first create a "real" date variable with year, month and day. I've chosen to add 
# "201" in from of your year, but it really doesn't matter in our case.
df <- df %>%
  group_by(year, month) %>%
  mutate(Date = as.Date(paste0("201", sub("^.+(\\d+)$", "\\1", year),
                               "-", month, "-", row_number()),
                        format = "%Y-%b-%d"))

# Since OP's daily values don't make up full months of data, 
# we need this step to show missing data correctly. 
df <- expand.grid(Date = seq.Date(from = min(df$Date), to = max(df$Date), by = "days")) %>% 
  mutate(year = paste("Year", sub("^\\d{3}(\\d)", "\\1", format(Date, "%Y"))),
         month = format(Date, "%b")) %>%
  left_join(df)

请注意,我已经使用month.abb代替了OP提供的月份,因为看起来他们使用的是非英语语言环境。

1。使用facet_grid

ggplot(df, aes(x = Date, y = value, group = year)) +
  geom_line() +
  facet_grid(. ~ year, scale = "free_x") +
  scale_x_date(labels = date_format("%b"), expand = c(0, 0)) +
  theme(panel.spacing.x = unit(0, "lines")) +
  ylim(c(0, 2.5))

enter image description here

我使用了expand中的scale_x_date来防止ggplot在每个构面的两端都添加空格,并使用panel.spacing.x来减小构面之间的间距。两者的结合给我们一种错觉,即面板已连接,但面板却没有连接(即使没有缺失值,每个构面的末端也不会连接到下一个面的开始)

2。使用geom_rect + geom_text

# Create labels
label_range <- df %>%
  group_by(year) %>%
  summarize(xmin = min(Date),
            xmax = max(Date),
            ymin = -0.5,
            ymax = ymin + 0.15)

ggplot(df) +
  geom_line(aes(x = Date, y = value)) +
  geom_rect(data = label_range, fill = "lightcoral", color = "#f2f2f2",
            aes(xmin = xmin, xmax = xmax, 
                ymin = ymin, ymax = ymax,
                group = year)) +
  geom_text(data = label_range,
            aes(x = xmin + 365/2, y = ymin + 0.1,
                group = year, label = year)) +
  coord_cartesian(ylim = c(0, 2.5), clip = "off") +
  scale_x_date(labels = date_format("%b"), 
               date_breaks = "1 month",
               expand = c(0.01, 0.01)) +
  theme_bw() +
  theme(plot.margin = unit(c(1,1,3,1), "lines"))

enter image description here

第二种方法比较繁琐,但是我们的数据将被视为一个连续序列。

  1. 创建label_range,以确定每个geom_rect四个角的坐标。

  2. 使用此数据集,我使用geom_rect绘制了“小平面框”,并使用了geom_text分组的year绘制了它们的标签。

  3. 我们希望矩形位于x轴下方,因此我使用coord_cartesian将图设置为特定的缩放比例,这样可以防止在将其设置在图外时将矩形剪裁掉。

  4. plot.margin在x轴下方为我们的构面标签添加了一些空间

  5. 注意DecJan之间的差距。它们是由缺失值引起的,这与第一种方法中的DecJan之间的差距不同。