生成具有交替轴和不同比例的堆叠 multi-panel 图

Produce stacked multi-panel plot with alternating axes and different scales

假设我们有这个数据:

    dat <- structure(list(variable = c("a1", "a1", "a1", "a1", "a1", "a1", 
"a2", "a2", "a2", "a2", "a2", "a2", "a3", "a3", "a3", "a3", "a3", 
"a3", "a4", "a4", "a4", "a4", "a4", "a4"), value = c(9.17804065427195, 
-0.477515191225569, 0.189943035684685, -6.06095979017212, -10.4173631972868, 
-6.119330192816, -14.3820530117637, 13.9823789620469, 15.6437973890843, 
0.754856919261315, -0.887052526388938, 7.4096244573169, 0.61043977214679, 
28.4639357142541, 15.4511442682744, 15.8118136384483, 6.65940292893, 
0.467862281678766, 482.791905769932, 493.606761379037, 491.254828253119, 
504.323684433231, 499.323576709646, 492.625278087471)), .Names = c("variable", 
"value"), row.names = c(NA, -24L), class = "data.frame")

我想为每个 variable 绘制一个图 value vs value,这样我就有 6 个面板,格式如下,其中字母代表轴的位置, p 显示面板所在的位置。

a2   p
a3   p  p
a4   p  p  p  
    a1  a2 a3   

我知道如果数据很长我可以绘制每一个并安排...,例如

par(.....)
plot(a1 ~ a2, data=longdat)
plot(a1 ~ a3, data=longdat)
plot(a1 ~ a4, data=longdat)
......

如果我能做到这一点,也许有一个快速的方法吗? 最好我想知道是否已经有办法做到这一点,比如 ggplot2

中的 facet_wrapfacet_grid

Lattice 似乎有我想要的形状图(见下文),但我只能看到如何为 using two axes split per factor 执行此操作。这里的直方图不是必需的这只是一个例子..

lattice 可以做类似的事情,但不是我想要的..

xyplot(value~value|variable, 
       data = a, 
       scales=list(alternating=FALSE,relation="same"), 
       layout=c(2,2))

通过重新排序数据,我也许可以完成这项工作,但是当您将 relation 更改为 "free" 时,您会在轴上为每个变量获得不同的比例,然后它将面板分解为单独的面板.

希望这就是您想要的。

x 是针对每个 z 的 x 绘制的。 “|”后面的变量是条件变量。这用于实现类似于 facet_grid() 的结果。布局通常根据您的地块大小或地块 window 按 lattice 选择。您可以强制采用如下所示的 2x2 布局,这似乎会自动将空的 space 放在右上角。

library("lattice")
dat <- data.frame(x=rnorm(15),z=rep(letters[1:3],each=5))
xyplot(x~x|z, data = dat, scales=list(alternating=FALSE), layout=c(2,2))

根据我对你问题的阅读,你想要的只是一个显示每对变量的散点图的图。通过使用 reshape2 包中的 dcast() 快速将数据从长格式转换为宽格式,使用基础图形中的 pairs() 可以轻松完成此操作。如下:

library(reshape2)

# assign some id variables to assist the conversion and cast
dat$id <- sequence(rle(as.character(dat$variable))$lengths)
dat2 <- dcast(dat, id ~ variable, value.var='value')

# plot
pairs(dat2[2:5], upper.panel=NULL)

这给我们留下了我认为你想要的情节。

从那里开始,如果您确实想在对角线或上图中添加 R 平方值、直方图等,您需要的代码可以在这里找到: How to modify this Correlation Matrix plot?

例如:

panel.hist <- function(x, ...)
{
  usr <- par("usr"); on.exit(par(usr))
  par(usr = c(usr[1:2], 0, 1.5) )
  h <- hist(x, plot = FALSE)
  breaks <- h$breaks; nB <- length(breaks)
  y <- h$counts; y <- y/max(y)
  rect(breaks[-nB], 0, breaks[-1], y, col="cyan", ...)
}

pairs(dat2[2:5], upper.panel=NULL, diag.panel=panel.hist)

希望对您有所帮助。

编辑:使用 GGally (v1.0.1)

使用 GGally 包中的 ggpairs() 函数更容易。让 ggpairs() 绘制和定位散点图,然后从结果图中删除不需要的元素。首先,将数据转换为宽格式。

# Packages
library(GGally)
library(ggplot2)
library(tidyr)

# Data
dat <- structure(list(variable = c("a1", "a1", "a1", "a1", "a1", "a1", 
"a2", "a2", "a2", "a2", "a2", "a2", "a3", "a3", "a3", "a3", "a3", 
"a3", "a4", "a4", "a4", "a4", "a4", "a4"), 
value = c(9.17804065427195, 
-0.477515191225569, 0.189943035684685, -6.06095979017212, -10.4173631972868, 
-6.119330192816, -14.3820530117637, 13.9823789620469, 15.6437973890843, 
0.754856919261315, -0.887052526388938, 7.4096244573169, 0.61043977214679, 
28.4639357142541, 15.4511442682744, 15.8118136384483, 6.65940292893, 
0.467862281678766, 482.791905769932, 493.606761379037, 491.254828253119, 
504.323684433231, 499.323576709646, 492.625278087471)), .Names = c("variable", 
"value"), row.names = c(NA, -24L), class = "data.frame")

# Get the data in its wide format
dat$id <- sequence(rle(as.character(dat$variable))$lengths)
dat2 = spread(data = dat, key = variable, value = value)


# Base plot 
gg = ggpairs(dat2, 
    columns = 2:5,
    lower = list(continuous = "points"),
    diag = list(continuous = "blankDiag"),
    upper = list(continuous = "blank"))

使用从 到 trim 的代码关闭未指定的元素

# Trim off the diagonal spaces
n <- gg$nrow 
gg$nrow <- gg$ncol <- n-1   
v <- 1:n^2
gg$plots <- gg$plots[v > n & v%%n != 0]

# Trim off the last x axis label
# and the first y axis label
gg$xAxisLabels <- gg$xAxisLabels[-n]
gg$yAxisLabels <- gg$yAxisLabels[-1]

# Draw the plot
gg = gg + 
     theme_bw() + 
     theme(panel.grid = element_blank())
gg

原创

pairs() 函数让您接近,但如果您只想要布局矩阵中显示的六个面板,那么您可能必须手动构建它。您可以使用 gridggplotgtable 构建图表。这是 ggplot / gtable 版本。

该脚本适用于您的 dat 数据文件(即长格式)。它构建了六个 ggplot 散点图的列表。 ggplots 被转换为 grobs,并提取相关轴——那些将成为新图表中的左轴和底轴的轴。构建 gtable 布局,并将散点图 grobs(仅限绘图面板)添加到布局中。修改布局以获取轴,然后再次修改布局以获取变量标签。最后,有一点整理。

dat <- structure(list(variable = c("a1", "a1", "a1", "a1", "a1", "a1", 
"a2", "a2", "a2", "a2", "a2", "a2", "a3", "a3", "a3", "a3", "a3", 
"a3", "a4", "a4", "a4", "a4", "a4", "a4"), 
value = c(9.17804065427195, 
-0.477515191225569, 0.189943035684685, -6.06095979017212, -10.4173631972868, 
-6.119330192816, -14.3820530117637, 13.9823789620469, 15.6437973890843, 
0.754856919261315, -0.887052526388938, 7.4096244573169, 0.61043977214679, 
28.4639357142541, 15.4511442682744, 15.8118136384483, 6.65940292893, 
0.467862281678766, 482.791905769932, 493.606761379037, 491.254828253119, 
504.323684433231, 499.323576709646, 492.625278087471)), .Names = c("variable", 
"value"), row.names = c(NA, -24L), class = "data.frame")

# Load packages
library("ggplot2")
library("plyr")
library("gtable")
library(grid)

# Number of items and item labels
item = unique(dat$variable)
n = length(item)

## List of scatterplots
scatter <- list()

for (i in 1:(n-1)) {
   for (j in (i+1):n) {

# Data frame 
df.point <- na.omit(data.frame(cbind(x = dat[dat$variable == item[i], 2], y = dat[dat$variable == item[j], 2])))

# Plot
p <- ggplot(df.point, aes(x, y)) +
   geom_point(size = 1) +
   theme_bw() + 
   theme(panel.grid = element_blank(),
          axis.text = element_text(size = 6))

name <- paste0("Item", i, j)
scatter[[name]] <- p
} }

# Convert ggplots to grobs
scatterGrob <- llply(scatter, ggplotGrob)

# Extract the axes as grobs
# x axis
xaxes = subset(scatterGrob, grepl(paste0("^Item.", n), names(scatterGrob))) 
xaxes = llply(xaxes, gtable_filter, "axis-b")

# y axis
yaxes = subset(scatterGrob, grepl("^Item1.*", names(scatterGrob))) 
yaxes = llply(yaxes, gtable_filter, "axis-l")

# Tick marks and tick mark labels are easier to position if they are separated. 
labelsb = list(); ticksb = list(); labelsl = list(); ticksl = list()
for(i in 1:(n-1)) {
  x = xaxes[[i]][[1]][[1]]$children[[2]]
  labelsb[[i]] = x$grobs[[2]]
  ticksb[[i]] = x$grobs[[1]]

  y = yaxes[[i]][[1]][[1]]$children[[2]]
  labelsl[[i]] = y$grobs[[1]]
  ticksl[[i]] = y$grobs[[2]]
} 

## Extract the plot panels
scatterGrob <- llply(scatterGrob, gtable_filter, "panel")

## Set up initial gtable layout
gt <- gtable(unit(rep(1, n-1), "null"), unit(rep(1, n-1), "null"))

# Add scatterplots in the lower half of the matrix
 k <- 1
 for (i in 1:(n-1)) {
    for (j in i:(n-1)) {
 gt <- gtable_add_grob(gt, scatterGrob[[k]], t=j, l=i)
 k <- k+1
 } }

# Add rows and columns for axes
gt <- gtable_add_cols(gt, unit(0.25, "lines"), 0)
gt <- gtable_add_cols(gt, unit(1, "lines"), 0)
gt <- gtable_add_rows(gt, unit(0.25, "lines"), 2*(n-1))
gt <- gtable_add_rows(gt, unit(0.5, "lines"), 2*(n-1))

for (i in 1:(n-1)) {
  gt <- gtable_add_grob(gt, ticksb[[i]], t=(n-1)+1, l=i+2)
  gt <- gtable_add_grob(gt, labelsb[[i]], t=(n-1)+2, l=i+2)
  gt <- gtable_add_grob(gt, ticksl[[i]], t=i, l=2)
  gt <- gtable_add_grob(gt, labelsl[[i]], t=i, l=1)
}

# Add rows and columns for variable names
gt <- gtable_add_cols(gt, unit(1, "lines"), 0)
gt <- gtable_add_rows(gt, unit(1, "lines"), n+1)
for(i in 1:(n-1))  gt <- gtable_add_grob(gt, 
           textGrob(item[i], gp = gpar(fontsize = 8)), t=n+2, l=i+3)
for(i in 2:n)  gt <- gtable_add_grob(gt, 
           textGrob(item[i], rot = 90, gp = gpar(fontsize = 8)), t=i-1, l=1)

# Add small gaps between the panels
for(i in (n-1):2) {
  gt <- gtable_add_cols(gt, unit(0.4, "lines"), i+2)
  gt <- gtable_add_rows(gt, unit(0.4, "lines"), i-1)
}

# Add margins to the whole plot
for(i in c(2*(n-1)+2, 0)) {
    gt <- gtable_add_cols(gt, unit(.75, "lines"), i)
    gt <- gtable_add_rows(gt, unit(.75, "lines"), i)
}

# Turn clipping off
gt$layout$clip = "off"

# Draw it
grid.newpage()
grid.draw(gt)