Colocação de etiqueta de ponto inteligente em R


102

1) Existe alguma biblioteca / função R que implementaria a colocação INTELIGENTE de rótulo no gráfico R? Tentei alguns, mas todos são problemáticos - muitos rótulos estão se sobrepondo uns aos outros ou a outros pontos (ou outros objetos no gráfico, mas vejo que isso é muito mais difícil de manusear).

2) Se não, há alguma maneira de ajudar CONFORTÁVELMENTE o algoritmo com a colocação de rótulos para pontos problemáticos particulares? A solução mais confortável e eficiente desejada.

Você pode jogar e testar outras possibilidades com meu exemplo reproduzível e ver se consegue obter resultados melhores do que eu:

# data
x = c(0.8846, 1.1554, 0.9317, 0.9703, 0.9053, 0.9454, 1.0146, 0.9012, 
0.9055, 1.3307)
y = c(0.9828, 1.0329, 0.931, 1.3794, 0.9273, 0.9605, 1.0259, 0.9542, 
0.9717, 0.9357)
ShortSci = c("MotAlb", "PruMod", "EriRub", "LusMeg", "PhoOch", "PhoPho", 
"SaxRub", "TurMer", "TurPil", "TurPhi")

# basic plot
plot(x, y, asp=1)
abline(h = 1, col = "green")
abline(v = 1, col = "green")

Para rotular, tentei essas possibilidades, ninguém é realmente bom:

1) este é terrível:

text(x, y, labels = ShortSci, cex= 0.7, offset = 10)

2) este é bom se você não quiser colocar rótulos para todos os pontos, mas apenas para os outliers, mas ainda assim, os rótulos costumam ser colocados errados:

identify(x, y, labels = ShortSci, cex = 0.7)

3) este parecia promissor, mas existe o problema dos rótulos estarem muito próximos dos pontos; Tive que preenchê-los com espaços, mas isso não ajuda muito:

require(maptools)
pointLabel(x, y, labels = paste("  ", ShortSci, "  ", sep=""), cex=0.7)

4)

require(plotrix)
thigmophobe.labels(x, y, labels = ShortSci, cex=0.7, offset=0.5)

5)

require(calibrate)
textxy(x, y, labs=ShortSci, cx=0.7)

Agradeço antecipadamente!

EDIT: todo: tente labcurve {Hmisc} .


2
As respostas às perguntas R parecem, infelizmente, estar igualmente divididas entre StackOverflow e CrossValidated. Nesse caso, a pergunta é uma duplicata de uma de 4 dias atrás ali .
Ed Staub

3
Encontrei um problema semelhante e escrevi um pacote básico que usa simulação de campo de força para ajustar a localização do objeto. Embora muitas melhorias sejam possíveis, incluindo integração com ggplot, etc., parece que a tarefa é cumprida. O seguinte ilustra a funcionalidade. Se alguém se deparar com o problema e procurar uma resposta, espero que isso seja de alguma ajuda:install.packages("FField") library(FField) FFieldPtRepDemo()
gregk

Posso pedir que experimente o ggrepel ?
Kamil Slowikowski

querido @Joran, por favor, coloque seu comentário "6) Para gráficos ggplot2, há uma opção mais recente chamada ggrepel que muitas pessoas parecem gostar." em um comentário ou resposta. Aqui eu incluí apenas a lista de opções que tentei, mas não são satisfatórias . Se for algo que funciona bem, deve ser uma resposta.
TMS

Respostas:


49

Primeiro, aqui estão os resultados da minha solução para este problema:

insira a descrição da imagem aqui

Fiz isso manualmente no Preview (PDF / visualizador de imagens muito básico no OS X) em apenas alguns minutos. ( Editar: o fluxo de trabalho foi exatamente o que você esperava: salvei o gráfico como um PDF do R, abri na visualização e criei caixas de texto com os rótulos desejados (9pt Helvetica) e, em seguida, apenas arrastei-os com meu mouse até que parecessem bom. Em seguida, exportei para um PNG para enviar para o SO.)

Agora, antes de você sucumbir ao forte desejo de votar isso no esquecimento e deixar comentários sarcásticos sobre como o objetivo é automatizar esse processo, ouça-me!

Procurar soluções algorítmicas é totalmente aceitável e (IMHO) realmente interessante. Mas, para mim, as situações de rotulagem apontam para cerca de três categorias:

  1. Você tem um pequeno número de pontos, nenhum que esteja terrivelmente próximo um do outro . Nesse caso, uma das soluções listadas na questão provavelmente funcionará com ajustes mínimos.
  2. Você tem um pequeno número de pontos, alguns dos quais muito compactados para que as soluções algorítmicas típicas forneçam bons resultados . Neste caso, uma vez que você só tem um pequeno número de pontos, rotulando-os com a mão (ou com um editor de imagens ou afinar a sua chamada para text) não é que muito esforço.
  3. Você tem um número bastante grande de pontos . Nesse caso, você realmente não deveria rotulá-los de qualquer maneira, pois é difícil processar um grande número de rótulos visualmente.

: subindo na caixa de sabão:

Já que gente como nós ama a automação, acho que muitas vezes caímos na armadilha de pensar que quase todos os aspectos da produção de um bom gráfico estatístico devem ser automatizados. Eu respeitosamente (humildemente!) Discordo.

Não existe um ambiente de plotagem estatístico perfeitamente geral que crie automaticamente a imagem que você tem em sua cabeça. Coisas como R, ggplot2, lattice etc. fazem a maior parte do trabalho; mas aquele pequeno ajuste extra, adicionar uma linha aqui, ajustar uma margem ali, provavelmente é mais adequado para uma ferramenta diferente.

: descendo da caixa de sabão:

Eu também observaria que acho que todos nós poderíamos chegar a gráficos de dispersão com <10-15 pontos que seriam quase impossíveis de rotular de forma limpa, mesmo à mão, e isso provavelmente quebrará qualquer solução automática que alguém venha com.

Por fim, quero reiterar que sei que essa não é a resposta que você está procurando. E eu estou não dizer que as tentativas de algoritmos são inúteis ou mudo. Votei nesta questão e ficarei feliz em votar em soluções algorítmicas interessantes!

A razão pela qual postei esta resposta é que acho que essa pergunta deveria ser a pergunta canônica de "marcação pontual em R" para futuras duplicatas, e acho que as soluções que envolvem marcação manual merecem um lugar à mesa, só isso.


10
Outra maneira manual é salvar o gráfico como um SVG e editá-lo usando o Inkscape e, em seguida, produzir PDF a partir dele.
Spacedman

Oi joran, obrigado pela sua resposta. OK, eu aceito esta solução, embora eu ache que o computador deveria fazer isso melhor primeiro E DEPOIS solicitar intervenção manual. Procuro aqui a solução mais confortável e rápida. Você poderia descrever como construiu o enredo, passo a passo? O que você gerou em R, exportou, movendo os rótulos no Preview, etc.?
TMS

1
@TomasT. Ah eu vejo. Nesse caso, eu "trapaceei", mais ou menos. Eu gerei um pdf com etiquetas usando um de seus métodos acima e um sem e usei aquele com etiquetas como um guia.
joran

1
+1 Esta é uma ótima resposta. Alguma explicação do porquê aparece no meta-CV : veja os comentários lá.
whuber

1
Mover um pequeno conjunto de etiquetas manualmente parece sensato, mas você também pode criá-las automaticamente primeiro e depois movê-las. Dessa forma, você está economizando muito trabalho e também reduzindo a probabilidade de rotulagem incorreta ...
naught101

42

ggrepelparece promissor quando aplicado a ggplot2gráficos de dispersão.

# data
x = c(0.8846, 1.1554, 0.9317, 0.9703, 0.9053, 0.9454, 1.0146, 0.9012, 
0.9055, 1.3307)
y = c(0.9828, 1.0329, 0.931, 1.3794, 0.9273, 0.9605, 1.0259, 0.9542, 
0.9717, 0.9357)
ShortSci = c("MotAlb", "PruMod", "EriRub", "LusMeg", "PhoOch", "PhoPho", 
"SaxRub", "TurMer", "TurPil", "TurPhi")


df <- data.frame(x = x, y = y, z = ShortSci)
library(ggplot2)
library(ggrepel)

ggplot(data = df, aes(x = x, y = y)) + theme_bw() + 

    geom_text_repel(aes(label = z), 
       box.padding = unit(0.45, "lines")) +

    geom_point(colour = "green", size = 3)

insira a descrição da imagem aqui


10

Você já experimentou o pacote directlabels ?

E, BTW, os argumentos pos e offset podem usar vetores para permitir que você os coloque nas posições corretas quando houver um número razoável de pontos em apenas algumas execuções do gráfico.


O pacote directlabels pode ser usado com plot()plot normal ? Não tive sucesso tentando então ... Obrigado! PS: @SpacedMan & Ben, limpei meus comentários sobre a atualização do R, uma vez que eles não são muito interessantes - você pode fazer o mesmo.
TMS

6

Encontrei alguma solução! Não é definitivo e ideal, infelizmente, mas é o que funciona melhor para mim agora. É meio algoritmico, meio manual, então economiza tempo em comparação com a solução manual pura esboçada por joran.

Esqueci uma parte muito importante da ?identifyajuda!

O algoritmo usado para colocar rótulos é o mesmo usado pelo texto se pos for especificado lá, a diferença é que a posição do ponteiro em relação ao ponto identificado determina a pos na identificação.

Então, se você usar a identify()solução como eu escrevi na minha pergunta, você pode afetar a posição do rótulo não clicando diretamente naquele ponto, mas clicando próximo a esse ponto relativamente na direção desejada !!! Funciona muito bem!

A desvantagem é que existem apenas 4 posições (superior, esquerda, inferior, direita), mas eu gostaria mais das outras 4 (superior esquerdo, superior direito, inferior esquerdo, inferior direito) ... Então, eu uso isso para rotular pontos onde não me incomoda e o resto dos pontos eu rotulo diretamente na minha apresentação em PowerPoint, conforme proposto por joran :-)

PS: Eu ainda não experimentei a solução directlabels lattice / ggplot, ainda prefiro usar a biblioteca de plotagem básica.


4

Eu sugiro que você dê uma olhada no wordcloudpacote. Eu sei que este pacote foca não exatamente nos pontos, mas nos rótulos em si, e também o estilo parece ser bastante fixo. Mesmo assim, os resultados que obtive ao usá-lo foram impressionantes. Observe também que a versão do pacote em questão foi lançada na época em que você fez a pergunta, portanto, ainda é muito nova.

http://blog.fellstat.com/?cat=11


3

Eu escrevi uma função R chamada addTextLabels()dentro de um pacoteplotteR . O pacote pode ser instalado diretamente em sua biblioteca R usando o seguinte código:

install.packages("devtools")
library("devtools")
install_github("JosephCrispell/basicPlotteR")

Para o exemplo fornecido, usei o código a seguir para gerar a figura de exemplo com link abaixo.

# Load the plotteR library
library(plotteR)

# Create vectors storing the X and Y coordinates
x = c(0.8846, 1.1554, 0.9317, 0.9703, 0.9053, 0.9454, 1.0146, 0.9012, 
      0.9055, 1.3307)
y = c(0.9828, 1.0329, 0.931, 1.3794, 0.9273, 0.9605, 1.0259, 0.9542, 
      0.9717, 0.9357)

# Store the labels to be plotted in a vector
ShortSci = c("MotAlb", "PruMod", "EriRub", "LusMeg", "PhoOch", "PhoPho", 
             "SaxRub", "TurMer", "TurPil", "TurPhi")

# Plot the X and Y coordinates without labels
plot(x, y, asp=1)
abline(h = 1, col = "green")
abline(v = 1, col = "green")

# Add non-overlapping text labels
addTextLabels(x, y, ShortSci, cex=0.9, col.background=rgb(0,0,0, 0.75), 
              col.label="white")

Funciona selecionando automaticamente um local alternativo em uma grade fina de pontos. Os pontos mais próximos na grade são visitados primeiro e selecionados se não se sobrepõem a nenhum ponto ou rótulo traçado. Dê uma olhada no código- fonte , se você estiver interessado.

Figura Exemplo


2

Não é uma resposta, mas muito tempo para um comentário. Uma abordagem muito simples que pode funcionar em casos simples, em algum lugar entre o pós-processamento de in-placeJoran e os algoritmos mais sofisticados que foram apresentados, é fazer transformações simples no dataframe.

Ilustro isso com ggplot2porque estou mais familiarizado com essa sintaxe do que gráficos R de base.

df <- data.frame(x = x, y = y, z = ShortSci)
library("ggplot2")
ggplot(data = df, aes(x = x, y = y, label = z)) + theme_bw() + 
    geom_point(shape = 1, colour = "green", size = 5) + 
    geom_text(data = within(df, c(y <- y+.01, x <- x-.01)), hjust = 0, vjust = 0)

Como você pode ver, neste caso o resultado não é ideal, mas pode ser bom o suficiente para alguns propósitos. E é muito fácil, normalmente algo assim é suficientewithin(df, y <- y+.01)

insira a descrição da imagem aqui


2
Em vez de modificar o dfuso within, geralmente faço isso ajustando a estética: geom_text(aes(x = x - .01, y = y + .01), hjust = 0, vjust = 0)parece mais limpo.
Gregor Thomas
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.