R ggplot2双y轴面包装,一个直方图和其他线

时间:2022-02-15 15:00:08

I have two facet wrapped plots, p1 and p2

我有两个面,p1和p2

p1

p1

R ggplot2双y轴面包装,一个直方图和其他线

p2

p2

R ggplot2双y轴面包装,一个直方图和其他线

As you can see, the x-axis values line up for both plots, however the y-axis values differ quite drastically. I would like to overlay p2 onto p1, keeping the p1 y axis on the left and creating another p2 y-axis on the right.

正如你所看到的,x轴值在这两个图上都是一致的,但是y轴值有很大的不同。我想在p1上覆盖p2,保持p1 y轴在左边,在右边创建另一个p2 y轴。

This is what I have right now, but I am unsure of how to correctly combine grobs for p1 and p2.

这就是我现在所拥有的,但是我不确定如何正确地结合p1和p2的grob。

library(ggplot2)
library(gtable)
library(grid)

themer <- theme(panel.grid.major = element_blank(), 
                panel.grid.minor = element_blank(), 
                panel.background = element_blank(),
                panel.margin = unit(0, "lines"),
                strip.background = element_rect(fill="#F8F8F8"))

p2 <- ggplot(normaldens, aes(y=density,x=predicted)) + 
        geom_line(color="red") + 
        facet_wrap(~ motif) + 
        labs(title=paste("Methylation Score:",motif_f[j]),x="Methylation Score",y="Density") +
        themer
p1 <- ggplot(dat, aes(x=score)) +
        geom_histogram( binwidth = bin_width,col="red",fill="blue",alpha=0.2) +  
        facet_wrap(~ motif) + 
        labs(title=paste("Methylation Score:",motif_f[j]),x="Methylation Score",y="Counts") +
        themer

###### COMBINE GROBS #######
g1 <- ggplot_gtable(ggplot_build(p1))
g2 <- ggplot_gtable(ggplot_build(p2))

combo_grob <- g2
pos <- length(combo_grob) - 1
combo_grob$grobs[[pos]] <- cbind(g1$grobs[[pos]],
                                 g2$grobs[[pos]], size = 'first')
panel_num <- length(unique(df1$z))
for (i in seq(panel_num))
{
  # grid.ls(g1$grobs[[i + 1]])
  panel_grob <- getGrob(g1$grobs[[i + 1]], 'geom_point.points',
                        grep = TRUE, global = TRUE)
  combo_grob$grobs[[i + 1]] <- addGrob(combo_grob$grobs[[i + 1]], 
                                       panel_grob)
}       


pos_a <- grep('axis_l', names(g1$grobs))
axis <- g1$grobs[pos_a]
for (i in seq(along = axis))
{
  if (i %in% c(2, 4))
  {
    pp <- c(subset(g1$layout, name == paste0('panel-', i), se = t:r))

    ax <- axis[[1]]$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.5, "cm")
    ax$grobs[[2]]$x <- ax$grobs[[2]]$x - unit(1, "npc") + unit(0.8, "cm")
    combo_grob <- gtable_add_cols(combo_grob, g2$widths[g2$layout[pos_a[i],]$l], length(combo_grob$widths) - 1)
    combo_grob <- gtable_add_grob(combo_grob, ax,  pp$t, length(combo_grob$widths) - 1, pp$b)
  }
}

pp <- c(subset(g1$layout, name == 'ylab', se = t:r))

ia <- which(g1$layout$name == "ylab")
ga <- g1$grobs[[ia]]
ga$rot <- 270
ga$x <- ga$x - unit(1, "npc") + unit(1.5, "cm")

combo_grob <- gtable_add_cols(combo_grob, g2$widths[g2$layout[ia,]$l], length(combo_grob$widths) - 1)
combo_grob <- gtable_add_grob(combo_grob, ga, pp$t, length(combo_grob$widths) - 1, pp$b)
combo_grob$layout$clip <- "off"

grid.draw(combo_grob)

And I get this error, which I know has to do something with the way I'm combining the two gtables.

我得到了这个误差,我知道它与我合并两个gtables的方式有关。

Error in gList(list(x = 0.5, y = 0.5, width = 1, height = 1, just = "centre", : only 'grobs' allowed in "gList"

gList错误(list(x = 0.5, y = 0.5, width = 1, height = 1, just = "centre",:只允许“grobs”进入“gList”

1 个解决方案

#1


1  

I don't think you can do a second y-axis within ggplot2, but what about plotting both density and histogram in a single plot and using bar labeling for the counts (instead of trying to hack a second y-axis). Here's an example (using the built-in iris dataset):

我不认为你可以在ggplot2中绘制第二个y轴,但是如果在一个图中同时绘制密度和直方图,并使用条形标记计数(而不是尝试破解第二个y轴)会怎么样呢?这里有一个示例(使用内置的iris数据集):

First, we'll calculate maximum values of density and count and use these to create scale factors that we'll use to programmatically ensure that the histogram and density plot have about the same vertical scale.

首先,我们将计算密度和计数的最大值,并使用它们创建比例因子,我们将用编程方式确保直方图和密度图具有相同的垂直比例。

library(dplyr) 

# Find maximum value of density
densMax = iris %>% group_by(Species) %>%
  summarise(dens = max(density(Sepal.Length)[["y"]])) %>%
  filter(dens == max(dens))

# Find maximum value of bin count
countMax = iris %>% 
  group_by(Species, 
           bins=cut(Sepal.Length, seq(floor(min(Sepal.Length)),
                                      ceiling(max(Sepal.Length)), 
                                      0.25), right=FALSE)) %>%
  summarise(count=n()) %>% 
  ungroup() %>% filter(count==max(count))

Now we scale the histogram bars to the size of the density plot. sf is the scale factor:

现在我们将直方图条按密度图的大小进行缩放。sf是比例因子:

ggplot(iris, aes(x=Sepal.Length, sf = countMax$count/densMax$dens)) + 
  geom_histogram(fill=hcl(195,100,65), colour="grey50", binwidth=0.25) +
  geom_density(colour="red", aes(y=..density.. * sf)) +
  facet_wrap(~ Species) + 
  themer

R ggplot2双y轴面包装,一个直方图和其他线

Alternatively, you could go in the other direction, and scale the density plot to the histogram:

或者,你也可以朝另一个方向走,将密度图缩放到直方图:

# Scale histogram bars to size of density plot
ggplot(iris, aes(x=Sepal.Length, sf = densMax$dens/countMax$count)) + 
  geom_histogram(aes(y=..count..*sf), 
                 fill=hcl(195,100,65), colour="grey50", binwidth=0.25) +
  stat_bin(aes(label=..count.., y=..count..*0.5*sf), 
           geom="text", size=4, color="white", binwidth=0.25) +
  geom_density(colour="red") +
  facet_wrap(~ Species) + 
  themer +
  labs(y="Density")

R ggplot2双y轴面包装,一个直方图和其他线

#1


1  

I don't think you can do a second y-axis within ggplot2, but what about plotting both density and histogram in a single plot and using bar labeling for the counts (instead of trying to hack a second y-axis). Here's an example (using the built-in iris dataset):

我不认为你可以在ggplot2中绘制第二个y轴,但是如果在一个图中同时绘制密度和直方图,并使用条形标记计数(而不是尝试破解第二个y轴)会怎么样呢?这里有一个示例(使用内置的iris数据集):

First, we'll calculate maximum values of density and count and use these to create scale factors that we'll use to programmatically ensure that the histogram and density plot have about the same vertical scale.

首先,我们将计算密度和计数的最大值,并使用它们创建比例因子,我们将用编程方式确保直方图和密度图具有相同的垂直比例。

library(dplyr) 

# Find maximum value of density
densMax = iris %>% group_by(Species) %>%
  summarise(dens = max(density(Sepal.Length)[["y"]])) %>%
  filter(dens == max(dens))

# Find maximum value of bin count
countMax = iris %>% 
  group_by(Species, 
           bins=cut(Sepal.Length, seq(floor(min(Sepal.Length)),
                                      ceiling(max(Sepal.Length)), 
                                      0.25), right=FALSE)) %>%
  summarise(count=n()) %>% 
  ungroup() %>% filter(count==max(count))

Now we scale the histogram bars to the size of the density plot. sf is the scale factor:

现在我们将直方图条按密度图的大小进行缩放。sf是比例因子:

ggplot(iris, aes(x=Sepal.Length, sf = countMax$count/densMax$dens)) + 
  geom_histogram(fill=hcl(195,100,65), colour="grey50", binwidth=0.25) +
  geom_density(colour="red", aes(y=..density.. * sf)) +
  facet_wrap(~ Species) + 
  themer

R ggplot2双y轴面包装,一个直方图和其他线

Alternatively, you could go in the other direction, and scale the density plot to the histogram:

或者,你也可以朝另一个方向走,将密度图缩放到直方图:

# Scale histogram bars to size of density plot
ggplot(iris, aes(x=Sepal.Length, sf = densMax$dens/countMax$count)) + 
  geom_histogram(aes(y=..count..*sf), 
                 fill=hcl(195,100,65), colour="grey50", binwidth=0.25) +
  stat_bin(aes(label=..count.., y=..count..*0.5*sf), 
           geom="text", size=4, color="white", binwidth=0.25) +
  geom_density(colour="red") +
  facet_wrap(~ Species) + 
  themer +
  labs(y="Density")

R ggplot2双y轴面包装,一个直方图和其他线