creating multiple scatter plots with same axes in R

不问归期 提交于 2019-12-05 12:21:51

ggplot2 might be have the highest pretty / easy ratio if beginning.

Example with rpy2:

from rpy2.robjects.lib import ggplot2
from rpy2.robjects import r, Formula

iris = r('iris')

p = ggplot2.ggplot(iris) + \
    ggplot2.geom_point(ggplot2.aes_string(x="Sepal.Length", y="Sepal.Width")) + \
    ggplot2.facet_wrap(Formula('~ Species'), ncol=2, nrow = 2) + \
    ggplot2.GBaseObject(r('ggplot2::coord_fixed')()) # aspect ratio
# coord_fixed() missing from the interface, 
# therefore the hack. This should be fixed in rpy2-2.3.3

p.plot()

Reading the comments to a previous answer I see that you might mean completely separate plots. With the default plotting system for R, par(mfrow(c(2,2)) or par(mfcol(c(2,2))) would the easiest way to go, and keep aspect ratio, ranges for the axes, and tickmarks consistent through the usual way those are fixed.

The most flexible system to plot in R might be grid. It is not as bad as it seems, think of is as a scene graph. With rpy2, ggplot2, and grid:

from rpy2.robjects.vectors import FloatVector

from rpy2.robjects.lib import grid
grid.newpage()
lt = grid.layout(2,2) # 2x2 layout
vp = grid.viewport(layout = lt)
vp.push()


# limits for axes and tickmarks have to be known or computed beforehand
xlims = FloatVector((4, 9))
xbreaks = FloatVector((4,6,8))
ylims = FloatVector((-3, 3))
ybreaks = FloatVector((-2, 0, 2))

# first panel
vp_p = grid.viewport(**{'layout.pos.col':1, 'layout.pos.row': 1})
p = ggplot2.ggplot(iris) + \
    ggplot2.geom_point(ggplot2.aes_string(x="Sepal.Length",
                                          y="rnorm(nrow(iris))")) + \
    ggplot2.GBaseObject(r('ggplot2::coord_fixed')()) + \
    ggplot2.scale_x_continuous(limits = xlims, breaks = xbreaks) + \
    ggplot2.scale_y_continuous(limits = ylims, breaks = ybreaks)
p.plot(vp = vp_p)
# third panel
vp_p = grid.viewport(**{'layout.pos.col':2, 'layout.pos.row': 2})
p = ggplot2.ggplot(iris) + \
    ggplot2.geom_point(ggplot2.aes_string(x="Sepal.Length",
                                          y="rnorm(nrow(iris))")) + \
    ggplot2.GBaseObject(r('ggplot2::coord_fixed')()) + \
    ggplot2.scale_x_continuous(limits = xlims, breaks = xbreaks) + \
    ggplot2.scale_y_continuous(limits = ylims, breaks = ybreaks)
p.plot(vp = vp_p)

More documentation in the rpy2 documentation about graphics, and after in the ggplot2 and grid documentations.

With lattice and ggplot2 You need to reshape the data. For example:

  1. create 4 data.frame(x=x1,y=y1)...
  2. add a group column for each data.frame, group=1,2,...
  3. rbind the 4 data.frame in once

Here an example using lattice

dat <- data.frame(x = rep(sample(1:100,size=10),4),
                  y = rep(rnorm(40)),
                  group = rep(1:4,each =10))

xyplot(y~x|group,       ## conditional formula to get 4 panels
       data =dat,       ## data
       type='l',        ## line type for plot
       groups=group,     ## group ti get differents colors
       layout=c(2,2))   ## equivalent to par or layout

PS : no need to set the sacles. In xyplot the default sacles settings is same (same sacles for all panels). You can modify it for example :

xyplot(y~x|group, data =dat, type='l',groups=group,
       layout=c(2,2), scales =list(y = list(relation='free')))

EDIT

There are a large number of arguments to lattice plotting functions to allow control over many details of a plot, here for example I customize :

  1. The text to use for labels and titles for strips
  2. The size and placement of axis tick labels,
  3. The size of the gaps between columns and rows of panels.

    xyplot(y~x|group, data =dat, type='l',groups=group,
          between =list(y=2,x=2),
          layout=c(2,2), 
          strip = myStrip,
          scales =list(y = list(relation='same',alternating= c(3,3))))
    

where

myStrip <- function(var.name,which.panel, which.given,...) {
  var.name <- paste(var.name ,which.panel)
  strip.default(which.given,which.panel,var.name,...)
  }

EDIT In order to get a lattice plot base-graphics plots, you can try this :

xyplot(y~x|group, data =dat, type='l',groups=group,
       between=list(y=2,x=2),
       layout=c(2,2), 
       strip =FALSE,
       xlab=c('a','a'),
       xlab.top=c('a','a'),
       ylab=c('b','b'),
       ylab.right = c('b','b'),
       main=c('plot1','plot2'),
       sub=c('plot3','plot4'),
       scales =list(y = list(alternating= c(3,3)),
                    x = list(alternating= c(3,3))))

Although an answer has been selected already, that answer uses ggplot rather than base R, which is what the OP wanted. Although ggplot is really nice for quick plotting, for publication you often want finer control over the plots than ggplot offers. That is where base plot excels.

I would suggest reading Sean Anderson's explanation of the magic that can be worked with clever use of par, as well as a few other nice tricks like using layout() and split.screen().

Using his explanation, I came up with this:

# Assume that you are starting with some data, 
# rather than generating it on the fly
data_mat <- matrix(rnorm(600), nrow=4, ncol=150)
x_val <- iris$Petal.Width

Ylim <- c(-3, 3)
Xlim <- c(0, 2.5)

# You'll need to make the ylimits the same if you want to share axes


par(mfrow=c(2,2))
par(mar=c(0,0,0,0), oma=c(4,4,0.5,0.5))
par(mgp=c(1, 0.6, 0.5))
for (n in 1:4) { 
  plot(x_val, data_mat[n,], "p", asp=1, axes=FALSE, ylim=Ylim, xlim=Xlim)
  box()
  if(n %in% c(1,3)){
    axis(2, at=seq(Ylim[1]+0.5, Ylim[2]-0.5, by=0.5))
  }
  if(n %in% c(3,4)){
    axis(1, at=seq(min(x_val), max(x_val), by=0.1))
  }
}

There is still some work to do here. Just as in the OP, the data appear squashed in the middle. It would, of course, be good to adjust things so the full plotting area is used.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!