2013-03-04 11 views
7

Il tracciato di R è ottimo per l'esplorazione dei dati, poiché spesso ha impostazioni predefinite molto intelligenti. Ad esempio, quando si esegue il tracciamento con una formula, le etichette per gli assi del diagramma derivano dalla formula. In altre parole, le seguenti due chiamate producono lo stesso risultato:Come posso rinominare automaticamente un grafico con la chiamata R che lo ha prodotto?

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

C'è un modo per ottenere un simile "auto-titolo intelligente"?

Per esempio, vorrei chiamare

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

e producono lo stesso risultato chiamando

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

Qualora il <something> inserisce la chiamata usata utilizzando qualche tipo di introspezione.

C'è una funzione per farlo in R, tramite un meccanismo standard o un pacchetto esterno?

modifica: un suggerimento era di specificare la formula come stringa e fornirla come argomento per una chiamata formula() e main. Questo è utile, ma perde i parametri che possono influenzare un grafico, come l'utilizzo di sottoinsiemi di dati. Elaborare, mi piacerebbe

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>) 

Per avere lo stesso effetto di

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

risposta

7

non credo che questo può essere fatto senza scrivere un sottile wrapper plot(). Il motivo è che R valuta gli "argomenti forniti" nel frame di valutazione della funzione chiamante, in cui non è possibile accedere alla chiamata della funzione corrente (see here for details).

Al contrario, "gli argomenti predefiniti" vengono valutati nel frame di valutazione della funzione, da cui è possibile l'introspezione . Qui ci sono un paio di possibilità (che differiscono solo in se si desidera "MyPlot" o "complotto" per comparire nel titolo:

## 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) 

Ecco una soluzione più generale:

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 tenterà di interrompe le linee deparsate se diventano troppo lunghe (il valore predefinito è 60 caratteri) .Quando esegue questa operazione, restituisce un vettore di stringhe. I metodi di plot presuppongono che 'main' sia una stringa singola, quindi la riga main <- paste(main, collapse='\n') risolve tutto concatenando tutto le stringhe restituite da sparse, unendole usando \n.

Ecco un esempio di dove questo è necessario:

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

Brillante! Penso che la soluzione più generale risolva il problema abbastanza bene. È fondamentalmente lo stesso di myplot2 di Greg Snows, ma ho scelto questo perché penso sia più facile capire come funziona. – saffsd

+0

@saffsd: idee fantastiche nelle modifiche che hai apportato. Grazie! Per favore, includi un esempio che mostri dove potrebbe entrare in gioco 'paste (main, collapse =" \ n ")'? –

3

Certo che c'è! Qui ya go:

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

something = "y~x" 

plot(formula(something),main=something) 

enter image description here

+1

è 'paste' davvero necessario? – joran

+0

Puoi modificarlo per ottenere esattamente ciò che desideri ma ottieni l'idea. –

+0

Puoi farlo senza la pasta. –

3

Si potrebbe pensare delle funzionalità di match.call. Tuttavia, funziona solo quando chiamato all'interno di una funzione, non passato come argomento.È possibile creare la funzione wrapper che avrebbe chiamato match.call quindi passare tutto il resto per plot o utilizzare sostituto per catturare la chiamata poi modificarlo con la chiamata prima di valutare:

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))) 
Problemi correlati