Having horizontal instead of vertical labels on 2x

2020-07-30 03:08发布

I want to have two graphs in one. They are both time series, but different scales (let's say heights and weights). The way I want to present this is by having two figures on top of each other that would share the x-label, but have different y-labels.

I have two different problems:

  1. If I do 2x1 facets, the default position for facet labels is on the right with vertical text, I would rather have them on top of the graphs as (sub)-titles
  2. ylab() defines one ylabel for all facets, but I have two different variables/scales. Is it possible to "split" it and have two different ylabel (say "grams" for weight and "inches" for height)?

Thanks!

EDIT: Ok, this is the code. mn is the variable that is ploted against time, grouped by risk. But the meaning of mn depends on var. For some values of var it is weight, for others it is height.

qplot(time, mn, data=d.plot.long,
  color=risk, group=risk,
  geom=c("line","point"),
  position=position_dodge(.2))+
geom_point(size=5, position=position_dodge(.2))+
geom_errorbar(aes(x=time, y=mn, ymin=low, ymax=hi),width=.3 ,position=position_dodge(.2))+
facet_grid(var~.,scales='free_y')+
xlab('Time')+ylab('')+
scale_color_discrete(name="The grouping variable", breaks=c("Hi","Low"), labels=(c("Group A","Group B")))

标签: r ggplot2
3条回答
叼着烟拽天下
2楼-- · 2020-07-30 03:33

Use gtable:::rbind_gtable; other answers won't properly align the axes.

align_plots = function(...){
  pl <- list(...)
  ## test that only passing plots
  stopifnot(do.call(all, lapply(pl, inherits, "gg")))
  gl <- lapply(pl, ggplotGrob)
  bind2 <- function(x,y)
    gtable:::rbind_gtable(x,y,"first") # bug with pmax

  combined <- Reduce(bind2, gl[-1], gl[[1]])

  wl <- lapply(gl, "[[", "widths")
  combined$widths <- do.call(grid::unit.pmax, wl)
  grid::grid.newpage()
  grid::grid.draw(combined)
}

align_plots(qplot(1,1), 
            qplot(100, 100), 
            qplot(1000, 1000) + ylab("two\nlines"))

enter image description here

查看更多
We Are One
3楼-- · 2020-07-30 03:43

As others have said, reproducibility makes questions easier to answer. However, this is the sort of question that can be easily answered with a general case.

ggplot2 offers somewhat limited options for multiple graphs on a single plate. The R Cookbook offers a pretty good and very easy to use workaround here. I can quickly walk you through it for your case:

First, some two simple sets of time series in a dataframe:

year<-c(2010:2014)
data1<-c(1:5)
data2<-c(20:24)
df<-data.frame(year,data1,data2)

Next, create your graphs. Since you want them to share an x axis, we'll remove it from the top graph:

library(ggplot2)
p1<-qplot(data=df,x=year,y=data1)+theme(axis.title.x = element_blank(), axis.text.x = element_blank())
p2<-qplot(df,x=year,y=data2)

Next, run the code from the cookbook to set up the multiplot function:

# Multiple plot function ggplot objects can be passed in ..., or to plotlist
# (as a list of ggplot objects) - cols: Number of columns in layout -
# layout: A matrix specifying the layout. If present, 'cols' is ignored.  If
# the layout is something like matrix(c(1,2,3,3), nrow=2, byrow=TRUE), then
# plot 1 will go in the upper left, 2 will go in the upper right, and 3 will
# go all the way across the bottom.
multiplot <- function(..., plotlist = NULL, file, cols = 1, layout = NULL) {
  require(grid)
  # Make a list from the ... arguments and plotlist
  plots <- c(list(...), plotlist)
  numPlots = length(plots)
  # If layout is NULL, then use 'cols' to determine layout
  if (is.null(layout)) {
    # Make the panel ncol: Number of columns of plots nrow: Number of rows
    # needed, calculated from # of cols
    layout <- matrix(seq(1, cols * ceiling(numPlots/cols)), ncol = cols,
                     nrow = ceiling(numPlots/cols))
  }
  if (numPlots == 1) {
    print(plots[[1]])
  } else {
    # Set up the page
    grid.newpage()
    pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
    # Make each plot, in the correct location
    for (i in 1:numPlots) {
      # Get the i,j matrix positions of the regions that contain this subplot
      matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))
      print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row, layout.pos.col = matchidx$col))
    }
  }
}

...and use the new function to lay out your graphs, one on top of the other.

multiplot(p1,p2,cols=1)

(I'd like to show you the final output, but it seems I've not got enough reputation to post an image! Try running all that to see the result for yourself.)

Is that what you're looking for?

查看更多
太酷不给撩
4楼-- · 2020-07-30 03:43

Using the data of @Joe, it's probably easier to use the gridExtra package.

The code:

require(ggplot2)
require(gridExtra)

p1 <- ggplot(data=df, aes(x=year, y=data1)) + 
  geom_point() +
  theme_bw() +
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank()
  )

p2 <- ggplot(data=df, aes(x=year, y=data2)) + 
  geom_point() + 
  theme_bw()

grid.arrange(p1, p2, ncol=1)

The result: enter image description here

查看更多
登录 后发表回答