首页 文章

如何在ggplot2的右侧放置转换后的比例?

提问于
浏览
18

我在下面附上了一个简单的例子 . 我想在图的右侧添加一个刻度(刻度线和注释),以英尺为单位显示高程 . 我知道ggplot2不会允许两个不同的比例(见Plot with 2 y axes, one y axis on the left, and another y axis on the right),但因为这是相同比例的转换,有没有办法做到这一点?我更喜欢继续使用ggplot2而不必恢复到plot()函数 .

library(ggplot2)
LakeLevels<-data.frame(Day=c(1:365),Elevation=sin(seq(0,2*pi,2*pi/364))*10+100)
p <- ggplot(data=LakeLevels) + geom_line(aes(x=Day,y=Elevation)) + 
  scale_y_continuous(name="Elevation (m)",limits=c(75,125)) 
p

4 回答

  • 5

    你应该看一下这个链接http://rpubs.com/kohske/dual_axis_in_ggplot2 .

    我已经根据你的例子调整了那里提供的代码 . 这个修复看起来非常“hacky”,但它会让你成为那里的一部分 . 剩下的唯一部分是弄清楚如何将文本添加到图表的右轴 .

    library(ggplot2)
        library(gtable)
        library(grid)
        LakeLevels<-data.frame(Day=c(1:365),Elevation=sin(seq(0,2*pi,2*pi/364))*10+100)
        p1 <- ggplot(data=LakeLevels) + geom_line(aes(x=Day,y=Elevation)) + 
              scale_y_continuous(name="Elevation (m)",limits=c(75,125))
    
        p2<-ggplot(data=LakeLevels)+geom_line(aes(x=Day, y=Elevation))+
            scale_y_continuous(name="Elevation (ft)", limits=c(75,125),           
            breaks=c(80,90,100,110,120),
                     labels=c("262", "295", "328", "361", "394"))
    
        #extract gtable
        g1<-ggplot_gtable(ggplot_build(p1))
        g2<-ggplot_gtable(ggplot_build(p2))
    
        #overlap the panel of the 2nd plot on that of the 1st plot
    
        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)
       ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
       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)
    
       # draw it
       grid.draw(g)
    

    enter image description here

  • 4

    我可能已经找到了一个放置轴 Headers 的解决方案,其中一些来自Nate Pope答案的想法可以在这里找到:
    ggplot2: Adding secondary transformed x-axis on top of plot
    关于在gtable中访问grobs的讨论:https://groups.google.com/forum/m/#!topic/ggplot2-dev/AVHHcYqc5uU

    最后,我刚刚添加了该行

    g <- gtable_add_grob(g, g2$grob[[7]], pp$t, length(g$widths), pp$b)
    

    在致电 grid.draw(g) 之前,这似乎可以解决问题 .
    据我了解,它采用y轴 Headers g2$grob[[7]] 并将其置于最右侧 . 它可能不是美妙的解决方案,但它对我有用 .

    最后一件事 . 找到一种旋转轴 Headers 的方法会很不错 .

    问候,

    蒂姆

  • 2

    这个问题已得到解答,但是在ggplot对象的右侧添加辅助轴和辅助比例的一般问题是一直出现的问题 . 我想在下面报告我对问题的调整,基于此线程中的各种答案给出的几个元素以及其他几个线程(参见下面的部分参考列表) .

    我需要批量 生产环境 双y轴图,所以我构建了一个函数 ggplot_dual_axis() . 以下是潜在兴趣的特征:

    • The code displays gridlines for both the y-left and y-right axes (这是我的主要贡献,虽然它是微不足道的)

    • The code prints a euro symbol and embeds it into the pdf (我在那里看到的东西:Plotting Euro Symbol € in ggplot2?

    • 代码试图避免两次打印某些元素('尝试'表明我怀疑它是否完全成功)

    未答复的问题:

    • 有没有办法修改 ggplot_dual_axis() 函数以删除其中一个 geom_line()geom_point() 或其他任何可能没有抛出错误,如果没有这样的geom元素 . 在伪代码中像 if has(geom_line) ...

    • 如何通过关键字而不是索引来调用 g2$grobs[[7]] ?这就是它返回的内容: text[axis.title.y.text.232] 我对这个问题的兴趣源于我通过应用类似的技巧尝试 grab 网格线的失败 . 我认为网格线隐藏在 g2$grobs[[4]] 内的某个地方,但我不知道如何访问它们 .

    Edit . 问题我能够自己回答:如何增加右侧的绘图边距,'Euro'标签在哪里?答:例如, theme(plot.margin = unit(c(1,3,0.5,0.8), "lines")) 会做的伎俩 .

    请指出任何明显的问题或建议改进 .

    现在代码:希望它对某人有用 . 正如我所说,我并不要求原创性,这是其他人已经展示的事物的组合 .

    ##' function named ggplot_dual_axis()
    ##' Takes 2 ggplot plots and makes a dual y-axis plot
    ##' function takes 2 compulsory arguments and 1 optional argument
    ##' arg lhs is the ggplot whose y-axis is to be displayed on the left
    ##' arg rhs is the ggplot whose y-axis is to be displayed on the right
    ##' arg 'axis.title.y.rhs' takes value "rotate" to rotate right y-axis label
    ##' The function does as little as possible, namely:
    ##'  # display the lhs plot without minor grid lines and with a
    ##'  transparent background to allow grid lines to show
    ##'  # display the rhs plot without minor grid lines and with a
    ##'  secondary y axis, a rotated axis label, without minor grid lines
    ##'  # justify the y-axis label by setting 'hjust = 0' in 'axis.text.y'
    ##'  # rotate the right plot 'axis.title.y' by 270 degrees, for symmetry
    ##'  # rotation can be turned off with 'axis.title.y.rhs' option
    ##'  
    
    ggplot_dual_axis <- function(lhs, rhs, axis.title.y.rhs = "rotate") {
      # 1. Fix the right y-axis label justification
        rhs <- rhs + theme(axis.text.y = element_text(hjust = 0))
      # 2. Rotate the right y-axis label by 270 degrees by default
        if (missing(axis.title.y.rhs) | 
            axis.title.y.rhs %in% c("rotate", "rotated")) {
            rhs <- rhs + theme(axis.title.y = element_text(angle = 270)) 
        }
      # 3a. Use only major grid lines for the left axis
        lhs <- lhs + theme(panel.grid.minor = element_blank())
      # 3b. Use only major grid lines for the right axis
      #     force transparency of the backgrounds to allow grid lines to show
        rhs <- rhs + theme(panel.grid.minor = element_blank(), 
            panel.background = element_rect(fill = "transparent", colour = NA), 
            plot.background = element_rect(fill = "transparent", colour = NA))
    # Process gtable objects
      # 4. Extract gtable
        library("gtable") # loads the grid package
        g1 <- ggplot_gtable(ggplot_build(lhs))
        g2 <- ggplot_gtable(ggplot_build(rhs))
      # 5. Overlap the panel of the rhs plot on that of the lhs plot
        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)
      # Tweak axis position and labels
        ia <- which(g2$layout$name == "axis-l")
        ga <- g2$grobs[[ia]]
        ax <- ga$children[["axis"]]  # ga$children[[2]]
        ax$widths <- rev(ax$widths)
        ax$grobs <- rev(ax$grobs)
        ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
        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)
        g <- gtable_add_grob(g, g2$grobs[[7]], pp$t, length(g$widths), pp$b)
      # Display plot with arrangeGrob wrapper arrangeGrob(g)
        library("gridExtra")
        grid.newpage()
        return(arrangeGrob(g))
    }
    

    还有一些虚假数据和两个以美元和欧元为单位的情节 . 拥有一个可以让你制作一个情节的包裹并且用它来包围调用双y轴情节并不是很酷,它会自动获取你的汇率! :-)

    # Set directory:
    if(.Platform$OS.type == "windows"){
      setwd("c:/R/plots")
    } else { 
      setwd("~/R/plots")
    }
    
    # Load libraries
    library("ggplot2")
    library("scales")
    
    # Create euro currency symbol in plot labels, simple version
    # avoids loading multiple libraries
    # avoids problems with rounding of small numbers, e.g. .0001
    labels_euro <- function(x) {# no rounding
    paste0("€", format(x, big.mark = ",", decimal.mark = ".", trim = TRUE,
        scientific = FALSE))
    } 
    
    labels_dollar <- function(x) {# no rounding: overwrites dollar() of library scales
    paste0("$", format(x, big.mark = ",", decimal.mark = ".", trim = TRUE,
        scientific = FALSE))
    } 
    
    # Create data
    df <- data.frame(
      Year = as.Date(c("2001", "2002", "2003", "2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017", "2018"),
        "%Y"), 
      Dollar = c(0, 9000000, 1000000, 8000000, 2000000, 7000000, 3000000, 6000000, 4000000, 5000000, 5000000, 6000000, 4000000, 7000000, 300000, 8000000, 2000000, 9000000))
    # set Euro/Dollar exchange rate at 0.8 euros = 1 dollar
    df <- cbind(df, Euro = 0.8 * df$Dollar)
    # Left y-axis
    p1 <- ggplot(data = df, aes(x = Year, y = Dollar)) + 
        geom_line(linestyle = "blank") + # manually remove the line
        theme_bw(20) +                   # make sure font sizes match in both plots
        scale_x_date(labels = date_format("%Y"), breaks = date_breaks("2 years")) + 
        scale_y_continuous(labels = labels_dollar, 
            breaks = seq(from = 0, to = 8000000, by = 2000000))
    # Right y-axis
    p2 <- ggplot(data = df, aes(x = Year, y = Euro)) + 
        geom_line(color = "blue", linestyle = "dotted", size = 1) + 
        xlab(NULL) +                     # manually remove the label
        theme_bw(20) +                   # make sure font sizes match in both plots
        scale_x_date(labels = date_format("%Y"), breaks = date_breaks("2 years")) +
        scale_y_continuous(labels = labels_euro, 
            breaks = seq(from = 0, to = 7000000, by = 2000000))
    
    # Combine left y-axis with right y-axis
    p <- ggplot_dual_axis(lhs = p1, rhs = p2)
    p
    
    # Save to PDF
    pdf("ggplot-dual-axis-function-test.pdf", 
      encoding = "ISOLatin9.enc", width = 12, height = 8)
    p
    dev.off()
    
    embedFonts(file = "ggplot-dual-axis-function-test.pdf", 
               outfile = "ggplot-dual-axis-function-test-embedded.pdf")
    

    enter image description here

    部分参考清单:

  • 15

    要旋转轴 Headers ,请将以下内容添加到p2图表中:

    p2 <- p2 + theme(axis.title.y=element_text(angle=270))
    

相关问题