• ggplot2绘制双坐标轴图


    R包ggplot2绘图精美,可以做出很复杂的图形,深受用户喜爱。它的作者hadley并不推荐使用ggplot2绘制双坐标轴图,认为这样会增加读图的难度,但是目前需要双坐标轴图应用的场景还是很多,如下图形直方图和曲线分别有不同的坐标轴,表示不同的意思,图片展示内容比较丰富
    在这里插入图片描述
    在这里插入图片描述
    今天我们通过我们的汽车销售数据(公众号回复:汽车销售,可以获得数据)来演示一下ggplot2绘制双坐标轴图,主要是通过sec.axis函数进行转换,进行第二个坐标轴的转换。我们先来导入数据

    library(foreign)
    library(ggplot2)
    library(plyr)
    bc <- read.spss("E:/r/test/tree_car.sav",
                    use.value.labels=F, to.data.frame=T)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    我们来看下数据,car就是汽车售价,age是年龄,gender是性别,inccat是收入,这里分成4个等级,ed是教育程度。
    我们用这个数据生成两个子数据,展示不同教育程度人群购车的区别,继续使用原来的summarySE函数生成数据,想了解这个函数的看《R语言绘制带误差和可信区间的折线图》这篇文章,主要是利用这个函数生成不同类型的数据分析指标,函数的代码如下:

    summarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=FALSE,
                          conf.interval=.95, .drop=TRUE) {
      library(plyr)
      
      # New version of length which can handle NA's: if na.rm==T, don't count them
      length2 <- function (x, na.rm=FALSE) {
        if (na.rm) sum(!is.na(x))
        else       length(x)
      }
      
      # This does the summary. For each group's data frame, return a vector with
      # N, mean, and sd
      datac <- ddply(data, groupvars, .drop=.drop,
                     .fun = function(xx, col) {
                       c(N    = length2(xx[[col]], na.rm=na.rm),
                         mean = mean   (xx[[col]], na.rm=na.rm),
                         sd   = sd     (xx[[col]], na.rm=na.rm)
                       )
                     },
                     measurevar
      )
      
      # Rename the "mean" column    
      datac <- rename(datac, c("mean" = measurevar))
      
      datac$se <- datac$sd / sqrt(datac$N)  # Calculate standard error of the mean
      
      # Confidence interval multiplier for standard error
      # Calculate t-statistic for confidence interval: 
      # e.g., if conf.interval is .95, use .975 (above/below), and use df=N-1
      ciMult <- qt(conf.interval/2 + .5, datac$N-1)
      datac$ci <- datac$se * ciMult
      
      return(datac)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    这个函数并不是今天的主要内容,主要是看我们生成的数据

    carss<- summarySE(bc, measurevar="car", groupvars=c("gender","ed"))
    carss1<- summarySE(bc, measurevar="car", groupvars=c("inccat","ed"))
    
    • 1
    • 2

    我们来看看生成的两个数据
    Carss
    在这里插入图片描述
    carss1
    在这里插入图片描述
    carss1和carss都有ed这个数据,carss1的数据比carss多,carss1有inccat这个指标carss没有
    我们先画一个carss数据的教育和汽车售价的直方图

    ggplot() +
      geom_col( data = carss,aes(x = ed,y = car),fill="#6794a7")
    
    • 1
    • 2

    在这里插入图片描述
    上图展示了不同教育程度买车的情况,假设我们想把carss1这个数据的inccat和ci这个指标映射进上图中(不管临床意义,只是展示数据映射),我们可以看到ci这个指标很小0-5这样,而汽车这个指标的范围是0-80,不能通过同一坐标轴展示,所以只能通过分轴展示。主要是通过rescale函数先把ci这个指标在在0-80区间进行标准化转换,然后在投射于右坐标轴。
    先把inccat转换成因子

    carss1$inccat<-as.factor(carss1$inccat)
    
    • 1

    绘图

    ggplot() +
      geom_col( data = carss,aes(x = ed,y = car),fill="#6794a7")+
      geom_line(data = carss1,aes(x = ed,y = rescale(ci,c(0,80)),colour=inccat,group=inccat),size=1.5) +
      geom_point(data = carss1,aes(x = ed,y = rescale(ci,c(0,80))),shape=21,fill="white",size=4)+
      scale_y_continuous(breaks=pretty_breaks(4),
                         sec.axis = sec_axis( ~rescale(.,c(0,5)),name = "ci",labels=sprintf('%.5f',(0:5))))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    图形左轴表示直方图中购车情况,右轴表示不同收入人群的ci情况,把图形进一步美化一下

    ggplot() +
      geom_col( data = carss,aes(x = ed,y = car),fill="#6794a7")+
      geom_line(data = carss1,aes(x = ed,y = rescale(ci,c(0,80)),colour=inccat,group=inccat),size=1.5) +
      geom_point(data = carss1,aes(x = ed,y = rescale(ci,c(0,80))),shape=21,fill="white",size=4)+
      scale_y_continuous(breaks=pretty_breaks(4),
                         sec.axis = sec_axis( ~rescale(.,c(0,5)),name = "ci",labels=sprintf('%.5f',(0:5))))+
      labs(title="This is a Title!",subtitle="This is a Subtitle",caption="This is a Caption")+
      theme_minimal(base_size=16) %+replace% 
      theme(
        plot.caption = element_text(hjust=0),
        plot.margin = unit(c(1,0.5,1,0.5), "lines")
      )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    参考文献

    1. ggplot2:数据分析与图形艺术
    2. ggplot2双坐标轴的解决方案 杜雨 https://zhuanlan.zhihu.com/p/31872309
  • 相关阅读:
    【机器学习】7 ——k近邻算法
    LeetCode(力扣)39. 组合总和Python
    降噪耳机哪款比较舒适?比较舒适的降噪耳机盘点
    MySQL:基本查询 | 表的增删改查
    一个 println 竟然比 volatile 还好使?
    044-WEB攻防-PHP应用&SQL盲注&布尔回显&延时判断&报错处理&增删改查方式
    linux安装gcc4.6.1
    优优嗨聚集团:美团外卖,让美好儿童餐计划触手可及
    [剑指 Offer 62]圆圈中最后剩下的数字(约瑟夫环问题:动态规划)
    人工神经网络与神经网络,人工神经网络入门书籍
  • 原文地址:https://blog.csdn.net/dege857/article/details/126026759