2010-10-14 20 views
133

Come dice il titolo: Come si può tracciare una legenda al di fuori dell'area di disegno quando si utilizza la grafica di base?Tracciare una legenda al di fuori dell'area di disegno nella grafica di base?

ho pensato di armeggiare intorno con layout e produrre una trama vuoto per contenere solo la leggenda, ma sarei interessato in modo utilizzando solo le strutture del grafico di base e, ad esempio, par(mar =) per ottenere qualche spazio a destra della trama per la leggenda.


Ecco un esempio:

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2)) 
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o") 
legend(1,-1,c("group A", "group B"), pch = c(1,2), lty = c(1,2)) 

produce:

alt text

Ma, come detto, vorrei che la leggenda di essere al di fuori dell'area tracciato (per esempio, a destra del grafico/grafico

+0

... si può anche incidere pari con il contenitore manichino per la leggenda, il time-to-tempo facile e molto conveniente. Domanda simile [qui] (http://stackoverflow.com/questions/8736647/adding-legend-annotate-to-rs-plot-similar-to-rs-ggplot). – hhh

+2

@hhh Il link non funziona più. Puoi aggiornarlo o pubblicare una risposta utilizzando questo approccio? – Henrik

risposta

84

Forse ciò che è necessario è par(xpd=TRUE) per consentire le cose da trarre fuori della regione trama. Quindi se fai la trama principale con bty='L' avrai uno spazio a destra per una legenda. Normalmente questo sarebbe ottenere agganciato alla regione trama, ma fare par(xpd=TRUE) e con un po 'di regolazione è possibile ottenere una leggenda come estrema destra in quanto si può andare:

set.seed(1) # just to get the same random numbers 
par(xpd=FALSE) # this is usually the default 

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2), bty='L') 
# this legend gets clipped: 
legend(2.8,0,c("group A", "group B"), pch = c(1,2), lty = c(1,2)) 

# so turn off clipping: 
par(xpd=TRUE) 
legend(2.8,-1,c("group A", "group B"), pch = c(1,2), lty = c(1,2)) 
+29

Si noti che è possibile passare direttamente xpd alla legenda in modo da non dover più preoccuparsi di reimpostare il par in un secondo momento. Vedi anche grconvertX & Y per un modo per specificare la posizione della legenda in un modo non dipendente dai limiti dei dati che stai tracciando. – Charles

+5

poichè questa domanda e risposta sono ancora molto popolari, 'par (xpd = NA)' è ancora più potente (cioè, stampa su più regioni). – Henrik

+0

+1. Dovremmo dire che ha senso avere una chiamata "par" separata proprio prima della legenda. Nella mia trama, ho usato 'par (new = T)' in molte altre occasioni e volevo semplicemente aggiungere il parametro 'xpd' nella stessa chiamata, il che causa problemi. –

2

Prova layout() che ho io per questo in passato, semplicemente creando una trama vuota di seguito, correttamente ridimensionata a circa 1/4 o giù di lì e inserendo manualmente le parti della legenda in essa.

Ci sono alcune vecchie domande qui su legend() che dovrebbe iniziare.

+0

Come già detto nella domanda, anche questo è ciò a cui ho pensato. Ma sarebbe l'ideale, se ci fosse un altro modo. In qualche modo suppongo che non ci sia. – Henrik

6

Posso offrire solo un esempio della soluzione di layout già indicata.

layout(matrix(c(1,2), nrow = 1), widths = c(0.7, 0.3)) 
par(mar = c(5, 4, 4, 2) + 0.1) 
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2)) 
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o") 
par(mar = c(5, 0, 4, 2) + 0.1) 
plot(1:3, rnorm(3), pch = 1, lty = 1, ylim=c(-2,2), type = "n", axes = FALSE, ann = FALSE) 
legend(1, 1, c("group A", "group B"), pch = c(1,2), lty = c(1,2)) 

an ugly picture :S

12

Ci scusiamo per resuscitare un vecchio thread, ma ero con lo stesso problema oggi. Il modo più semplice che ho trovato è la seguente:

# Expand right side of clipping rect to make room for the legend 
par(xpd=T, mar=par()$mar+c(0,0,0,6)) 

# Plot graph normally 
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2)) 
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o") 

# Plot legend where you want 
legend(3.2,1,c("group A", "group B"), pch = c(1,2), lty = c(1,2)) 

# Restore default clipping rect 
par(mar=c(5, 4, 4, 2) + 0.1) 

Trovato qui: http://www.harding.edu/fmccown/R/

+3

Ancora meglio è oldpar <- par (XPD = T, mar = par() $ mar + c (0,0,0,6)) ... par (oldpar) (vedere la guida di par) – rakensi

111

Nessuno ha menzionato utilizzando negativi inset valori per legend. Ecco un esempio, in cui la legenda è a destra del grafico, allineata in alto (utilizzando la parola chiave "topright").

# Random data to plot: 
A <- data.frame(x=rnorm(100, 20, 2), y=rnorm(100, 20, 2)) 
B <- data.frame(x=rnorm(100, 21, 1), y=rnorm(100, 21, 1)) 

# Add extra space to right of plot area; change clipping to figure 
par(mar=c(5.1, 4.1, 4.1, 8.1), xpd=TRUE) 

# Plot both groups 
plot(y ~ x, A, ylim=range(c(A$y, B$y)), xlim=range(c(A$x, B$x)), pch=1, 
       main="Scatter plot of two groups") 
points(y ~ x, B, pch=3) 

# Add legend to top right, outside plot region 
legend("topright", inset=c(-0.2,0), legend=c("A","B"), pch=c(1,3), title="Group") 

Il primo valore di inset=c(-0.2,0) possono necessitare di aggiustamenti in base alla larghezza della legenda.

legend_right

+0

davvero bello. e sembra funzionare senza 'xpd = TRUE'. – Henrik

+9

@ Henrik no non funziona senza xpd = TRUE. Si noti inoltre che è meglio impostare xpd = TRUE come argomento della funzione legend(). –

+0

A volte 'xpd' deve essere impostato su' TRUE' perché l'inserto negativo funzioni. Ma a volte no. Con il comando 'args.legend = list (x =" bottom ", horiz = TRUE, inset = -0.2) 'all'interno di un barplot (...' non sembra che sia necessario 'xpd = TRUE' ma con solo' legend (x = "bottom", horiz = TRUE, inset = -0.2) 'sembra ho bisogno di 'xpd = TRUE'. Qualsiasi intuizione? Sono solo confuso nel passare i miei argomenti? – user3386170

2

Si potrebbe fare questo con il Plotly R API, sia con il codice, o dalla GUI trascinando la leggenda dove si desidera.

Ecco un esempio. Il grafico e il codice sono anche here.

x = c(0,1,2,3,4,5,6,7,8) 
y = c(0,3,6,4,5,2,3,5,4) 
x2 = c(0,1,2,3,4,5,6,7,8) 
y2 = c(0,4,7,8,3,6,3,3,4) 

È possibile posizionare la legenda all'esterno del grafico assegnando uno dei valori xey a 100 o -100.

legendstyle = list("x"=100, "y"=1) 
layoutstyle = list(legend=legendstyle) 

Qui ci sono le altre opzioni:

  • list("x" = 100, "y" = 0) per esterno basso a destra
  • list("x" = 100, "y"= 1) esterno destro Top
  • list("x" = 100, "y" = .5) esterno destro Medio
  • list("x" = 0, "y" = -100) Sotto Sinistra
  • list("x" = 0.5, "y" = -100) Sotto Ce nter
  • list("x" = 1, "y" = -100) Sotto destro

Poi la risposta.

response = p$plotly(x,y,x2,y2, kwargs=list(layout=layoutstyle));

Plotly restituisce un URL con il grafico quando si effettua una chiamata. Puoi accedervi più rapidamente chiamando lo browseURL(response$url) in modo che apra il tuo grafico nel tuo browser.

url = response$url 
filename = response$filename 

Questo ci dà questo grafico. È inoltre possibile spostare la legenda all'interno della GUI e quindi il grafico si ridimensionerà di conseguenza. Full disclosure: Sono nella squadra di Plotly.

Legend on side of graph

21

Un'altra soluzione, oltre ai già citati ondes (usando layout o par(xpd=TRUE)) è quello di sovrapporre la trama con una trama trasparente sopra l'intero dispositivo e quindi aggiungere la leggenda a questo.

Il trucco consiste nel sovrapporre un grafico (vuoto) sopra l'area di disegno completa e aggiungere la legenda a questo. Possiamo usare l'opzione par(fig=...). In primo luogo insegniamo R per creare una nuova trama sull'intero dispositivo di stampa:

par(fig=c(0, 1, 0, 1), oma=c(0, 0, 0, 0), mar=c(0, 0, 0, 0), new=TRUE) 

impostazione è necessario oma e mar poiché vogliamo avere l'interno della trama copre l'intero dispositivo. new=TRUE è necessario per impedire a R di avviare un nuovo dispositivo. poi possiamo aggiungere la trama vuoto:

plot(0, 0, type='n', bty='n', xaxt='n', yaxt='n') 

E noi siamo pronti ad aggiungere la leggenda:

legend("bottomright", ...) 

aggiungerà una leggenda in basso a destra del dispositivo. Allo stesso modo, possiamo aggiungere la legenda al margine superiore o destro. L'unica cosa che dobbiamo assicurare è che il margine della trama originale sia abbastanza grande da contenere la leggenda.

Mettere tutto questo in una funzione;

add_legend <- function(...) { 
    opar <- par(fig=c(0, 1, 0, 1), oma=c(0, 0, 0, 0), 
    mar=c(0, 0, 0, 0), new=TRUE) 
    on.exit(par(opar)) 
    plot(0, 0, type='n', bty='n', xaxt='n', yaxt='n') 
    legend(...) 
} 

E un esempio.Innanzitutto creare la trama assicurandosi che abbiamo abbastanza spazio in basso per aggiungere la leggenda:

par(mar = c(5, 4, 1.4, 0.2)) 
plot(rnorm(50), rnorm(50), col=c("steelblue", "indianred"), pch=20) 

quindi aggiungere la leggenda

add_legend("topright", legend=c("Foo", "Bar"), pch=20, 
    col=c("steelblue", "indianred"), 
    horiz=TRUE, bty='n', cex=0.8) 

Con conseguente:

Example figure shown legend in top margin

+2

Grande aggiunta all'elenco qui. C'è una spiegazione su come fare questo lavoro con più trame nel grafico [qui] (http: // dr-k-lo.blogspot.com/2014/03/the-simplest-way-to-plot-legend-outside.html). – shiri

+0

Il trucco migliore! Funziona pulito! – Facottons

+0

Jan, c'è un modo per aumentare il font dimensione nella legenda, senza che alcuni testi vengano ritagliati Ad esempio, ho un grafico di 4 diversi tipi di etichette, ma con molto spazio vuoto tra di loro –

7

Recentemente ho trovato la funzione molto facile e interessante per stampare legenda al di fuori dell'area del tracciato in cui si desidera.

Rendere il margine esterno sul lato destro della trama.

par(xpd=T, mar=par()$mar+c(0,0,0,5)) 

creare un grafico

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2)) 
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o") 

Add leggenda e basta usare locator (1) funzione come qui di seguito. Quindi devi solo cliccare dove vuoi dopo aver caricato lo script seguente.

legend(locator(1),c("group A", "group B"), pch = c(1,2), lty = c(1,2)) 

Provalo

11

mi piace fare in questo modo:

par(oma=c(0, 0, 0, 5)) 
plot(1:3, rnorm(3), pch=1, lty=1, type="o", ylim=c(-2,2)) 
lines(1:3, rnorm(3), pch=2, lty=2, type="o") 
legend(par('usr')[2], par('usr')[4], bty='n', xpd=NA, 
     c("group A", "group B"), pch=c(1, 2), lty=c(1,2)) 

enter image description here

L'unico ritocco richiesto è nella impostazione del margine destro ad essere sufficientemente ampia per accogliere il leggenda.

Tuttavia, questo può anche essere automatizzato:

dev.off() # to reset the graphics pars to defaults 
par(mar=c(par('mar')[1:3], 0)) # optional, removes extraneous right inner margin space 
plot.new() 
l <- legend(0, 0, bty='n', c("group A", "group B"), 
      plot=FALSE, pch=c(1, 2), lty=c(1, 2)) 
# calculate right margin width in ndc 
w <- grconvertX(l$rect$w, to='ndc') - grconvertX(0, to='ndc') 
par(omd=c(0, 1-w, 0, 1)) 
plot(1:3, rnorm(3), pch=1, lty=1, type="o", ylim=c(-2, 2)) 
lines(1:3, rnorm(3), pch=2, lty=2, type="o") 
legend(par('usr')[2], par('usr')[4], bty='n', xpd=NA, 
     c("group A", "group B"), pch=c(1, 2), lty=c(1, 2)) 

enter image description here

+0

Utilizzo di xpd = T o xpd = NA doesn ' t prevenire il mio 'principale' (t itle) dall'essere ritagliato quando viene allungato per provare a utilizzare l'area aggiunta con l'ampio margine destro. –

+0

@PhilGoetz sei sicuro di aver pianificato la parte principale all'interno dell'area della trama? È possibile che non ci siano abbastanza linee di margine da tracciare? – jbaums

Problemi correlati