Traçar uma legenda fora da área de plotagem nos gráficos de base?


185

Como o título diz: Como plotar uma legenda fora da área de plotagem ao usar gráficos de base?

Pensei em mexer layoute produzir uma trama vazia para conter apenas a legenda, mas eu estaria interessado de alguma maneira usando apenas as instalações básicas do gráfico e, por exemplo, par(mar = )para obter algum espaço à direita da trama para a legenda.


Aqui está um exemplo:

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

produz:

texto alternativo

Mas como dito, eu gostaria que a legenda estivesse fora da área de plotagem (por exemplo, à direita do gráfico / plotagem).


... você também pode hackear o par com o recipiente fictício da lenda, de tempos em tempos fácil e bastante conveniente. Pergunta semelhante aqui .
hhh

3
@hhh O link não está mais funcionando. Você pode atualizá-lo ou postar uma resposta usando essa abordagem?
Henrik

Respostas:


111

Talvez o que você precise é par(xpd=TRUE)permitir que as coisas sejam desenhadas fora da região da trama. Então, se você fizer o enredo principal, bty='L'terá algum espaço à direita para uma lenda. Normalmente, isso seria cortado na região da plotagem, mas, par(xpd=TRUE)com um pouco de ajuste, você pode obter uma legenda o mais correta possível:

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

33
Observe que você pode passar o xpd diretamente para a legenda para não precisar se preocupar em redefinir o par posteriormente. Veja também grconvertX & Y para obter uma maneira de especificar a localização da legenda de uma maneira que não dependa dos limites dos dados que você está plotando.
Charles

6
como essa pergunta e resposta ainda são muito populares, par(xpd=NA)é ainda mais poderosa (ou seja, parcelas para mais regiões).
Henrik

+1. Devemos mencionar que faz sentido ter uma parchamada separada logo antes da legenda. No meu enredo, usei par(new=T)em várias outras ocasiões e simplesmente queria adicionar o xpdparâmetro na mesma chamada, o que causa problemas.
Matt Bannert

146

Ninguém mencionou o uso de insetvalores negativos para legend. Aqui está um exemplo, onde a legenda está à direita do gráfico, alinhada ao topo (usando a palavra-chave "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")

O primeiro valor de inset=c(-0.2,0)talvez precise ser ajustado com base na largura da legenda.

legend_right


14
@ Henrik não, ele não funciona sem xpd = TRUE. Observe também que é melhor definir xpd = TRUE como um argumento da função legend ().
Stéphane Laurent

1
Às vezes, xpddeve ser definido como TRUEpara que a inserção negativa funcione. Mas às vezes não. Com o comando args.legend=list(x="bottom", horiz=TRUE, inset=-0.2)dentro de um barplot(..., não parece precisar, xpd=TRUEmas apenas com legend(x="bottom", horiz=TRUE, inset=-0.2)o que parece xpd=TRUE. Alguma ideia? Estou apenas confuso em passar meus argumentos?
precisa saber é o seguinte

28

Outra solução, além dos ondes já mencionados (usando layoutoupar(xpd=TRUE) ), é sobrepor sua plotagem com uma plotagem transparente sobre todo o dispositivo e adicionar a legenda a isso.

O truque é sobrepor um gráfico (vazio) sobre a área de plotagem completa e adicionar a legenda a isso. Nós podemos usar a par(fig=...)opção Primeiro, instruímos R para criar um novo gráfico em todo o dispositivo de plotagem:

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

É necessário definir omae maré necessário, pois queremos que o interior da trama cubra todo o dispositivo. new=TRUEé necessário para impedir que o R inicie um novo dispositivo. Podemos então adicionar o gráfico vazio:

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

E estamos prontos para adicionar a legenda:

legend("bottomright", ...)

adicionará uma legenda no canto inferior direito do dispositivo. Da mesma forma, podemos adicionar a legenda à margem superior ou direita. A única coisa que precisamos garantir é que a margem da trama original seja grande o suficiente para acomodar a legenda.

Colocando tudo isso em uma função;

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 um exemplo Primeiro, crie o gráfico, certificando-se de que temos espaço suficiente na parte inferior para adicionar a legenda:

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

Em seguida, adicione a legenda

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

Resultando em:

Figura de exemplo mostrada legenda na margem superior


2
Ótimo complemento para a lista aqui. Há uma explicação sobre como fazer isso funcionar com vários gráficos no gráfico aqui .
shiri

Jan, existe uma maneira de aumentar o tamanho da fonte na legenda, sem que algum texto seja cortado? Por exemplo, eu tenho um gráfico 4 tipos diferentes de etiquetas, mas com muito espaço vazio entre elas.
Um velho no mar.

Escrevi uma pergunta com mais detalhes stackoverflow.com/questions/42707308/…
Um velho no mar.

16

Desculpe por ressuscitar um thread antigo, mas eu estava com o mesmo problema hoje. A maneira mais simples que encontrei é a seguinte:

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

Encontrado aqui: http://www.harding.edu/fmccown/R/


4
Ainda melhor é oldpar <- par (xpd = T, mar = par () $ mar + c (0,0,0,6)) ... par (oldpar) (Veja a ajuda do par)
rakensi

Esta solução é melhor porque o espaço para a legenda é fixo não importa o comprimento das cordas da lenda
Sergio

15

Eu gosto de fazer assim:

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

insira a descrição da imagem aqui

O único ajuste necessário é definir a margem certa para ser larga o suficiente para acomodar a legenda.

No entanto, isso também pode ser automatizado:

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

insira a descrição da imagem aqui


Usar xpd = T ou xpd = NA não impede que meu 'main' (título) seja cortado quando esticado para tentar usar a área adicionada com a ampla margem direita.
27516 Phil

@PhilGoetz, você tem certeza de que está tramando o principal na área de plotagem? É possível que você não tenha linhas de margem suficientes para plotar?
Jbaums

10

Recentemente, achei uma função muito fácil e interessante para imprimir legendas fora da área de plotagem onde você deseja.

Faça a margem externa no lado direito da plotagem.

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

Crie uma plotagem

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

Adicione legenda e use a função localizador (1) como abaixo. Depois, basta clicar no local desejado após o carregamento, seguindo o script.

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

Tente


9

Eu posso oferecer apenas um exemplo da solução de layout já apontada.

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

uma imagem feia: S


9

Adicionando outra alternativa simples que é bastante elegante na minha opinião.

Seu enredo:

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

Lenda:

legend("bottomright", c("group A", "group B"), pch=c(1,2), lty=c(1,2),
       inset=c(0,1), xpd=TRUE, horiz=TRUE, bty="n"
       )

Resultado:

imagem com legenda

Aqui, apenas a segunda linha da legenda foi adicionada ao seu exemplo. Por sua vez:

  • inset=c(0,1)- move a legenda por fração da região da plotagem nas direções (x, y). Nesse caso, a legenda está em"bottomright" posição. Ele é movido por 0 regiões de plotagem na direção x (portanto permanece na "direita") e por 1 região de plotagem na direção y (de baixo para cima). E acontece que aparece logo acima da trama.
  • xpd=TRUE - vamos aparecer a legenda fora da região de plotagem.
  • horiz=TRUE - instrui a produzir uma legenda horizontal.
  • bty="n" - um detalhe de estilo para se livrar da caixa delimitadora da legenda.

O mesmo se aplica ao adicionar legenda ao lado:

par(mar=c(5,4,2,6))
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("topleft", c("group A", "group B"), pch=c(1,2), lty=c(1,2),
       inset=c(1,0), xpd=TRUE, bty="n"
       )

Aqui, simplesmente ajustamos as posições das legendas e adicionamos espaço de margem adicional ao lado direito do gráfico. Resultado:

foto com legenda 2


4

Você poderia fazer isso com a API Plotly R , com o código ou com a GUI arrastando a legenda para onde desejar.

Aqui está um exemplo. O gráfico e o código também estão aqui .

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)

Você pode posicionar a legenda fora do gráfico, atribuindo um dos valores xey para 100 ou -100.

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

Aqui estão as outras opções:

  • list("x" = 100, "y" = 0) para parte inferior direita exterior
  • list("x" = 100, "y"= 1) Parte superior direita do lado de fora
  • list("x" = 100, "y" = .5) Fora Direito Médio
  • list("x" = 0, "y" = -100) Sob Esquerda
  • list("x" = 0.5, "y" = -100) Abaixo do centro
  • list("x" = 1, "y" = -100) Sob Direito

Então a resposta.

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

Plotly retorna um URL com seu gráfico quando você faz uma chamada. Você pode acessá-lo mais rapidamente ligando browseURL(response$url)para que ele abra seu gráfico no seu navegador.

url = response$url
filename = response$filename

Isso nos dá esse gráfico. Você também pode mover a legenda de dentro da GUI e, em seguida, o gráfico será dimensionado de acordo. Divulgação completa: estou na equipe Plotly.

Legenda no lado do gráfico


2

Experimente o layout()que eu usei para isso no passado, simplesmente criando um gráfico vazio abaixo, dimensionado adequadamente em cerca de 1/4 ou mais e colocando as partes da legenda manualmente nele.

Existem algumas perguntas mais antigas sobre legend()quais devem começar.


Como já foi dito na pergunta, também pensei nisso. Mas seria ideal, se houvesse outro caminho. De alguma forma, suponho que não há.
21910 Henrik
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.