2015-10-13 56 views
0

我想用coplot{graphic}創建一個漂亮的調節圖。感謝這個答案Add a line to coplot {graphics}, classic approaches don't work我可以簡單地將幾個數據(行)添加到我的圖中。 但是,請問,我怎樣才能很好地添加輔助軸及其名稱 - 理想情況下以不同的顏色?我發現我可以在panel中添加第二軸爲axis(4, col = "red", lwd = 2),其名稱爲mtext(2,...)。這個工程,但我有我所有的陰謀xlab和ylab,而不只是在條件劇情的邊界。請問,如何添加輔助軸名稱並保持可讀?謝謝 !R:將副軸的名稱添加到coplot {圖形}

我的代碼:

# exemple data 
set.seed(15) 
dd <- do.call("rbind", 
    do.call("Map", c(list(function(a,b) { 
     cbind.data.frame(a,b, x=1:5, 
     y1=cumsum(rpois(5,7)), 
     y2=cumsum(rpois(5,9)+100)) # make y axis ad different scale 
    }), 
    expand.grid(a=letters[1:5], b=letters[20:22]))) 
) 


# create coplot 

coplot(y~x|a+b, 
    # make a fake y col to cover range of all y1 and y2 values 
    cbind(dd, y=seq(min(dd$y1, dd$y2), max(dd$y1, dd$y2), length.out=nrow(dd))), xlab="", ylab = "", main = "", 
    #request subscripts to be sent to panel function 
    subscripts=TRUE, 
    panel=function(x,y,subscripts, ...) { 
      # add first plot for y1 
      par(new=T) 
      plot(x, dd$y1[subscripts], axes = F) 
     # draw group 1 
     lines(x, dd$y1[subscripts]) 
     # axis(2, col = "black", lwd = 2) - how to write this?? 
     # mtext(2, text = "name y1 axe", col = "black") 

     # add data on secondary y2 axis 
     par(new=T) 
     plot(x, dd$y2[subscripts], axes = F) 
     lines(x, dd$y2[subscripts], col="red") 
     # axis(4, col = "red", lwd = 2) - and this? 
     # mtext(4, text = "name y2 axe", col = "red")  
}) 

究竟應該如何看起來像:

enter image description here

回答

1

這裏是一個開始回答你兩個問題:1-頂部添加輔助y軸和底部行,並在輔助軸上添加y標籤。訣竅是僅爲特定的下標繪製次y軸(和標籤)。你可能想玩弄下標數字來理解它們在情節中的位置。例如,下標[[75]]是右上角的面板。

if(subscripts[[25]]|subscripts[[75]]) axis(4, col = "red", lwd = 2)# - and this? 
if(subscripts[[50]]) mtext(4, text = "name y2 axe", col = "red",line=2) 

下面是完整的代碼:

coplot(y~x|a+b, 
    # make a fake y col to cover range of all y1 and y2 values 
    cbind(dd, y=seq(min(dd$y1, dd$y2), max(dd$y1, dd$y2), length.out=nrow(dd))), xlab="", ylab = "", main = "", xaxs=FALSE, 
    #request subscripts to be sent to panel function 
    subscripts=TRUE, 
    panel=function(x,y,subscripts, ...) { 
      # add first plot for y1 
      par(new=T) 
      plot(x, dd$y1[subscripts], axes = F) 
     # draw group 1 
     lines(x, dd$y1[subscripts]) 
     # axis(2, col = "black", lwd = 2) - how to write this?? 
     # mtext(2, text = "name y1 axe", col = "black") 

     # add data on secondary y2 axis 
     par(new=T) 
     plot(x, dd$y2[subscripts], axes = F) 
     lines(x, dd$y2[subscripts], col="red") 
     if(subscripts[[25]]|subscripts[[75]]) axis(4, col = "red", lwd = 2)# - and this? 
     if(subscripts[[50]]) mtext(4, text = "name y2 axe", col = "red",line=2) 
}) 

這是你會得到什麼: enter image description here

現在,我懷疑你也想擺脫由coplot生成的原始軸。沒有直接的方法來做到這一點。我建議你根據原來的功能創建你自己的coplot2函數。

你需要的是擺脫coplot這部分功能(在面板上這增加了左,右軸):

if ((j == 1) && ((total.rows - i)%%2 == 0)) 
    Paxis(2, y) 
else if ((j == columns || index == nplots) && ((total.rows - 
    i)%%2 == 0)) 
    Paxis(4, y) 

UPDATE 下面介紹如何修改coplot功能,以滿足您要求。

下面是一個新的coplot2函數,它不繪製面板的左右軸。代碼與coplot相同,但上面的代碼已被註釋掉。

coplot2 <- function(formula, data, given.values, panel = points, rows, 
    columns, show.given = TRUE, col = par("fg"), pch = par("pch"), 
    bar.bg = c(num = gray(0.8), fac = gray(0.95)), xlab = c(x.name, 
     paste("Given :", a.name)), ylab = c(y.name, paste("Given :", 
     b.name)), subscripts = FALSE, axlabels = function(f) abbreviate(levels(f)), 
    number = 6, overlap = 0.5, xlim, ylim, ...) 
{ 
    deparen <- function(expr) { 
     while (is.language(expr) && !is.name(expr) && deparse(expr[[1L]])[1L] == 
      "(") expr <- expr[[2L]] 
     expr 
    } 
    bad.formula <- function() stop("invalid conditioning formula") 
    bad.lengths <- function() stop("incompatible variable lengths") 
    getOp <- function(call) deparse(call[[1L]], backtick = FALSE)[[1L]] 
    formula <- deparen(formula) 
    if (!inherits(formula, "formula")) 
     bad.formula() 
    y <- deparen(formula[[2L]]) 
    rhs <- deparen(formula[[3L]]) 
    if (getOp(rhs) != "|") 
     bad.formula() 
    x <- deparen(rhs[[2L]]) 
    rhs <- deparen(rhs[[3L]]) 
    if (is.language(rhs) && !is.name(rhs) && getOp(rhs) %in% 
     c("*", "+")) { 
     have.b <- TRUE 
     a <- deparen(rhs[[2L]]) 
     b <- deparen(rhs[[3L]]) 
    } 
    else { 
     have.b <- FALSE 
     a <- rhs 
    } 
    if (missing(data)) 
     data <- parent.frame() 
    x.name <- deparse(x) 
    x <- eval(x, data, parent.frame()) 
    nobs <- length(x) 
    y.name <- deparse(y) 
    y <- eval(y, data, parent.frame()) 
    if (length(y) != nobs) 
     bad.lengths() 
    a.name <- deparse(a) 
    a <- eval(a, data, parent.frame()) 
    if (length(a) != nobs) 
     bad.lengths() 
    if (is.character(a)) 
     a <- as.factor(a) 
    a.is.fac <- is.factor(a) 
    if (have.b) { 
     b.name <- deparse(b) 
     b <- eval(b, data, parent.frame()) 
     if (length(b) != nobs) 
      bad.lengths() 
     if (is.character(b)) 
      b <- as.factor(b) 
     b.is.fac <- is.factor(b) 
     missingrows <- which(is.na(x) | is.na(y) | is.na(a) | 
      is.na(b)) 
    } 
    else { 
     missingrows <- which(is.na(x) | is.na(y) | is.na(a)) 
     b <- NULL 
     b.name <- "" 
    } 
    number <- as.integer(number) 
    if (length(number) == 0L || any(number < 1)) 
     stop("'number' must be integer >= 1") 
    if (any(overlap >= 1)) 
     stop("'overlap' must be < 1 (and typically >= 0).") 
    bad.givens <- function() stop("invalid 'given.values'") 
    if (missing(given.values)) { 
     a.intervals <- if (a.is.fac) { 
      i <- seq_along(a.levels <- levels(a)) 
      a <- as.numeric(a) 
      cbind(i - 0.5, i + 0.5) 
     } 
     else co.intervals(unclass(a), number = number[1L], overlap = overlap[1L]) 
     b.intervals <- if (have.b) { 
      if (b.is.fac) { 
       i <- seq_along(b.levels <- levels(b)) 
       b <- as.numeric(b) 
       cbind(i - 0.5, i + 0.5) 
      } 
      else { 
       if (length(number) == 1L) 
        number <- rep.int(number, 2) 
       if (length(overlap) == 1L) 
        overlap <- rep.int(overlap, 2) 
       co.intervals(unclass(b), number = number[2L], 
        overlap = overlap[2L]) 
      } 
     } 
    } 
    else { 
     if (!is.list(given.values)) 
      given.values <- list(given.values) 
     if (length(given.values) != (if (have.b) 
      2L 
     else 1L)) 
      bad.givens() 
     a.intervals <- given.values[[1L]] 
     if (a.is.fac) { 
      a.levels <- levels(a) 
      if (is.character(a.intervals)) 
       a.intervals <- match(a.intervals, a.levels) 
      a.intervals <- cbind(a.intervals - 0.5, a.intervals + 
       0.5) 
      a <- as.numeric(a) 
     } 
     else if (is.numeric(a)) { 
      if (!is.numeric(a.intervals)) 
       bad.givens() 
      if (!is.matrix(a.intervals) || ncol(a.intervals) != 
       2) 
       a.intervals <- cbind(a.intervals - 0.5, a.intervals + 
        0.5) 
     } 
     if (have.b) { 
      b.intervals <- given.values[[2L]] 
      if (b.is.fac) { 
       b.levels <- levels(b) 
       if (is.character(b.intervals)) 
        b.intervals <- match(b.intervals, b.levels) 
       b.intervals <- cbind(b.intervals - 0.5, b.intervals + 
        0.5) 
       b <- as.numeric(b) 
      } 
      else if (is.numeric(b)) { 
       if (!is.numeric(b.intervals)) 
        bad.givens() 
       if (!is.matrix(b.intervals) || ncol(b.intervals) != 
        2) 
        b.intervals <- cbind(b.intervals - 0.5, b.intervals + 
        0.5) 
      } 
     } 
    } 
    if (any(is.na(a.intervals)) || (have.b && any(is.na(b.intervals)))) 
     bad.givens() 
    if (have.b) { 
     rows <- nrow(b.intervals) 
     columns <- nrow(a.intervals) 
     nplots <- rows * columns 
     if (length(show.given) < 2L) 
      show.given <- rep.int(show.given, 2L) 
    } 
    else { 
     nplots <- nrow(a.intervals) 
     if (missing(rows)) { 
      if (missing(columns)) { 
       rows <- ceiling(round(sqrt(nplots))) 
       columns <- ceiling(nplots/rows) 
      } 
      else rows <- ceiling(nplots/columns) 
     } 
     else if (missing(columns)) 
      columns <- ceiling(nplots/rows) 
     if (rows * columns < nplots) 
      stop("rows * columns too small") 
    } 
    total.columns <- columns 
    total.rows <- rows 
    f.col <- f.row <- 1 
    if (show.given[1L]) { 
     total.rows <- rows + 1 
     f.row <- rows/total.rows 
    } 
    if (have.b && show.given[2L]) { 
     total.columns <- columns + 1 
     f.col <- columns/total.columns 
    } 
    mar <- if (have.b) 
     rep.int(0, 4) 
    else c(0.5, 0, 0.5, 0) 
    oma <- c(5, 6, 5, 4) 
    if (have.b) { 
     oma[2L] <- 5 
     if (!b.is.fac) 
      oma[4L] <- 5 
    } 
    if (a.is.fac && show.given[1L]) 
     oma[3L] <- oma[3L] - 1 
    opar <- par(mfrow = c(total.rows, total.columns), oma = oma, 
     mar = mar, xaxs = "r", yaxs = "r") 
    on.exit(par(opar)) 
    dev.hold() 
    on.exit(dev.flush(), add = TRUE) 
    plot.new() 
    if (missing(xlim)) 
     xlim <- range(as.numeric(x), finite = TRUE) 
    if (missing(ylim)) 
     ylim <- range(as.numeric(y), finite = TRUE) 
    pch <- rep_len(pch, nobs) 
    col <- rep_len(col, nobs) 
    do.panel <- function(index, subscripts = FALSE, id) { 
     Paxis <- function(side, x) { 
      if (nlevels(x)) { 
       lab <- axlabels(x) 
       axis(side, labels = lab, at = seq(lab), xpd = NA) 
      } 
      else Axis(x, side = side, xpd = NA) 
     } 
     istart <- (total.rows - rows) + 1 
     i <- total.rows - ((index - 1)%/%columns) 
     j <- (index - 1)%%columns + 1 
     par(mfg = c(i, j, total.rows, total.columns)) 
     plot.new() 
     plot.window(xlim, ylim) 
     if (any(is.na(id))) 
      id[is.na(id)] <- FALSE 
     if (any(id)) { 
      grid(lty = "solid") 
      if (subscripts) 
       panel(x[id], y[id], subscripts = id, col = col[id], 
        pch = pch[id], ...) 
      else panel(x[id], y[id], col = col[id], pch = pch[id], 
       ...) 
     } 
     if ((i == total.rows) && (j%%2 == 0)) 
      Paxis(1, x) 
     else if ((i == istart || index + columns > nplots) && 
      (j%%2 == 1)) 
      Paxis(3, x) 
#  if ((j == 1) && ((total.rows - i)%%2 == 0)) 
#   Paxis(2, y) 
#  else if ((j == columns || index == nplots) && ((total.rows - 
#   i)%%2 == 0)) 
#   Paxis(4, y) 
     box() 
    } 
    if (have.b) { 
     count <- 1 
     for (i in 1L:rows) { 
      for (j in 1L:columns) { 
       id <- ((a.intervals[j, 1] <= a) & (a <= a.intervals[j, 
        2]) & (b.intervals[i, 1] <= b) & (b <= b.intervals[i, 
        2])) 
       do.panel(count, subscripts, id) 
       count <- count + 1 
      } 
     } 
    } 
    else { 
     for (i in 1L:nplots) { 
      id <- ((a.intervals[i, 1] <= a) & (a <= a.intervals[i, 
       2])) 
      do.panel(i, subscripts, id) 
     } 
    } 
    mtext(xlab[1L], side = 1, at = 0.5 * f.col, outer = TRUE, 
     line = 3.5, xpd = NA, font = par("font.lab"), cex = par("cex.lab")) 
    mtext(ylab[1L], side = 2, at = 0.5 * f.row, outer = TRUE, 
     line = 3.5, xpd = NA, font = par("font.lab"), cex = par("cex.lab")) 
    if (length(xlab) == 1L) 
     xlab <- c(xlab, paste("Given :", a.name)) 
    if (show.given[1L]) { 
     par(fig = c(0, f.col, f.row, 1), mar = mar + c(3 + (!a.is.fac), 
      0, 0, 0), new = TRUE) 
     plot.new() 
     nint <- nrow(a.intervals) 
     a.range <- range(a.intervals, finite = TRUE) 
     plot.window(a.range + c(0.03, -0.03) * diff(a.range), 
      0.5 + c(0, nint)) 
     rect(a.intervals[, 1], 1L:nint - 0.3, a.intervals[, 2], 
      1L:nint + 0.3, col = bar.bg[if (a.is.fac) 
       "fac" 
      else "num"]) 
     if (a.is.fac) { 
      text(apply(a.intervals, 1L, mean), 1L:nint, a.levels) 
     } 
     else { 
      Axis(a, side = 3, xpd = NA) 
      axis(1, labels = FALSE) 
     } 
     box() 
     mtext(xlab[2L], 3, line = 3 - a.is.fac, at = mean(par("usr")[1L:2]), 
      xpd = NA, font = par("font.lab"), cex = par("cex.lab")) 
    } 
    else { 
     mtext(xlab[2L], 3, line = 3.25, outer = TRUE, at = 0.5 * 
      f.col, xpd = NA, font = par("font.lab"), cex = par("cex.lab")) 
    } 
    if (have.b) { 
     if (length(ylab) == 1L) 
      ylab <- c(ylab, paste("Given :", b.name)) 
     if (show.given[2L]) { 
      par(fig = c(f.col, 1, 0, f.row), mar = mar + c(0, 
       3 + (!b.is.fac), 0, 0), new = TRUE) 
      plot.new() 
      nint <- nrow(b.intervals) 
      b.range <- range(b.intervals, finite = TRUE) 
      plot.window(0.5 + c(0, nint), b.range + c(0.03, -0.03) * 
       diff(b.range)) 
      rect(1L:nint - 0.3, b.intervals[, 1], 1L:nint + 0.3, 
       b.intervals[, 2], col = bar.bg[if (b.is.fac) 
        "fac" 
       else "num"]) 
      if (b.is.fac) { 
       text(1L:nint, apply(b.intervals, 1L, mean), b.levels, 
        srt = 90) 
      } 
      else { 
       Axis(b, side = 4, xpd = NA) 
       axis(2, labels = FALSE) 
      } 
      box() 
      mtext(ylab[2L], 4, line = 3 - b.is.fac, at = mean(par("usr")[3:4]), 
       xpd = NA, font = par("font.lab"), cex = par("cex.lab")) 
     } 
     else { 
      mtext(ylab[2L], 4, line = 3.25, at = 0.5 * f.row, 
       outer = TRUE, xpd = NA, font = par("font.lab"), 
       cex = par("cex.lab")) 
     } 
    } 
    if (length(missingrows)) { 
     cat("\n", gettextf("Missing rows: %s", paste0(missingrows, 
      collapse = ", ")), "\n") 
     invisible(missingrows) 
    } 
    else invisible() 
} 

使用這個新的coplot2函數,您現在可以使用此代碼生成圖表。我還修正了y軸的範圍,使它們在行間保持不變。

coplot2(y~x|a+b, 
    # make a fake y col to cover range of all y1 and y2 values 
    cbind(dd, y=seq(min(dd$y1, dd$y2), max(dd$y1, dd$y2), length.out=nrow(dd))), xlab="", ylab = "", main = "", xaxs=FALSE, 
    #request subscripts to be sent to panel function 
    subscripts=TRUE, 
    panel=function(x,y,subscripts, ...) { 
      # add first plot for y1 
      par(new=T) 
      plot(x, dd$y1[subscripts], axes = F, ylim=(range(dd$y1))) 
     # draw group 1 
     lines(x, dd$y1[subscripts]) 
     if(subscripts[[5]]|subscripts[[30]]|subscripts[[55]]) axis(2, col = "black", lwd = 2, cex.axis=0.9)# - and this? 
     if(subscripts[[30]]) mtext(2, text = "name y1 axe", col = "black",line=2) 

     # add data on secondary y2 axis 
     par(new=T) 
     plot(x, dd$y2[subscripts], axes = F, ylim=(range(dd$y2))) 
     lines(x, dd$y2[subscripts], col="red") 
     if(subscripts[[25]]|subscripts[[50]]|subscripts[[75]]) axis(4, col = "red", col.axis="red", lwd = 2, cex.axis=0.9)# - and this? 
     if(subscripts[[50]]) mtext(4, text = "name y2 axe", col = "red",line=2) 
}) 

enter image description here

+0

嗨@PLapointe,感謝您的回答!然而,我的y1比例是3 - 51,我的y2比例是105 - 558.因此,在我的例子中,我只保留y1的比例,但我想保持這個比例幷包含比例y2。在你的情節中,只有y2的比例,但y1缺失?請問,我怎樣才能保持y1和y2的比例?再次感謝你! – maycca

+0

這就是爲什麼我懷疑你可能想創建自己的'coplot'函數。查看我的更新以瞭解您的問題以獲取完整的步行。 –

+0

哇!謝謝 !!那是我的(你的)第一個OWN修改函數!!再次感謝您分享您的知識,並幫助我發現R的力量:-DD這真的很令人興奮! :)) – maycca