【问题标题】:Reproduce a 'The Economist' chart with dual axis重现具有双轴的“经济学人”图表
【发布时间】:2016-05-20 12:45:13
【问题描述】:

我试图复制这个 chart 来自经济学人(左边那个)。该图表在左侧 y 轴上绘制了俄罗斯的亿万富翁数量,在右侧绘制了世界其他地区的亿万富翁数量。

  1. 为俄罗斯亿万富翁创建图表 (p1)。
  2. 为其他人创建图表 (p2)。
  3. 使用Kohske 的代码将p1p2 组合成一个双y 轴图表。

数据:(billionaire.csv的内容)

,Russia,World
1996,0,423
1997,4,220
1998,1,221
1999,0,298
2000,0,322
2001,8,530
2002,6,466
2003,17,459
2004,25,562
2005,27,664
2006,33,760
2007,53,893
2008,87,1038
2009,32,761
2010,62,949
2011,101,1109
2012,96,1130
2013,110,1317
2014,111,1535
2015,88,1738

代码:

library(ggplot2)
library(gtable)
library(grid)
library(extrafont) # for Officiana font
dat <- read.csv("billionaire.csv")
rus <- dat[,1:2]
world <- dat[,-2]

grid.newpage()
p1 <- ggplot(rus, aes(X, Russia)) + geom_line(colour = "#68382C", size = 1.5) + ggtitle("Number in Russia") +
  ylim(0, 200) + labs(x="",y="") +
  theme(#plot.margin = unit(c(2,1,0,0), "cm"),
    panel.grid.minor = element_blank(), 
    panel.grid.major = element_line(color = "gray50", size = 0.5),
    panel.grid.major.x = element_blank(),
    text=element_text(family="ITCOfficinaSans LT Book"),
    axis.text.y = element_text(colour="#68382C", size = 14),
    axis.text.x = element_text(size = 14),
    axis.ticks = element_line(colour = 'gray50'),
    plot.title = element_text(hjust = -0.17, vjust=2.12, colour="#68382C", size = 14, family = "ITCOfficinaSans LT Bold")) 

p2 <- ggplot(world, aes(X, World)) + geom_line(colour = "#00a4e6", size = 1.5) +  #ggtitle("Rest of world") +
  ylim(0, 2000) + labs(x="",y="") +
  theme(#plot.margin = unit(c(2,1,0,0), "cm"),
    panel.grid.minor = element_blank(), 
    panel.grid.major = element_blank(),
    text = element_text(family="ITCOfficinaSans LT Book"),
    axis.text.y = element_text(colour="#00a4e6", size=14),
    axis.text.x = element_text(size=14),
    axis.ticks = element_blank(),
    plot.title = element_text(hjust = 0.2, vjust=2.12, colour="#00a4e6", size = 14, family = "ITCOfficinaSans LT Bold"))

# Combining p1 and p2
g1 <- ggplot_gtable(ggplot_build(p1))
g2 <- ggplot_gtable(ggplot_build(p2))

pp <- c(subset(g1$layout, name == "panel", se = t:r))
g <- gtable_add_grob(g1, g2$grobs[[which(g2$layout$name == "panel")]], pp$t, 
                             pp$l, pp$b, pp$l)

ia <- which(g2$layout$name == "axis-l")
ga <- g2$grobs[[ia]]
ax <- ga$children[[2]]
ax$widths <- rev(ax$widths)
ax$grobs <- rev(ax$grobs)


g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)
ggsave("plot.pdf",g, width=5, height=5)

要使用我选择的字体和颜色来格式化文本“俄罗斯的数字”和“世界其他地区”,我将它们放在ggtitle 中。但是在步骤 3 中将图表组合在一起后,p2 的标题不见了,所以这就是我得到的全部

我想要实现的是
1. 以我选择的颜色和字体系列(不是默认的 Helvetica)添加文本“世界其他地区”。
2.在x轴上添加标签1996。

感谢任何帮助。谢谢!

编辑:添加了数据集和完整代码。
EDIT2:仅供参考,我从这里获得了所有的 Officiana 字体:http://people.oregonstate.edu/~hanshumw/Specie%20I.D./Signage%20Backup/FONT%20Officina%20full/
EDIT3:好的,我终于如何通过在网格级别摆弄情节来使其工作

g$grobs[[8]]$children$GRID.text.526$label <- c("Number in Russia", "Rest of World")
g$grobs[[8]]$children$GRID.text.526$gp$col <- c("#68382C","#00a4e6")
g$grobs[[8]]$children$GRID.text.526$x <- unit(c(-0.175, 0.774), "npc")

将此块放在ggsave(...) 之前,结果如下:

【问题讨论】:

  • 从 "+ #ggtitle("Rest of world")" 中删除 # 可能会有所帮助。
  • 请注意,在ggthemes 包中,有一个theme_economist()。这可能对您的问题没有帮助,但可能有助于节省一些输入。
  • @coffeinjunky 像theme_excel 吗?
  • @RHA:我已经试过了,但什么也没发生,所以我把它注释掉了。
  • 请在您的帖子中包含重现该图所需的所有数据和代码,因此数据(不是链接)以及 Kohske 的代码。我认为他不会介意(只要哈德利不会看到)

标签: r ggplot2 gtable


【解决方案1】:

这是一个使用 R 基础图形而不是 ggplot 的解决方案。我没有更改字体系列,因为它只能在安装了相同字体的系统之间移植(我这里没有 Officiana)。将family 参数添加到mtext 很容易。

par(mar = c(3, 3, 3, 3), las = 1)
plot(tmp[,c(1,3)], type = 'n', axes = FALSE, ylim = c(0, 2000))
abline(h = c(0, 500, 1000, 1500, 2000), col = "grey")
points(tmp[,c(1,3)], type = 'l', col = "blue", lwd = 2)
points(x = tmp[,1], y = tmp[,2] * 10, type = 'l', col = "brown", lwd = 2)
axis(side = 4, at = c(0, 500, 1000, 1500, 2000), tick = FALSE,
     col.axis = "blue", line = 1, hadj = 1)
axis(side = 2, at = c(0, 500, 1000, 1500, 2000), tick = FALSE,
     col.axis = "brown", hadj = 1,
     labels = c(0, 50, 100, 150, 200))
axis(side = 1, at = c(1996, 2000, 2005, 2010, 2015), lwd = 0, line = -1,
     lwd.ticks = 2, col.ticks = "grey")
mtext("Number in Russia", side = 2, col = "brown", at = 2150, line = 2.5,
      adj = 0)
mtext("Rest of World", side = 4, col = "blue", at = 2150, line = 2,
      adj = 1)

【讨论】:

    【解决方案2】:

    当然,在gridgtable 的帮助下,可以使用gplot2 来完成。我不会尝试在 ggplots 中放置轴标签;而是将轴标签绘制在自己的 grob 中,然后定位到 gtable 中。

    这利用了来自here 的代码,而后者又利用了来自herecowplot 包的代码)。 (在使用ggplot2 2.1.0 版绘制的叠加图中,需要做更多的工作才能获得定位良好的刻度线和刻度线标签。请注意,例如,它们与原始 The Economist 中一样左对齐em> 渲染。)

    # Data
    dat = read.csv(text = ",Russia,World
    1996,0,423
    1997,4,220
    1998,1,221
    1999,0,298
    2000,0,322
    2001,8,530
    2002,6,466
    2003,17,459
    2004,25,562
    2005,27,664
    2006,33,760
    2007,53,893
    2008,87,1038
    2009,32,761
    2010,62,949
    2011,101,1109
    2012,96,1130
    2013,110,1317
    2014,111,1535
    2015,88,1738", header  = TRUE)
    
    rus <- dat[,1:2]
    world <- dat[,-2]
    
    # Packages
    library(ggplot2)
    library(gtable)
    library(grid)
    
    # The ggplots
    p1 <- ggplot(rus, aes(X, Russia)) + 
      geom_line(colour = "#68382C", size = 1.5) + 
      scale_x_continuous("", breaks = c(1996, seq(2000, 2015, 5))) +
      scale_y_continuous("", lim = c(0, 200), expand = c(0, 0)) +
      theme_bw() +
      theme(panel.grid.minor = element_blank(), 
        panel.grid.major = element_line(color = "gray50", size = 0.5),
        panel.grid.major.x = element_blank(),
        axis.text.y = element_text(colour = "#68382C", size = 14),
        axis.text.x = element_text(size = 14),
        axis.ticks = element_line(colour = 'gray50'),
        panel.border = element_blank(),
        plot.margin = unit(c(40, 20, 80, 20), "pt"))
    
    p2 <- ggplot(world, aes(X, World)) + 
      geom_line(colour = "#00a4e6", size = 1.5) +  
      scale_x_continuous("", breaks= c(1996, seq(2000, 2015, 5))) +
      scale_y_continuous("", lim = c(0, 2000), expand = c(0, 0)) +
      theme_bw() +
      theme(panel.grid.minor = element_blank(), 
        panel.grid.major = element_blank(),
        axis.text.y = element_text(colour = "#00a4e6", size = 14),
        axis.text.x = element_text(size = 14),
        axis.ticks = element_line(colour = 'gray50'),
        panel.border = element_blank(),
        panel.background = element_rect(fill = "transparent"))
    
    # Get the plot grobs
    g1 <- ggplotGrob(p1)
    g2 <- ggplotGrob(p2)
    
    # Get the location of the plot panel in g1
    pp <- c(subset(g1$layout, name == "panel", se = t:r))
    
    # Overlap panel for second plot on that of the first plot
    g1 <- gtable_add_grob(g1, g2$grobs[[which(g2$layout$name == "panel")]], pp$t, pp$l, pp$b, pp$l)
    
    # ggplot contains many labels that are themselves complex grob; 
    # usually a text grob surrounded by margins.
    # When moving the grobs from, say, the left to the right of a plot,
    # make sure the margins and the justifications are swapped around.
    # The function below does the swapping.
    # Taken from the cowplot package:
    # https://github.com/wilkelab/cowplot/blob/master/R/switch_axis.R 
    hinvert_title_grob <- function(grob){
    
      # Swap the widths
      widths <- grob$widths
      grob$widths[1] <- widths[3]
      grob$widths[3] <- widths[1]
      grob$vp[[1]]$layout$widths[1] <- widths[3]
      grob$vp[[1]]$layout$widths[3] <- widths[1]
    
      # Fix the justification
      grob$children[[1]]$hjust <- 1 - grob$children[[1]]$hjust 
      grob$children[[1]]$vjust <- 1 - grob$children[[1]]$vjust 
      grob$children[[1]]$x <- unit(1, "npc") - grob$children[[1]]$x
      grob
    }
    
    # Get the y axis from g2 (axis line, tick marks, and tick mark labels)
    index <- which(g2$layout$name == "axis-l")  # Which grob
    yaxis <- g2$grobs[[index]]                  # Extract the grob
    
    # yaxis is a complex of grobs containing the axis line, the tick marks, and the tick mark labels.
    # The relevant grobs are contained in axis$children:
    #   axis$children[[1]] contains the axis line;
    #   axis$children[[2]] contains the tick marks and tick mark labels.
    
    # Second, swap tick marks and tick mark labels
    ticks <- yaxis$children[[2]]
    ticks$widths <- rev(ticks$widths)
    ticks$grobs <- rev(ticks$grobs)
    
    # Third, move the tick marks
    # Tick mark lengths can change. 
    # A function to get the original tick mark length
    # Taken from the cowplot package:
    # https://github.com/wilkelab/cowplot/blob/master/R/switch_axis.R 
    plot_theme <- function(p) {
      plyr::defaults(p$theme, theme_get())
    }
    
    tml <- plot_theme(p1)$axis.ticks.length   # Tick mark length
    ticks$grobs[[1]]$x <- ticks$grobs[[1]]$x - unit(1, "npc") + tml
    
    # Fourth, swap margins and fix justifications for the tick mark labels
    ticks$grobs[[2]] <- hinvert_title_grob(ticks$grobs[[2]])
    
    # Fifth, put ticks back into yaxis
    yaxis$children[[2]] <- ticks
    
    # Put the transformed yaxis on the right side of g1
    g1 <- gtable_add_cols(g1, g2$widths[g2$layout[index, ]$l], pp$r)
    g1 <- gtable_add_grob(g1, yaxis, pp$t, pp$r + 1, pp$b, pp$r + 1, clip = "off", name = "axis-r")
    
    # Labels grob
    left = textGrob("Number in Russia", x = 0, y = 1, just = c("left", "top"), gp = gpar(fontsize = 14, col =  "#68382C"))
    right =  textGrob("Rest of World", x = 1, y = 1, just = c("right", "top"), gp = gpar(fontsize = 14, col =  "#00a4e6"))
    labs = gTree("Labs", children = gList(left, right))
    
    # New row in the gtable for labels - immediately above the panel
    pos = g1$layout[grepl("panel", g1$layout$name), c('t', 'l')]
    height = unit(3, "grobheight", left)
    g1 <- gtable_add_rows(g1, height, pos$t-1)  
    
    # Put the label in the new row
    g1 = gtable_add_grob(g1, labs, t = pos$t-1, l = pos$l-1, r = pos$l+1)
    
    # Remove a column y label
    g1 = g1[, -2]
    
    # Grey rectangle
    rect = rectGrob(gp = gpar(col = NA, fill = "grey90"))
    
    # Put the grey rectangles into the margin columns and rows
    g1 = gtable_add_grob(g1, list(rect, rect), t = 1, b = length(g1$heights), l = c(1, length(g1$widths)))
    g1 = gtable_add_grob(g1, list(rect, rect), t = c(1, length(g1$heights)), l = 1, r = length(g1$widths))
    
    # Draw it
    grid.newpage()
    grid.draw(g1)
    

    【讨论】:

    • 谢谢,这确实是我想要的。既然您对gridgtable 如此熟悉,那么您是否知道如何将g 覆盖在这样的灰色背景上:i.imgur.com/OmPandU.png
    • 可能有几种方法。在这里,我为 p1 添加了边距,然后在边距行和列中添加了灰色矩形。我已经更新了答案。
    • 太棒了!今天用gtable学到了一些技巧,谢谢!
    【解决方案3】:

    您用于组合图的代码在我的 R 会话中不起作用,因此我无法帮助您。但这里是你问的两个问题:

    。使用ggtitle
    2.使用scale_x_continuous
    3.注意:我也把你的ylim改成lims,把你的labs改成theme(..., axis.title= element_blank(), ...)

    p1 <- ggplot(rus, aes(X, Russia)) + geom_line(colour = "#68382C", size = 1.5) + ggtitle("Number in Russia") +
      lims(y= c(0, 200)) + 
      scale_x_continuous(breaks= c(1996, seq(2000,2015,5))) +
      theme(#plot.margin = unit(c(2,1,0,0), "cm"),
        panel.grid.minor = element_blank(), 
        panel.grid.major = element_line(color = "gray50", size = 0.5),
        panel.grid.major.x = element_blank(),
        text=element_text(family="ITCOfficinaSans LT Book"),
        axis.text.y = element_text(colour="#68382C", size = 14),
        axis.text.x = element_text(size = 14),
        axis.title= element_blank(),
        axis.ticks = element_line(colour = 'gray50'),
        plot.title = element_text(hjust=0,vjust=2.12, colour="#68382C", size = 14, family = "ITCOfficinaSans LT Bold")) 
    
    p2 <- ggplot(world, aes(X, World)) + geom_line(colour = "#00a4e6", size = 1.5) + ggtitle("Rest of World") +
      lims(y= c(0, 2000)) +  scale_x_continuous(breaks= c(1996, seq(2000,2015,5))) +
      theme(#plot.margin = unit(c(2,1,0,0), "cm"),
        panel.grid.minor = element_blank(), 
        panel.grid.major = element_blank(),
        text = element_text(family="ITCOfficinaSans LT Book"),
        axis.text.y = element_text(colour="#00a4e6", size=14),
        axis.text.x = element_text(size=14),
        axis.title= element_blank(),
        axis.ticks = element_blank(),
        plot.title = element_text(hjust = 1, vjust=2.12, colour="#00a4e6", size = 14, family = "ITCOfficinaSans LT Bold"))
    

    【讨论】:

    • 感谢scale_x_continuous的提示!
    【解决方案4】:

    仅使用 ggplot2 即可创建此图,如下所示:https://rpubs.com/chidungkt/564046

    【讨论】:

      猜你喜欢
      • 2015-07-03
      • 1970-01-01
      • 2020-07-24
      • 1970-01-01
      • 2010-09-28
      • 1970-01-01
      • 2022-07-08
      • 1970-01-01
      • 2021-08-30
      相关资源
      最近更新 更多