Overview

昨天写了个R语言脚本,主要是借助ROCR包画ROC曲线,只是最后画图时,没用ROCR提供的plot函数画ROC曲线,而是用ROCR处理了数据后,提取了画图的数据,用ggplot2包画了ROC曲线。因为ggplot2可以提供强大的自定义绘图功能,没想到也正是这个自定义样式函数,在移植的时候出现了一些兼容性问题。

1. 问题描述

我使用的ggplot2样式函数,是一个我已经用了一年多的样式,专门写在了一个名字叫style.R的R文件中,内容如下:

library(grid)

theme_custom <- function (base_size = 10, base_family = "serif") {
    theme_grey(base_size = base_size, base_family = base_family) %+replace%
    theme(
          line =               element_line(colour = "black", size = 1, linetype = 1, lineend = "butt"),
          rect =               element_rect(fill = "white", colour = "black", size = 1, linetype = 1),
          text =               element_text(family = base_family, face = "plain", colour = "black", size = base_size, hjust = 0.5, vjust = 0.5, angle = 0, lineheight = 0.9),
          axis.text =          element_text(size = rel(0.8), colour = "grey50"),
          strip.text =         element_text(size = rel(0.8)),
          ## used to delete the text up the picture    
          #strip.text = element_blank(),

          axis.line =          element_blank(),
          axis.text.x =        element_text(family = base_family, size = base_size * 1.2, lineheight = 0.8, vjust = 1.2),
          axis.text.y =        element_text(family = base_family, size = base_size * 1.2, lineheight = 0.8, hjust = 1.2),
          axis.ticks =         element_line(colour = "black", size=0.2),
          axis.title.x =       element_text(family = base_family, size = base_size*1.5, vjust = 0.5),
          axis.title.y =       element_text(family = base_family, size = base_size*1.5, angle = 90, vjust = 0.5),
          axis.ticks.length =  unit(0.15, "cm"),
          axis.ticks.margin =  unit(0.1, "cm"),
      
          legend.background =  element_rect (fill="white",colour="grey50", size=0.1, linetype=1),
          legend.margin =      unit(0.5, "cm"),
          legend.key =         element_rect(fill = "grey95", colour = "white"),
          legend.key.size =    unit(1.2, "lines"),
          legend.key.height =  NULL,
          legend.key.width =   NULL,
          legend.text =        element_text(family = base_family, size = base_size * 1.2),
          legend.text.align =  NULL,
          ##legend.title =       element_text(family = base_family, size = base_size * 3, face = "bold", hjust = 1),
          legend.title =element_blank(),
          legend.title.align = NULL,
          legend.position =    c(0.7,0.15),
          legend.direction =   NULL,
          legend.justification = "center",
          legend.box =         "horizontal",

          panel.background =   element_rect(fill = "white", colour = NA),
          panel.border =       element_rect(fill = NA, colour = "grey50"),
          panel.grid.major =   element_line(colour = "grey30", size = 0.5, linetype="dotted"),
          panel.grid.minor =   element_blank(),
          #panel.grid.minor =   element_line(colour = "grey30", size = 0.5, linetype="dotted"),
          ## panel.margin =       unit(c(0.1, 0.1, 0.1, 0.1), "lines"),

          strip.background =   element_rect(fill = NA, colour = NA),
          strip.text.x =       element_text(family = base_family, size = base_size * 0.8),
          strip.text.y =       element_text(family = base_family, size = base_size * 0.8, angle = -90),

          plot.background =    element_rect(colour = NA, fill = "white"),
          plot.title =         element_text(family = base_family, size = base_size),
          ##plot.title = element_blank(),
          plot.margin =        unit(c(0.5, 1, 0.5, 0.5), "lines") #top,right,bottom,left
    )
}

这个样式我在MacUbuntu 12.04上都使用过,都可以正常使用,但是这两天在windowsUbuntu 15.04上使用时都出了问题,报错如下:

警告信息:
`axis.ticks.margin` is deprecated. Please set `margin` property  of `axis.text` instead
错误于FUN("text"[[1L]], ...) :
  Theme element 'text' has NULL property: margin, debug
Calls: print ... element_render -> calc_element -> lapply -> FUN -> lapply -> FUN
停止执行

这其实是两个问题,一个警告,外加一个错误。

第一个警告信息很好理解,我把代码中的

axis.ticks.margin =  unit(0.1, "cm"),

直接注释掉就没有了。但是在windowsUbuntu 15.04上使用时,依然报错:

错误于FUN("text"[[1L]], ...) :
  Theme element 'text' has NULL property: margin, debug
Calls: print ... element_render -> calc_element -> lapply -> FUN -> lapply -> FUN
停止执行

2. 错误复现

首先想到的就是:为什么在MacUbuntu 12.04却没有报错,查了一些资料,终于在ggthemes的github issues 上面找到了原因,原因在于ggplot2总是在不停地更新,而更新之后,对于旧版本的兼容性不是很好,我的MacUbuntu 12.04使用的是旧版本,因此还可以正常使用,但是使用新版本的电脑就不能很好的兼容这段代码。因此我把mac下的ggplot2更新一下。在这里我并没有更新ggplot2,而是更新了ggthemes

2.1 ggthemes

ggthemes包:丰富ggplot2的表现力 这个链接的名字已经解释了ggthemes

ggplot2包的最新0.93版本允许自定义主题,这样ggplot的表现力可以通过各种不同的主题获得提升。
ggthemes包就是ggplot2的主题扩展包,提供了供ggplot2使用的新主题,尺度,几何对象和一些新函数。

其实这一两节是我后面加上的,原因是我google的时候正好在ggthemesgithub issues中找到了错误和复现的解决方法。 然后又理了一下思路,发现其实我想浮现这个问题,应该更新ggplot2包就可以了,单纯更新ggthemes应该会顺带更新它的依赖项,所以ggplot2也顺带更新了。

这里也只是一个逻辑上的分析,标记一下,以后再仔细确认。

2.2 安装devtools

在R交互命令行下,运行下面的命令安装devtools包:

install.packages("devtools")

2.3 从github上更新ggthemes

安装devtools包之后,就可以使用devtools包直接从github上更新最新的ggthemes了,而不是从CRAN上更新。 命令如下:

devtools::install_github("jrnold/ggthemes")

安装之后,重新运行ROC画图代码,谢天谢地,也报了同样的错误。

3. 解决方法

很明显,这个是由于ggplot2版本更新引起的一个兼容问题,在 github ggthemes issue=57可以找到答案:

It does look like the documentation for ggplot2 may not have been updated to account for changes made with ggplot2 2.0.0. ggplot2 version 2.0.0 added the elements margin and debug to element_text, so you need to change the text element of the theme...

新版本的ggplot2中,text = element_text()中,多了两个参数margindebug,我们上面style.R中,并没有使用这两个参数,所以才会报错,把style.R中:

text =               element_text(family = base_family, face = "plain", colour = "black", size = base_size, hjust = 0.5, vjust = 0.5, angle = 0, lineheight = 0.9),

修改为

text =               element_text(family = base_family, face = "plain", colour = "black", size = base_size, hjust = 0.5, vjust = 0.5, angle = 0, lineheight = 0.9,margin = margin(), debug = FALSE),

重新运行画图的R代码,就可以正常绘图了。