上面的函数对于不完整的行还是没法处理啊
想了想,与其写函数的人折腾得死去活来,不如让用户自觉遵守规范,不把注释写在行末算了
我最终决定不管那些写在行末的注释,并添加了几个参数,让用户可以控制是否保留注释(keep.comment)、是否保留空行(keep.blank.line)、注释首尾的标记,并保证这两个标记与原始代码没有冲突:
tidy.source <- function(source = "clipboard", keep.comment = TRUE, <br />
keep.blank.line = FALSE, begin.comment, end.comment, ...) {<br />
# parse and deparse the code<br />
tidy.block = function(block.text) {<br />
exprs = parse(text = block.text)<br />
n = length(exprs)<br />
res = character(n)<br />
for (i in 1:n) {<br />
dep = paste(deparse(exprs[i]), collapse = "\n")<br />
res[i] = substring(dep, 12, nchar(dep) - 1)<br />
}<br />
return(res)<br />
}<br />
text.lines = readLines(source, warn = FALSE)<br />
if (keep.comment) {<br />
# identifier for comments<br />
identifier = function() paste(sample(LETTERS), collapse = "")<br />
if (missing(begin.comment)) <br />
begin.comment = identifier()<br />
if (missing(end.comment)) <br />
end.comment = identifier()<br />
# remove leading and trailing white spaces<br />
text.lines = gsub("^[[:space:]]+|[[:space:]]+$", "", <br />
text.lines)<br />
# make sure the identifiers are not in the code<br />
# or the original code might be modified<br />
while (length(grep(sprintf("%s|%s", begin.comment, end.comment), <br />
text.lines))) {<br />
begin.comment = identifier()<br />
end.comment = identifier()<br />
}<br />
head.comment = substring(text.lines, 1, 1) == "#"<br />
# add identifiers to comment lines to cheat R parser<br />
if (any(head.comment)) {<br />
text.lines[head.comment] = gsub("\"", "\'", text.lines[head.comment])<br />
text.lines[head.comment] = sprintf("%s=\"%s%s\"", <br />
begin.comment, text.lines[head.comment], end.comment)<br />
}<br />
# keep blank lines?<br />
blank.line = text.lines == ""<br />
if (any(blank.line) & keep.blank.line) <br />
text.lines[blank.line] = sprintf("%s=\"%s\"", begin.comment, <br />
end.comment)<br />
text.tidy = tidy.block(text.lines)<br />
# remove the identifiers<br />
text.tidy = gsub(sprintf("%s = \"|%s\"", begin.comment, <br />
end.comment), "", text.tidy)<br />
}<br />
else {<br />
text.tidy = tidy.block(text.lines)<br />
}<br />
cat(paste(text.tidy, collapse = "\n"), "\n", ...)<br />
invisible(text.tidy)<br />
} <br />
测试:
> tidy.source('http://addictedtor.free.fr/graphiques/sources/source_152.R')<br />
#' Represents Correlation circles<br />
#'<br />
#' @author Taiyun Wei<br />
#' @param corr Correlation matrix to represent<br />
#' @param col vector the fill color of circles from 1 to -1<br />
#' the length of it may not be 2, eg rainbow(50)<br />
#' @param bg background color of graph<br />
#' @param cex numeric, for the variable names<br />
#' @param order whether reorder the variables using principal<br />
#' component analysis of the correlation matrix<br />
#' @param title title of the graph<br />
#' @param ... extra parameters, currenlty ignored<br />
circle.corr <- function(corr, col = c("black", "white"), <br />
bg = "white", cex = 1, order = FALSE, title = "", ...) {<br />
if (is.null(corr)) <br />
return(invisible())<br />
if ((!is.matrix(corr)) || (round(min(corr, na.rm = TRUE), <br />
6) < -1) || (round(max(corr, na.rm = TRUE), 6) > 1)) <br />
stop("Need a correlation matrix!")<br />
n <- nrow(corr)<br />
m <- ncol(corr)<br />
## reorder the variables using principal component analysis<br />
if (order) {<br />
if (!n == m) {<br />
stop("The matrix must be squre if order is TRUE!")<br />
}<br />
x.eigen <- eigen(corr)$vectors[, 1:2]<br />
e1 <- x.eigen[, 1]<br />
e2 <- x.eigen[, 2]<br />
alpha <- ifelse(e1 > 0, atan(e2/e1), atan(e2/e1) + pi)<br />
corr <- corr[order(alpha), order(alpha)]<br />
}<br />
## set up variable names<br />
rname <- rownames(corr)<br />
cname <- colnames(corr)<br />
if (is.null(rname)) <br />
rname <- 1:n<br />
if (is.null(cname)) <br />
cname <- 1:m<br />
rname <- as.character(rname)<br />
cname <- as.character(cname)<br />
## calculate label-text width approximately<br />
par(mar = c(0, 0, 2, 0), bg = "white")<br />
plot.new()<br />
plot.window(c(0, m), c(0, n), asp = 1)<br />
xlabwidth <- max(strwidth(rname, cex = cex))<br />
ylabwidth <- max(strwidth(cname, cex = cex))<br />
## set up an empty plot with the appropriate dimensions<br />
plot.window(c(-xlabwidth + 0.5, m + 0.5), c(0, n + 1 + ylabwidth), <br />
asp = 1, xlab = "", ylab = "")<br />
rect(0.5, 0.5, m + 0.5, n + 0.5, col = bg)<br />
## add variable names and title<br />
text(rep(-xlabwidth/2, n), n:1, rname, col = "red", cex = cex)<br />
text(1:m, rep(n + 1 + ylabwidth/2, m), cname, srt = 90, col = "red", <br />
cex = cex)<br />
title(title)<br />
## add grid<br />
segments(rep(0.5, n + 1), 0.5 + 0:n, rep(m + 0.5, n + 1), <br />
0.5 + 0:n, col = "gray")<br />
segments(0.5 + 0:m, rep(0.5, m + 1), 0.5 + 0:m, rep(n + 0.5, <br />
m), col = "gray")<br />
## assign circles' fill color<br />
nc <- length(col)<br />
if (nc == 1) <br />
bg <- rep(col, n * m)<br />
else {<br />
ff <- seq(-1, 1, length = nc + 1)<br />
bg2 = rep(0, n * m)<br />
for (i in 1:(n * m)) {<br />
bg2[i] <- rank(c(ff[2:nc], as.vector(corr)[i]), ties.method = "random")[nc]<br />
}<br />
bg <- (col[nc:1])[bg2]<br />
}<br />
## plot n*m circles using vector language, suggested by Yihui Xie<br />
## the area of circles denotes the absolute value of coefficient<br />
symbols(rep(1:m, each = n), rep(n:1, m), add = TRUE, inches = F, <br />
circles = as.vector(sqrt(abs(corr))/2), bg = as.vector(bg))<br />
}<br />
## examples<br />
data(mtcars)<br />
circle.corr(cor(mtcars), order = TRUE, bg = "gray50", <br />
col = colorRampPalette(c("blue", "white", "red"))(100))