Интеллектуальное размещение меток точек в R

102

1) Есть ли какая-либо библиотека / функция R, которая будет реализовывать размещение меток INTELLIGENT на графике R? Я пробовал некоторые, но все они проблематичны - многие метки перекрывают друг друга или другие точки (или другие объекты на графике, но я вижу, что с этим намного труднее справиться).

2) Если нет, есть ли способ УДОБНО помочь алгоритму с размещением меток для определенных проблемных точек? Требуется максимально удобное и эффективное решение.

Вы можете поиграть и протестировать другие возможности на моем воспроизводимом примере и посмотреть, сможете ли вы добиться лучших результатов, чем я:

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

Для маркировки я затем попробовал эти возможности, никто не особо хорош:

1) это ужасно:

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

2) этот хорош, если вы не хотите ставить метки для всех точек, а только для выбросов, но все же метки часто размещаются неправильно:

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

3) этот выглядел многообещающе, но есть проблема с ярлыками, которые слишком близко расположены к точкам; Мне пришлось заполнить их пробелами, но это мало помогает:

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)

Заранее спасибо!

РЕДАКТИРОВАТЬ : задача : попробуйте labcurve {Hmisc} .

ТМС
источник
2
К сожалению, ответы на вопросы R равномерно разделены между StackOverflow и CrossValidated. В данном случае это дубликат вопроса, полученного 4 дня назад .
Эд Стауб
3
Я столкнулся с аналогичной проблемой и написал базовый пакет, который использует симуляцию силового поля для настройки местоположения объекта. Хотя возможно значительное улучшение, включая интеграцию с ggplot и т. Д., Похоже, что задача решена. Ниже показаны функциональные возможности. Если кто-то столкнется с проблемой и install.packages("FField") library(FField) FFieldPtRepDemo()
попытается найти
Могу я попросить вас попробовать ggrepel ?
Камил Словиковски
дорогой @Joran, пожалуйста, оставьте свой комментарий: «6) Для графиков ggplot2 есть новая опция под названием ggrepel, которая, кажется, нравится многим». в комментарии или ответе. Здесь я только включил список опций, которые я пробовал, но они меня не устраивают . Если что-то работает хорошо, то это должно быть в ответе.
TMS

Ответы:

49

Во-первых, вот результаты моего решения этой проблемы:

введите описание изображения здесь

Я сделал это вручную в Preview (очень простая программа просмотра PDF / изображений в OS X) всего за несколько минут. ( Изменить: рабочий процесс был именно таким, как вы ожидали: я сохранил график как PDF-файл из R, открыл его в предварительном просмотре и создал текстовые поля с желаемыми метками (9pt Helvetica), а затем просто перетащил их с помощью мыши, пока они не посмотрели хорошо. Затем я экспортировал в PNG для загрузки в SO.)

Теперь, прежде чем вы поддадитесь сильному побуждению проголосовать за это до забвения и оставить язвительные комментарии о том, как автоматизировать этот процесс, выслушайте меня!

Искать алгоритмические решения - это нормально и (ИМХО) действительно интересно. Но для меня ситуации с маркировкой точек можно разделить примерно на три категории:

  1. У вас есть небольшое количество точек, ни одна из которых не находится близко друг к другу . В этом случае одно из решений, которые вы указали в вопросе, вероятно, будет работать с минимальной настройкой.
  2. У вас есть небольшое количество точек, некоторые из которых слишком тесно упакованы, чтобы типичные алгоритмические решения давали хорошие результаты . В этом случае, так как у вас есть только небольшое количество точек, маркируя их вручную (либо с помощью редактора изображений или тонкой настройки вашего вызова text) не являются , что много усилий.
  3. У вас достаточно большое количество очков . В этом случае вам все равно не стоит их маркировать, так как визуально обработать большое количество этикеток сложно.

: забраться на мыльницу:

Поскольку такие люди, как мы, любят автоматизацию, я думаю, что мы часто попадаем в ловушку, полагая, что почти каждый аспект создания хорошей статистической графики должен быть автоматизирован. Я уважительно (скромно!) Не согласен.

Не существует совершенно общей среды статистического построения графиков, которая автоматически создает картину, которая у вас в голове. Такие вещи, как R, ggplot2, lattice и т. Д., Делают большую часть работы; но эта дополнительная небольшая настройка, добавление линии здесь, настройка поля там, вероятно, лучше подходит для другого инструмента.

: слезая из мыльницы:

Я также хотел бы отметить, что я думаю, что мы все могли бы придумать диаграммы рассеяния с <10-15 точками, которые будет почти невозможно точно пометить даже вручную, и они, вероятно, сломают любое автоматическое решение, которое кто-то придумает.

Наконец, я хочу повторить, что знаю, что это не тот ответ, который вы ищете. И я не говорю, что алгоритмические попытки бесполезны или тупы. Я проголосовал за этот вопрос и с радостью проголосую за интересные алгоритмические решения!

Причина, по которой я опубликовал этот ответ, заключается в том, что я думаю, что этот вопрос должен быть каноническим вопросом о «маркировке точек в R» для будущих дубликатов, и я думаю, что решения, связанные с ручной маркировкой, заслуживают места за столом, вот и все.

Joran
источник
10
Другой способ вручную - сохранить график как SVG и отредактировать его с помощью Inkscape, а затем создать из него PDF.
Spacedman
Привет, Джоран, спасибо за ответ. Хорошо, я принимаю это решение, хотя я думаю, что компьютер должен сначала сделать это лучше всего, А ЗАТЕМ запросить ручное вмешательство. Здесь ищу наиболее удобное и быстрое решение. Не могли бы вы описать шаг за шагом, как вы делали сюжет? Что вы создали в R, экспорт, перемещение меток в предварительном просмотре и т. Д.?
TMS
1
@TomasT. О, я вижу. В этом случае я вроде как "обманул". Я создал один PDF-файл с метками, используя один из описанных выше методов, а другой - без, и использовал тот, который с метками, в качестве руководства.
Joran
1
+1 Это отличный ответ. Некоторое объяснение того, почему появляется в мета-резюме : см. Комментарии там.
whuber
1
Перемещение небольшого набора этикеток вручную кажется разумным, но вы также можете сначала создать их автоматически , а затем переместить. Таким образом вы сэкономите много работы, а также уменьшите вероятность неправильной маркировки ...
naught101
42

ggrepelвыглядит многообещающим в применении к ggplot2диаграммам рассеяния.

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

введите описание изображения здесь

Сэнди Маспратт
источник
10

Вы пробовали пакет directlabels ?

И, кстати, аргументы pos и offset могут принимать векторы, чтобы вы могли разместить их в правильных положениях, когда есть разумное количество точек всего за несколько прогонов графика.

Джон
источник
Можно ли использовать пакет directlabels с обычным графиком plot()? У меня не получилось, поэтому ... Спасибо! PS: @SpacedMan & Ben, я убрал свои комментарии по поводу обновления R, так как они не так интересны - вы можете сделать то же самое.
TMS
6

Я нашел какое-то решение! К сожалению, он не идеален и не идеален, но сейчас мне больше всего подходит. Это наполовину алгоритм, наполовину ручной, поэтому он экономит время по сравнению с чисто ручным решением, предложенным Джораном.

Я упустил из виду очень важную часть ?identifyпомощи!

Алгоритм, используемый для размещения меток, тот же, что и для текста, если там указано pos, с той разницей, что положение указателя относительно идентифицированной точки определяет pos в identify.

Поэтому, если вы используете identify()решение, как я написал в своем вопросе, вы можете повлиять на положение метки, не щелкая непосредственно в этой точке, а щелкая рядом с этой точкой относительно в желаемом направлении !!! Работает просто отлично!

Обратной стороной является то, что есть только 4 позиции (верхняя, левая, нижняя, правая), но я бы больше ценил другие 4 (верхняя левая, верхняя правая, нижняя левая, нижняя правая) ... Итак, я используйте это для обозначения точек, где это меня не беспокоит, и остальных точек, которые я помечаю непосредственно в своей презентации Powerpoint, как предложил Джоран :-)

PS: Я еще не пробовал решение directlabels lattice / ggplot, я все еще предпочитаю использовать базовую библиотеку графиков.

ТМС
источник
4

Предлагаю вам взглянуть на wordcloudпосылку. Я знаю, что этот пакет фокусируется не на точках, а на самих этикетках, а также стиль кажется довольно фиксированным. Но все же результаты, которые я получил от его использования, были довольно ошеломляющими. Также обратите внимание, что рассматриваемая версия пакета была выпущена примерно в то время, когда вы задали вопрос, поэтому она все еще очень новая.

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

майор
источник
3

Я написал функцию R, вызываемую addTextLabels()внутри пакета basicPlotteR. Пакет можно напрямую установить в вашу библиотеку R, используя следующий код:

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

В представленном примере я использовал следующий код для создания приведенного ниже примера рисунка.

# Load the basicPlotteR library
library(basicPlotteR)

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

Он работает, автоматически выбирая альтернативное местоположение из точной сетки точек. Ближайшие точки сетки просматриваются первыми и выбираются, если они не перекрываются с нанесенными точками или метками. Если вам интересно, посмотрите исходный код .

Пример рисунка

Джозеф Криспелл
источник
2

Не ответ, но слишком длинный для комментария. Очень простой подход, который может работать с простыми случаями, где-то между пост-обработкой Джорана и более сложными алгоритмами, которые были представлены, - это выполнение in-placeпростых преобразований в фрейм данных.

Я проиллюстрирую это, ggplot2потому что я более знаком с этим синтаксисом, чем с базовыми графиками R.

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)

Как видите, в данном случае результат не идеален, но для некоторых целей его может хватить. И это довольно легко, обычно достаточно чего-то подобного.within(df, y <- y+.01)

введите описание изображения здесь

PatrickT
источник
2
Вместо того, чтобы изменять dfиспользование within, я часто делаю это, корректируя эстетику: geom_text(aes(x = x - .01, y = y + .01), hjust = 0, vjust = 0)кажется чище.
Грегор Томас