2013-03-04 32 views
7

R的绘图非常适合数据探索,因为它通常具有非常明智的默认值。例如,使用公式绘图时,绘图轴的标签是从公式中导出的。换句话说,下面的两个调用产生相同的输出:如何使用生成它的R调用自动标题剧情?

plot(x~y) 
plot(x~y, xlab="x", ylab="y") 

有没有什么办法让类似的“智能自动标题”?

例如,我想打电话给

plot(x~y, main=<something>) 

,并产生相同的输出作为调用

plot(x~y, main="plot(x~y)") 

<something>插入使用某种反省的调用中使用。

在R中是否有这样的工具可以通过某种标准机制或外部包?

编辑:一个建议是将公式作为字符串指定,并将其作为参数提供给formula()调用以及main。这很有用,但它会忽略参数,而不会影响绘图,例如使用数据子集。为了详细说明,我想

x<-c(1,2,3) 
y<-c(1,2,3) 
z<-c(0,0,1) 
d<-data.frame(x,y,z) 
plot(x~y, subset(d, z==0), main=<something>) 

具有相同的效果

plot(x~y, subset(d, z==0), main="plot(x~y, subset(d, z==0))") 

回答

7

我不认为这可以在不围绕plot()写一个瘦包装来完成。原因在于R在调用函数的评估框架中评估“提供的参数”,其中无法访问当前函数调用(see here for details)。

相比之下,在函数的评估框架中评估“默认参数”,从其中自省是可能的。这里有几个可能性(在短短的不同是否要“myPlot”或“暗算”出现在标题:

## Function that reports actual call to itself (i.e. 'myPlot()') in plot title. 
myPlot <- function(x,...) { 
    cl <- deparse(sys.call()) 
    plot(x, main=cl, ...) 
} 

## Function that 'lies' and says that plot() (rather than myPlot2()) called it. 
myPlot2 <- function(x,...) { 
    cl <- sys.call() 
    cl[[1]] <- as.symbol("plot") 
    cl <- deparse(cl) 
    plot(x, main=cl, ...) 
} 

## Try them out 
x <- 1:10 
y <- 1:10 
par(mfcol=c(1,2)) 
myPlot(x,y) 
myPlot2(y~x) 

这里有一个更通用的解决方案:

plotCaller <- function(plotCall, ...) { 
    main <- deparse(substitute(plotCall)) 
    main <- paste(main, collapse="\n") 
    eval(as.call(c(as.list(substitute(plotCall)), main=main, ...))) 
} 

## Try _it_ out 

plotCaller(hist(rnorm(9999), breaks=100, col="red")) 

library(lattice) 
plotCaller(xyplot(rnorm(10)~1:10, pch=16)) 

## plotCaller will also pass through additional arguments, so they take effect 
## without being displayed 
plotCaller(xyplot(rnorm(10)~1:10), pch=16) 

deparse将尝试如果它们变得太长(默认是60个字符),那么会打破分解线(当默认值是60个字符时),当它返回一个字符串向量时,plot方法假定'main'是一个单独的字符串,所以行main <- paste(main, collapse='\n')通过连接所有通过deparse返回的字符串,使用\n加入它们。

这里是哪里,这是必要的一个例子:

plotCaller(hist(rnorm(9999), breaks=100, col="red", xlab="a rather long label", 
    ylab="yet another long label")) 
+0

太棒了!我认为更一般的解决方案很好地解决了这个问题。它与Greg Snows的myplot2基本相同,但我选择了这个,因为我认为它更容易理解它的工作原理。 – saffsd 2013-03-05 00:30:50

+0

@saffsd - 在您所做的修改中使用了很酷的想法。谢谢!你能否给我们一个例子说明'paste(main,collapse =“\ n”)'可能会发挥作用? – 2013-03-06 03:00:23

3

当然有!这里亚去:

x = rnorm(100) 
y = sin(x) 

something = "y~x" 

plot(formula(something),main=something) 

enter image description here

+1

是'paste'真的有必要吗? – joran 2013-03-04 23:27:06

+0

你可以编辑它来得到你想要的东西,但你明白了。 – 2013-03-04 23:27:17

+0

你可以不用粘贴。 – 2013-03-04 23:28:26

3

你可能会想的match.call功能。但是,只有在函数内调用时才有效,而不是作为参数传入。你可以创建你的包装函数将调用match.call然后通过一切到plot或评估之前使用替代品来捕获呼叫然后修改它与呼叫:

x <- runif(25) 
y <- rnorm(25, x, .1) 

myplot <- function(...) { 
    tmp <- match.call() 
    plot(..., main=deparse(tmp)) 
} 

myplot(y~x) 
myplot(y~x, xlim=c(-.25,1.25)) 

## or 

myplot2 <- function(FUN) { 
    tmp1 <- substitute(FUN) 
    tmp2 <- deparse(tmp1) 
    tmp3 <- as.list(tmp1) 
    tmp4 <- as.call(c(tmp3, main=tmp2)) 
    eval(tmp4) 
} 

myplot2(plot(y~x)) 
myplot2(plot(y~x, xlim=c(-.25,1.25)))