【问题标题】:Can this chart be created in R using ggplot2?可以使用 ggplot2 在 R 中创建此图表吗?
【发布时间】:2019-02-04 07:48:54
【问题描述】:

假设我在R 中有以下dataframe

df1 <- read.csv("jan.csv", stringsAsFactors = FALSE, header = TRUE)
str(df1)

'data.frame':   4 obs. of  5 variables:
 $ JANUARY: chr  "D-150" "D-90" "D-60" "D-30"
 $ X2016  : num   0.24    0.5    0.63   0.76
 $ X2017  : num   0.32    0.45   0.6    0.79
 $ X2018  : num   0.2     0.4    0.61   0.82
 $ X2019  : num   0.21    0.35   0.63   0.85

如何使用ggplot2 输出如下图(在Excel 制作):

我很乐意在ggplot2 中生成一个简单的column chart,但我正在努力按上面所示的方式对条形进行分组并放置相关标签。另外,我需要重塑数据来实现这一点吗?

【问题讨论】:

  • 您可以使用gplot2geom_col()facet_wrap()geom_text 来实现与此接近的目标。你试过什么这么安全?
  • 这些年份标签是否可能在栏上指定错误? x 轴上的每个“D”标签是否应该分别具有 2016、2017、2018 和 2019 年?
  • @MikeH。是的,你是对的!我会更正。

标签: r ggplot2 charts


【解决方案1】:

是的,你可以。我认为你的年份标签不正确。检查我的情节:

这是生成绘图的代码:

library(tidyverse)

df1 %>%
  gather(year, value, X2016:X2019) %>%
  mutate(JANUARY = JANUARY %>% fct_rev() %>% fct_relevel('D-150')) %>%
  group_by(JANUARY) %>%
  mutate(y_pos = min(value) / 2) %>%
  ggplot(aes(
    x = JANUARY,
    y = value,
    fill = JANUARY,
    group = year
  )) +
  geom_col(
    position = position_dodge(.65),
    width = .5
  ) +
  geom_text(aes(
      y = value + max(value) * .03,
      label = round(value * 100) %>% str_c('%')
    ),
    position = position_dodge(.65)
  ) +
  geom_text(aes(
      y = y_pos,
      label = str_remove(year, 'X')
    ),
    color = 'white',
    angle = 90,
    fontface = 'bold',
    position = position_dodge(.65)
  ) +
  scale_y_continuous(
    breaks = seq(0, .9, .1),
    labels = function(x) round(x * 100) %>% str_c('%')
  ) +
  scale_fill_manual(values = c(
    rgb(47, 85, 151, maxColorValue = 255),
    rgb(84, 130, 53, maxColorValue = 255),
    rgb(244, 177, 131, maxColorValue = 255),
    rgb(112, 48, 160, maxColorValue = 255)
  )) +
  theme(
    plot.title = element_text(hjust = .5),
    panel.background = element_blank(),
    panel.grid.major.y = element_line(color = rgb(.9, .9, .9)),
    axis.ticks = element_blank(),
    legend.position = 'none'
  ) +
  xlab('') +
  ylab('') +
  ggtitle('Month of JANUARY')

【讨论】:

  • 谢谢。您是否使用特定的库来转换数据,因为我收到此特定错误消息:“mutate_impl(.data, dots) 中的错误:评估错误:找不到函数“fct_rev”。?
  • 加载tidyverse 包。
  • 这很奇怪。 tidyverse 加载 forcats 包...尝试独立加载 forcats
  • 我会尝试更新我的 tidyverse 库,看看效果如何。
【解决方案2】:

通过更多的数据处理,我认为您可以实现您想要的。我们首先将数据融合为长格式,这是ggplot 对这种类型的绘图所需要的。然后我们创建一个单独的标签数据集,其中包含 y 值(在每个“D”组中似乎是最小值):

df_m <- melt(df, id.vars = "JANUARY")
df_m$above_text <- scales::percent(df_m$value)
labels <- df_m
labels$value <- ave(labels$value, labels$JANUARY, FUN = function(x) min(x/2))
labels$variable <- sub("X", "", labels$variable)
pos_d <- position_dodge(width = 0.7)

ggplot(df_m, aes(x = JANUARY, y = value, group = variable, fill = JANUARY)) + 
  geom_col(width = 0.6, position = pos_d) +
  geom_text(aes(label = above_text), position = pos_d, size = 2, hjust = 0.5, vjust = -1) + 
  geom_text(data = labels, aes(x = JANUARY, y = value, group = variable, label = variable), angle = 90, position = pos_d, hjust = 0.5)

请注意,您可以使用 % 标签大小。什么看起来不错取决于图像文件的实际尺寸。对我来说看起来不错的是 2.75 左右,但在这里复制为图像看起来很拥挤。

数据:

df <- data.frame(JANUARY = c("D-150", "D-90", "D-60", "D-30"),
                 X2016   = c(0.24, 0.5, 0.63, 0.76),
                 X2017   = c(0.32, 0.45, 0.6, 0.79),
                 X2018   = c(0.2, 0.4, 0.61, 0.82),
                 X2019   = c(0.21, 0.35, 0.63, 0.85), stringsAsFactors = FALSE)

【讨论】:

    【解决方案3】:

    我的方法

    样本数据

    library( data.table )
    
    dt <- fread('year  "D-150" "D-90" "D-60" "D-30"
    2016   0.24    0.5    0.63   0.76
    2017   0.32    0.45   0.6    0.79
    2018   0.2     0.4    0.61   0.82
    2019   0.21    0.35   0.63   0.85', header = TRUE)
    

    代码

    #first, melt
    dt.melt <- melt( dt, id.vars = "year", variable.name = "Dvalue", value.name = "value" )
    #create values (=positions in the chart) for the year-text within the bars.
    dt.melt[, yearTextPos := min( value / 2 ), by = "Dvalue"]
    
    #then build chart
    library( ggplot2 )
    library( scales)
    ggplot( dt.melt, aes( x = Dvalue, y = value, group = year, fill = Dvalue ) ) + 
      #build the bars, dodged position
      geom_col( width = 0.6, position = position_dodge(width = 0.75) ) +
      #set up the y-scale
      scale_y_continuous( limits = c(0,1), breaks = seq(0,1,0.1), 
                          labels = scales::percent, expand = c(0,0) ) +
      #insert year-text in bars, at the previuously calculated positions
      geom_text( aes( x = Dvalue, y = yearTextPos, group = year, label = year ), 
                 color = "white", position = position_dodge( width = 0.75  ), 
                 hjust = 0.5, angle = 90, size = 5 ) +
      #wite value on top as percentage
      geom_text( aes( x = Dvalue, y = value + 0.01, group = year, 
                      label = paste0( round( value * 100), "%" ) ), 
                 color = "black", position = position_dodge( width = 0.75  ), 
                 hjust = 0.5, angle = 0, size = 3 )
    

    输出

    【讨论】:

      【解决方案4】:

      是的,是可行的。但是,首先我们需要将您的数据以真正的表格格式(就像您要导出到 sql 一样)。

      所以,这是你的数据:

      January = c("D-150","D-90","D-60")
      x2016 = c(0.24 ,   0.5,    0.63)
      x2017 = c(0.32  ,  0.45,   0.6)
      x2018 = c(0.2   ,  0.4  ,  0.61)
      df1 <- data.frame(January,x2016,x2017,x2018)
      

      要以某种方式绘制它,我们必须将您的年份列合并为 2 列,如下所示:

      library(tidyr)
      nuevoDf1<-gather(data = df1, losAnhos,valores,-January)
      

      结果将如下所示:

        January losAnhos valores 
      1   D-150    x2016    0.24 
      2    D-90    x2016    0.50 
      3    D-60    x2016    0.63 
      4   D-150    x2017    0.32 
      5    D-90    x2017    0.45
      

      最后,使用 ggplot2,您可以通过以下方式开始您的图表:

      ggplot(nuevoDf1,aes(losAnhos,valores)) + 
        facet_wrap(~January)+
        geom_bar(stat="sum",na.rm=TRUE)
      

      结果将与图片中的结果类似。我不是颜色的忠实粉丝,但 ggplot2 允许在情节构建后进行自定义。希望这能让你走上正确的道路,只是为了弄清楚图表的短暂和瞬间的美丽。

      【讨论】:

        【解决方案5】:

        首先,我使用gather 将数据从宽格式转换为长格式,然后使用parse_number 将原始列名(X2016X2017、...)转换为数值变量。我使用fct_inorder 按出现的顺序排列JANUARY 的级别。

        library(tidyverse)
        
        df1_long <- df1 %>% 
          gather(year, percentage, -JANUARY) %>% 
          mutate(year = parse_number(year), 
                 JANUARY = fct_inorder(JANUARY)) 
        
        df1_long
        
        #    JANUARY year percentage
        # 1    D-150 2016       0.24
        # 2     D-90 2016       0.50
        # 3     D-60 2016       0.63
        # 4     D-30 2016       0.76
        # 5    D-150 2017       0.32
        # 6     D-90 2017       0.45
        # 7     D-60 2017       0.60
        # 8     D-30 2017       0.79
        # 9    D-150 2018       0.20
        # 10    D-90 2018       0.40
        # 11    D-60 2018       0.61
        # 12    D-30 2018       0.82
        # 13   D-150 2019       0.21
        # 14    D-90 2019       0.35
        # 15    D-60 2019       0.63
        # 16    D-30 2019       0.85
        

        然后可以将这些数据用于绘图。

        ggplot(df1_long, aes(year, percentage, fill = JANUARY)) +
          geom_col() +
          scale_y_continuous(labels = scales::percent, expand = c(0, 0), limits = c(0, 1)) +
          facet_wrap(~ JANUARY, nrow = 1, strip.position = "bottom") +
          geom_text(aes(label = year), y = 0.1, angle = 90, color = "white")  +
          geom_text(aes(label = str_c(percentage*100, "%")), vjust = -0.5) +
          ggtitle("Month of JANUARY") +
          scale_fill_manual(values = c("darkblue", "darkgreen", "burlywood2", "darkorchid4")) +
          theme_minimal() +
          theme(axis.text.x = element_blank(), 
                axis.ticks.x = element_blank(), 
                axis.title = element_blank(),
                panel.spacing = unit(0, "cm"),
                panel.grid.major.x = element_blank(),
                panel.grid.minor.x = element_blank(),
                legend.position = "none")
        

        数据

        df1 <- data.frame(JANUARY = c("D-150", "D-90", "D-60", "D-30"),
                          X2016   = c(0.24, 0.5, 0.63, 0.76),
                          X2017   = c(0.32, 0.45, 0.6, 0.79),
                          X2018   = c(0.2, 0.4, 0.61, 0.82),
                          X2019   = c(0.21, 0.35, 0.63, 0.85))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-11-25
          • 2019-10-27
          • 2018-05-11
          • 2021-08-17
          • 1970-01-01
          • 1970-01-01
          • 2023-02-21
          • 2010-12-16
          相关资源
          最近更新 更多