美文网首页R基因组数据绘图ggplot2绘图
R小tip(五)横断坐标轴画法

R小tip(五)横断坐标轴画法

作者: 小潤澤 | 来源:发表于2020-01-16 20:11 被阅读0次

    前言

    转载自:https://www.jianshu.com/p/de283990ecd1
    以获得博主的转载许可权
    最近日常闲逛的时候,无意间看到大神@六六_ryx写的这篇推送,在这里我们大家一起学习如何用R画横断坐标轴

    示例数据

    我们以原推送的示例数据为例:

    df <- data.frame(name=c("AY","BY","CY","DY","EY","FY","GY"),Money=c(1510,1230,995,48,35,28,10))
    df
    
    #加载 R 包
    library(ggplot2)
    # ggplot画图
    p0 <- ggplot(df, aes(name,Money,fill = name)) +
      geom_col(position = position_dodge(width = 0.8),color="black") +
      labs(x = NULL, y = NULL) +
      scale_fill_brewer(palette="Accent")+
      #scale_x_discrete(expand = c(0, 0)) +
      scale_y_continuous(breaks = seq(0, 1600, 400), limits = c(0, 1600), expand = c(0,0)) +
      theme(axis.text.x = element_text(angle = 45, hjust = 1), legend.title = element_blank())
    
    p0
    
    全图

    正常图形是这样的

    分割组合法

    这个方法就是把一张图按自己的需求截取成两张,然后再拼接成一张

    p1 = p0 + coord_cartesian(ylim = c(0,50)) +  #以y轴为基础截取p0的0-50部分
      theme_classic()+
      theme(legend.position = "none")
    
    p1
    
    p1
    p2 = p0 + coord_cartesian(ylim = c(700,1600)) + #以y轴为基础截取p0的700-1600部分
      theme_classic() + 
      theme(axis.line.x = element_line(colour = "white"),
            axis.text.x = element_blank(),axis.ticks.x = element_blank(),
            legend.position = c(0.85,0.6))
    
    p2
    
    p2
    library(grid)
    
    grid.newpage()
    plot_site1 = viewport(x = 0.008,y = 0,width = 0.994,height = 0.4,just = c('left','bottom')) #其中x,y是调位置参数用的
    plot_site2 = viewport(x = -0.035,y = 0.4,width = 1,height = 0.5,just = c('left','bottom')) #其中x,y是调位置参数用的
    print(p1,vp = plot_site1)
    print(p2,vp = plot_site2)
    
    image.png

    这个办法比较笨,而且不好看

    plotrix R包

    library(plotrix)
    
    gap.barplot(df$Money,gap = c(50,740),xaxlab = df$name,ytics = c(50,700,800,900,1000,1100,1200,1300,1400,1500,1600),
                col = rainbow(7),xlim = c(0,8),width) #gap为设置断点区间
    
    image.png

    我们还可以改的更魔性化一点:

    axis.break(2,50,breakcol = "snow",style = "gap") #数字代表断轴位置
    axis.break(2,50*(1+0.02),breakcol = "black",style = "slash") #根据不同风格改形状
    
    image.png

    大神自编函数

    链接:https://blog.csdn.net/u014801157/article/details/24372371
    我们看看原函数形式:

    gap.barplot <- function(df, y.cols = 1:ncol(df), sd.cols = NULL, btm = NULL,
                            top = NULL, min.range = 10, max.fold = 5, ratio = 1, gap.width = 1, brk.type = "normal",
                            brk.bg = "white", brk.srt = 135, brk.size = 1, brk.col = "black", brk.lwd = 1,
                            cex.error = 1, ...) {
      if (missing(df))
        stop("No data provided.")
      if (is.numeric(y.cols))
        ycol <- y.cols else ycol <- colnames(df) == y.cols
        if (!is.null(sd.cols))
          if (is.numeric(sd.cols))
            scol <- sd.cols else scol <- colnames(df) == sd.cols
            ## Arrange data
            opts <- options()
            options(warn = -1)
            y <- t(df[, ycol])
            colnames(y) <- NULL
            if (missing(sd.cols))
              sdx <- 0 else sdx <- t(df[, scol])
            sdu <- y + sdx
            sdd <- y - sdx
            ylim <- c(0, max(sdu) * 1.05)
            ## 如果没有设置btm或top,自动计算
            if (is.null(btm) | is.null(top)) {
              autox <- .auto.breaks(dt = sdu, min.range = min.range, max.fold = max.fold)
              if (autox$flag) {
                btm <- autox$btm
                top <- autox$top
              } else {
                xx <- barplot(y, beside = TRUE, ylim = ylim, ...)
                if (!missing(sd.cols))
                  errorbar(xx, y, sdu - y, horiz = FALSE, cex = cex.error)
                box()
                return(invisible(xx))
              }
            }
            ## Set up virtual y limits
            halflen <- btm - ylim[1]
            xlen <- halflen * 0.1 * gap.width
            v_tps1 <- btm + xlen  # virtual top positions
            v_tps2 <- v_tps1 + halflen * ratio
            v_ylim <- c(ylim[1], v_tps2)
            r_tps1 <- top  # real top positions
            r_tps2 <- ylim[2]
            ## Rescale data
            lmx <- summary(lm(c(v_tps1, v_tps2) ~ c(r_tps1, r_tps2)))
            lmx <- lmx$coefficients
            sel1 <- y > top
            sel2 <- y >= btm & y <= top
            y[sel1] <- y[sel1] * lmx[2] + lmx[1]
            y[sel2] <- btm + xlen/2
            sel1 <- sdd > top
            sel2 <- sdd >= btm & sdd <= top
            sdd[sel1] <- sdd[sel1] * lmx[2] + lmx[1]
            sdd[sel2] <- btm + xlen/2
            sel1 <- sdu > top
            sel2 <- sdu >= btm & sdu <= top
            sdu[sel1] <- sdu[sel1] * lmx[2] + lmx[1]
            sdu[sel2] <- btm + xlen/2
            ## bar plot
            xx <- barplot(y, beside = TRUE, ylim = v_ylim, axes = FALSE, names.arg = NULL,
                          ...)
            ## error bars
            if (!missing(sd.cols))
              errorbar(xx, y, sdu - y, horiz = FALSE, cex = cex.error)
            ## Real ticks and labels
            brks1 <- pretty(seq(0, btm, length = 10), n = 4)
            brks1 <- brks1[brks1 >= 0 & brks1 < btm]
            brks2 <- pretty(seq(top, r_tps2, length = 10), n = 4)
            brks2 <- brks2[brks2 > top & brks2 <= r_tps2]
            labx <- c(brks1, brks2)
            ## Virtual ticks
            brks <- c(brks1, brks2 * lmx[2] + lmx[1])
            axis(2, at = brks, labels = labx)
            box()
            ## break marks
            pos <- par("usr")
            xyratio <- (pos[2] - pos[1])/(pos[4] - pos[3])
            xlen <- (pos[2] - pos[1])/50 * brk.size
            px1 <- pos[1] - xlen
            px2 <- pos[1] + xlen
            px3 <- pos[2] - xlen
            px4 <- pos[2] + xlen
            py1 <- btm
            py2 <- v_tps1
            rect(px1, py1, px4, py2, col = brk.bg, xpd = TRUE, border = brk.bg)
            x1 <- c(px1, px1, px3, px3)
            x2 <- c(px2, px2, px4, px4)
            y1 <- c(py1, py2, py1, py2)
            y2 <- c(py1, py2, py1, py2)
            px <- .xy.adjust(x1, x2, y1, y2, xlen, xyratio, angle = brk.srt * pi/90)
            if (brk.type == "zigzag") {
              x1 <- c(x1, px1, px3)
              x2 <- c(x2, px2, px4)
              if (brk.srt > 90) {
                y1 <- c(y1, py2, py2)
                y2 <- c(y2, py1, py1)
              } else {
                y1 <- c(y1, py1, py1)
                y2 <- c(y2, py2, py2)
              }
            }
            if (brk.type == "zigzag") {
              px$x1 <- c(pos[1], px2, px1, pos[2], px4, px3)
              px$x2 <- c(px2, px1, pos[1], px4, px3, pos[2])
              mm <- (v_tps1 - btm)/3
              px$y1 <- rep(c(v_tps1, v_tps1 - mm, v_tps1 - 2 * mm), 2)
              px$y2 <- rep(c(v_tps1 - mm, v_tps1 - 2 * mm, btm), 2)
            }
            par(xpd = TRUE)
            segments(px$x1, px$y1, px$x2, px$y2, lty = 1, col = brk.col, lwd = brk.lwd)
            options(opts)
            par(xpd = FALSE)
            invisible(xx)
    }
    ## 绘制误差线的函数
    errorbar <- function(x, y, sd.lwr, sd.upr, horiz = FALSE, cex = 1, ...) {
      if (missing(sd.lwr) & missing(sd.upr))
        return(NULL)
      if (missing(sd.upr))
        sd.upr <- sd.lwr
      if (missing(sd.lwr))
        sd.lwr <- sd.upr
      if (!horiz) {
        arrows(x, y, y1 = y - sd.lwr, length = 0.1 * cex, angle = 90, ...)
        arrows(x, y, y1 = y + sd.upr, length = 0.1 * cex, angle = 90, ...)
      } else {
        arrows(y, x, x1 = y - sd.lwr, length = 0.1 * cex, angle = 90, ...)
        arrows(y, x, x1 = y + sd.upr, length = 0.1 * cex, angle = 90, ...)
      }
    }
    .xy.adjust <- function(x1, x2, y1, y2, xlen, xyratio, angle) {
      xx1 <- x1 - xlen * cos(angle)
      yy1 <- y1 + xlen * sin(angle)/xyratio
      xx2 <- x2 + xlen * cos(angle)
      yy2 <- y2 - xlen * sin(angle)/xyratio
      return(list(x1 = xx1, x2 = xx2, y1 = yy1, y2 = yy2))
    }
    ## 自动计算断点位置的函数
    .auto.breaks <- function(dt, min.range, max.fold) {
      datax <- sort(as.vector(dt))
      flags <- FALSE
      btm <- top <- NULL
      if (max(datax)/min(datax) < min.range)
        return(list(flag = flags, btm = btm, top = top))
      m <- max(datax)
      btm <- datax[2]
      i <- 3
      while (m/datax[i] > max.fold) {
        btm <- datax[i]
        flags <- TRUE
        i <- i + 1
      }
      if (flags) {
        btm <- btm + 0.05 * btm
        x <- 2
        top <- datax[i] * (x - 1)/x
        while (top < btm) {
          x <- x + 1
          top <- datax[i] * (x - 1)/x
          if (x > 100) {
            flags <- FALSE
            break
          }
        }
      }
      return(list(flag = flags, btm = btm, top = top))
    }
    
    参数图

    下面我们用个例子来说明:
    首先用官方例子来说明:

    datax <- na.omit(airquality)[, 1:4]
    cols <- terrain.colors(ncol(datax) - 1)
    layout(matrix(1:4, ncol = 2))
    set.seed(0)
    for (ndx in 1:4) {
      dt <- datax[sample(rownames(datax), 10), ]
      dt <- cbind(dt, dt[, -1] * 0.1)
      par(mar = c(1, 3, 0.5, 0.5))
      brkt <- sample(c("normal", "zigzag"), 1)
      gap.barplot(dt, y.cols = 2:4, sd.cols = 5:7, col = cols, brk.type = brkt,
                  brk.size = 0.6, brk.lwd = 2, max.fold = 5, ratio = 2, cex.error = 0.3)
    }
    
    image.png

    官方例子一画就是四幅图,如果我们要画一幅图,可以搭配par()这个函数,选用fig这个参数
    以下是我的画法:

    datax <- na.omit(airquality)[, 1:4]
    cols <- terrain.colors(ncol(datax) - 1)
    dt <- datax[sample(rownames(datax), 10), ]
    dt <- cbind(dt, dt[, -1] * 0.1)
    par(fig=c(0,1,0.05,1)) #四个参数代表位置信息
    gap.barplot(dt, y.cols = 2:4, sd.cols = 5:7, col = cols, brk.type = brkt,
                brk.size = 0.6, brk.lwd = 2, max.fold = 5, ratio = 2, cex.error = 0.3)
    
    image.png

    这是不是很完美呢?
    嗯嗯,我是小潤澤,我只负责传播知识

    相关文章

      网友评论

        本文标题:R小tip(五)横断坐标轴画法

        本文链接:https://www.haomeiwen.com/subject/svafzctx.html