R ggmap, перерисовка, точки перекрывают друг друга

У меня проблема с перерисовкой.

Ситуация выглядит так: у меня есть некоторые данные с координатами и разными названиями мест, некоторые места находятся в одной сборке - поэтому у меня есть одинаковые координаты для нескольких названий мест. Как сделать так, чтобы они не перекрывали друг друга? Я пробовал с разными формами, лучшим вариантом было бы разбросать эти точки или, может быть, нарисовать одну точку несколькими цветами? Но я понятия не имею, как это сделать. Я буду признателен за любую помощь.

Пример кода:

require(rgdal)
require(ggmap)
require(maptools)
require (plyr)

swd <- structure(list(nazwa = structure(c(8L, 8L, 9L, 7L, 7L, 7L, 3L, 
                                   5L, 6L, 4L, 2L, 2L, 1L), .Label = c("ODDZIAŁ CHIRURGII ONKOLOGICZNEJ", 
                                                                       "ODDZIAŁ GINEKOLOGII ONKOLOGICZNEJ", "ODDZIAŁ ONKOLOGICZNY", 
                                                                       "ODDZIAŁ ONKOLOGII I HEMATOLOGII DZIECIĘCEJ", "ODDZIAŁ ONKOLOGII KLINICZNEJ CHEMIOTERAPII", 
                                                                       "ODDZIAŁ RADIOTERAPII", "PORADNIA CHIRURGII ONKOLOGICZNEJ", "PORADNIA ONKOLOGICZNA", 
                                                                       "PORADNIA RADIOTERAPII"), class = "factor"), miasto = structure(c(8L, 
                                                                                                                                         8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L), .Label = c("DZIAŁDOWO", 
                                                                                                                                                                                                     "ELBLĄG", "EŁK", "GIŻYCKO", "MRĄGOWO", "NOWE MIASTO LUBAWSKIE", 
                                                                                                                                                                                                     "OLECKO", "OLSZTYN", "OSTRÓDA", "PISZ", "SZCZYTNO"), class = "factor"), 
               dom = structure(c(17L, 5L, 17L, 17L, 8L, 18L, 5L, 17L, 17L, 
                                 20L, 17L, 19L, 17L), .Label = c("BARANKI 24", "GNIEŹNIEŃSKA 2", 
                                                                 "GOŁDAPSKA 1", "HENRYKA SIENKIEWICZA 4", "JAGIELLOŃSKA 78", 
                                                                 "JANA III SOBIESKIEGO 3 C/44", "KONOPNICKIEJ 1", "KOPERNIKA 30", 
                                                                 "KOŚCIUSZKI 30", "KRÓLEWIECKA 146", "KRÓLEWIECKA 146 146", 
                                                                 "LEŚNA 1", "MICKIEWICZA 10", "MICKIEWICZA 14", "OSEDLE MAZURSKIE 33 A", 
                                                                 "WARSZAWSKA 41", "WOJSKA POLSKIEGO 37", "ŻOŁNIERSKA 16B", 
                                                                 "ŻOŁNIERSKA 18", "ŻOŁNIERSKA 18 A"), class = "factor"), Lat = c(53.794077, 
                                                                                                                                 53.80182, 53.794077, 53.794077, 53.7827025, 53.7688275, 53.80182, 
                                                                                                                                 53.794077, 53.794077, 53.7696245, 53.794077, 53.7698809, 
                                                                                                                                 53.794077), Long = c(20.483249, 20.508952, 20.483249, 20.483249, 
                                                                                                                                                      20.4918876, 20.4903438, 20.508952, 20.483249, 20.483249, 
                                                                                                                                                      20.4927874, 20.483249, 20.492049, 20.483249)), .Names = c("nazwa", 
                                                                                                                                                                                                                "miasto", "dom", "Lat", "Long"), row.names = c(1L, 2L, 12L, 13L, 
                                                                                                                                                                                                                                                               14L, 15L, 23L, 25L, 27L, 29L, 30L, 31L, 32L), class = "data.frame")
polska <- get_googlemap(
  center =c('Olsztyn, Polska'), 
  zoom=12, 
  maptype="roadmap" ,
  scale = 2 
  ,color = "bw"
)
kontury<- ggmap(polska)




punkty <- kontury+ geom_point( aes(x=Long, y=Lat, color=nazwa, shape=nazwa )
                               ,data=subset(swd,(  nazwa=='ODDZIAŁ GINEKOLOGII ONKOLOGICZNEJ'|
                                                     nazwa=='PORADNIA CHIRURGII ONKOLOGICZNEJ'|
                                                     nazwa=='ODDZIAŁ ONKOLOGII KLINICZNEJ CHEMIOTERAPII'|
                                                     nazwa=='PORADNIA ONKOLOGICZNA'|
                                                     nazwa=='ODDZIAŁ RADIOTERAPII'& 
                                                     miasto=="OLSZTYN"))
                               ,size=7

)+ 

  guides(fill  = guide_legend(ncol = 1)) + 
  theme(legend.position="right") +
  scale_shape_manual(values = c(15,16,17,18,19,20), name="Symbol")

print(punkty) 

ВЫВОД

ОБНОВЛЕНИЕ на основе ответа Филиппа. Я сделал что-то вроде этого:

require(rgdal)
require(ggmap)
require(maptools)
require (plyr)

swd <- structure(list(nazwa = structure(c(8L, 8L, 9L, 7L, 7L, 7L, 3L, 
                                          5L, 6L, 4L, 2L, 2L, 1L), .Label = c("ODDZIAŁ CHIRURGII ONKOLOGICZNEJ", 
                                                                              "ODDZIAŁ GINEKOLOGII ONKOLOGICZNEJ", "ODDZIAŁ ONKOLOGICZNY", 
                                                                              "ODDZIAŁ ONKOLOGII I HEMATOLOGII DZIECIĘCEJ", "ODDZIAŁ ONKOLOGII KLINICZNEJ CHEMIOTERAPII", 
                                                                              "ODDZIAŁ RADIOTERAPII", "PORADNIA CHIRURGII ONKOLOGICZNEJ", "PORADNIA ONKOLOGICZNA", 
                                                                              "PORADNIA RADIOTERAPII"), class = "factor"), miasto = structure(c(8L, 
                                                                                                                                                8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L, 8L), .Label = c("DZIAŁDOWO", 
                                                                                                                                                                                                            "ELBLĄG", "EŁK", "GIŻYCKO", "MRĄGOWO", "NOWE MIASTO LUBAWSKIE", 
                                                                                                                                                                                                            "OLECKO", "OLSZTYN", "OSTRÓDA", "PISZ", "SZCZYTNO"), class = "factor"), 
                      dom = structure(c(17L, 5L, 17L, 17L, 8L, 18L, 5L, 17L, 17L, 
                                        20L, 17L, 19L, 17L), .Label = c("BARANKI 24", "GNIEŹNIEŃSKA 2", 
                                                                        "GOŁDAPSKA 1", "HENRYKA SIENKIEWICZA 4", "JAGIELLOŃSKA 78", 
                                                                        "JANA III SOBIESKIEGO 3 C/44", "KONOPNICKIEJ 1", "KOPERNIKA 30", 
                                                                        "KOŚCIUSZKI 30", "KRÓLEWIECKA 146", "KRÓLEWIECKA 146 146", 
                                                                        "LEŚNA 1", "MICKIEWICZA 10", "MICKIEWICZA 14", "OSEDLE MAZURSKIE 33 A", 
                                                                        "WARSZAWSKA 41", "WOJSKA POLSKIEGO 37", "ŻOŁNIERSKA 16B", 
                                                                        "ŻOŁNIERSKA 18", "ŻOŁNIERSKA 18 A"), class = "factor"), Lat = c(53.794077, 
                                                                                                                                        53.80182, 53.794077, 53.794077, 53.7827025, 53.7688275, 53.80182, 
                                                                                                                                        53.794077, 53.794077, 53.7696245, 53.794077, 53.7698809, 
                                                                                                                                        53.794077), Long = c(20.483249, 20.508952, 20.483249, 20.483249, 
                                                                                                                                                             20.4918876, 20.4903438, 20.508952, 20.483249, 20.483249, 
                                                                                                                                                             20.4927874, 20.483249, 20.492049, 20.483249)), .Names = c("nazwa", 
                                                                                                                                                                                                                       "miasto", "dom", "Lat", "Long"), row.names = c(1L, 2L, 12L, 13L, 
                                                                                                                                                                                                                                                                      14L, 15L, 23L, 25L, 27L, 29L, 30L, 31L, 32L), class = "data.frame")

swd <- data.table(swd)           # idk rly why but it didnt want to work w/o this command
setkey(swd,dom)
swd <- swd[swd[,.N,keyby=dom],.(dom,is.unique=N==1,nazwa,miasto,Lat,Long)]

olsztynOSM <- get_openstreetmap(bbox = c (left=20.4359, bottom = 53.7319, right= 20.5623, top= 53.81), scale = 40913, color = c('color'))

moja.paleta <- brewer.pal(9, "Set1") 
swd$kolor <- moja.paleta[swd$nazwa] 

konturyOSM<- ggmap(olsztynOSM)


punkty <- konturyOSM + geom_jitter(aes(x=Long,y=Lat,fill=nazwa), data = swd[!(is.unique)], width=0.006,height=0.006, size=7,pch=21) +
  geom_point(aes(x=Long,y=Lat,fill=nazwa), data = swd[(is.unique)], size=7, pch=25)+ 

  scale_fill_manual( values=setNames(moja.paleta,levels(swd$nazwa)),name='Legenda' ) + 
  guides(fill  = guide_legend(ncol = 1)) + 
  theme(legend.position="right") 

plot(punkty)

ВЫВОД

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


person banshe    schedule 29.02.2016    source источник


Ответы (1)


Попробуйте geom_jitter вместо geom_point. Вы можете указать width и height, чтобы настроить величину джиттера.

Из документации:

width Величина вертикального и горизонтального дрожания. Джиттер добавляется как в положительном, так и в отрицательном направлениях, поэтому общий разброс в два раза превышает указанное здесь значение. Если опущено, по умолчанию используется 40% разрешения данных: это означает, что значения джиттера будут занимать 80% подразумеваемых бинов. Категориальные данные выравниваются по целым числам, поэтому ширина или высота 0,5 будут распространять данные, поэтому невозможно будет увидеть различие между категориями.

height Величина вертикального и горизонтального дрожания. Джиттер добавляется как в положительном, так и в отрицательном направлениях, поэтому общий разброс в два раза превышает указанное здесь значение. Если опущено, по умолчанию используется 40% разрешения данных: это означает, что значения джиттера будут занимать 80% подразумеваемых бинов. Категориальные данные выравниваются по целым числам, поэтому ширина или высота 0,5 будут распространять данные, поэтому невозможно будет увидеть различие между категориями.

В ответ на дополнительный вопрос в вашем комментарии: Допустим, у вас есть некоторые данные со столбцом (или столбцами), которые могут дублироваться или не дублироваться в наблюдениях:

library(data.table)
set.seed(123)
x <- data.table(a=sample(1:5,10,replace=T))
setkey(x,a)

> x
    a
 1: 1
 2: 2
 3: 3
 4: 3
 5: 3
 6: 3
 7: 4
 8: 5
 9: 5
10: 5

Теперь мы можем добавить столбец, чтобы указать, является ли значение уникальным или нет: (Изменить, чтобы ответить на вопрос в вашем другом комментарии: в data.table .N = количество, поэтому x[,.N,keyby=a] вернет количество наблюдений, сгруппированных при каждом появлении a. Кроме того, поскольку я уже установил ключ x равным a и использую keyby, x[,.N,keyby=a] сам является data.table с тем же ключом, что и x, поэтому x[ x[,.N,keyby=a] ] является data.table объединением: соединяет дополнительный столбец N во внутренней таблице со столбцами во внешней таблице. Тогда .(a,is.unique=N==1) является стандартной операцией data.table для выбора списка из двух столбцов, хотя я поленился не использовать больше круглых скобок, чем необходимо. Это также можно было бы прочитать как list(a=a,is.unique=(N==1)). Обратите внимание: лучший способ разобраться в этих командах — разбить их на части и выполнять их шаг за шагом в REPL, внимательно просматривая вывод, пока вы не поймете, что делает каждая из них.)

pts <- x[x[,.N,keyby=a],.(a,is.unique=N==1)]
> pts
    a is.unique
 1: 1      TRUE
 2: 2      TRUE
 3: 3     FALSE
 4: 3     FALSE
 5: 3     FALSE
 6: 3     FALSE
 7: 4      TRUE
 8: 5     FALSE
 9: 5     FALSE
10: 5     FALSE

Давайте добавим столбец только для перечисления наблюдений для построения графика:

pts[,b:=.I]
> pts
    a is.unique  b
 1: 1      TRUE  1
 2: 2      TRUE  2
 3: 3     FALSE  3
 4: 3     FALSE  4
 5: 3     FALSE  5
 6: 3     FALSE  6
 7: 4      TRUE  7
 8: 5     FALSE  8
 9: 5     FALSE  9
10: 5     FALSE 10

Теперь мы можем сделать график, разделяющий по тому, будут ли данные перерисованы (обратите внимание, что не буквально для этих данных, так как здесь я сделал все значения x разными, но я думаю, что это все равно легко визуализировать), как я предложил в комментарии :

ggplot(pts,aes(x=b,y=a)) +
    geom_point(data=pts[(is.unique)],color="blue") +
    geom_jitter(data=pts[!(is.unique)],color="red")

График из десяти точек с дрожанием по умолчанию

Обратите внимание, что только уникальные значения (синие) точно попадают в точки решетки. Мы можем настроить джиттер, скажем, в точках джиттера только по вертикали и меньше, чем по умолчанию:

ggplot(pts,aes(x=b,y=a)) +
    geom_point(data=pts[(is.unique)],color="blue") +
    geom_jitter(data=pts[!(is.unique)],color="red",width=0,height=.2)

График из десяти точек без горизонтального дрожания

Кстати, непрошенная стилистическая придирка: если вы дадите своим шкалам цвета/заливки и формы одно и то же имя, они объединятся, и у вас может быть единая более красивая легенда. Например.:

ggplot(pts,aes(x=b,y=a,color=is.unique,shape=is.unique)) +
     geom_point(data=pts[(is.unique)]) +
     geom_jitter(data=pts[(!is.unique)]) +
     scale_color_manual(values=c("red","blue"),name="Unique a?") +
     scale_shape_manual(values=c(15,16),name="Unique a?")

Сюжет похож на первый график, но с комбинированной легендой цвета и формы

person Philip    schedule 29.02.2016
comment
Но тогда плохо настроить все точки не только с одинаковыми координатами для нескольких топонимов, а у меня гораздо больше точек с одним названием по координате. В этом примере данных я представил только проблему, исходные данные намного больше. Или я ошибаюсь? Через секунду попробую и напишу, что вижу. - person banshe; 01.03.2016
comment
Если это большая проблема, вы можете разделить свои данные (либо на два data.frames, либо добавив столбец для использования в качестве индикатора и используя аргумент data для geom_point), а затем сделать два слоя: один для уникальных данных с geom_point, и один для данных, которые могли бы быть перерисованы, с geom_jitter (или, что то же самое, с width/height=0). Я добавил фиктивный MWE, с которым вы сможете повозиться, чтобы получить результат. - person Philip; 01.03.2016
comment
Большое спасибо за ваши усилия, ваш пример действительно полезен. Я попробую, и я постараюсь добавить вашу идею в свой сценарий. Благодарю вас! :) - person banshe; 01.03.2016
comment
Знаете, почему я не могу использовать ggplot на карте? Когда я пытаюсь это сделать, я получаю сообщение об ошибке: Error in p + o : non-numeric argument to binary operator In addition: Warning message: Incompatible methods ("+.gg", "Ops.data.frame") for "+" это работает, когда я делаю это так: kontury<- ggmap(polska) punkty <- kontury + geom_jitter(aes(x=Long,y=Lat,color=nazwa), data = swd, width=0.02,height=.05, size=7) но у меня проблемы с легендой, когда я использую 2 разные функции: точку геометрии и дрожание, обе с aes внутри. - person banshe; 01.03.2016
comment
И кстати, не могли бы вы объяснить это x[x[,.N,keyby=a],.(a,is.unique=N==1)]? для чего ,.N? Я понимаю keyby и после этого выбор столбцов. Надеюсь, я не прошу слишком многого... Я не хочу отнимать у вас слишком много времени. - person banshe; 01.03.2016
comment
Обычно ошибка non-numeric argument возникает, когда вы не ставите + в нужных местах. + необходимо объединить объекты, которые ggplot2 распознает, например. убедитесь, что у вас нет конечных + после вашего последнего geom, и убедитесь, что ваш первый объект - ggplot()/ggmap() и т. д. - person Philip; 01.03.2016
comment
Я объясню синтаксис в ответе. - person Philip; 01.03.2016
comment
Кроме того, вы можете помочь избежать ошибок, а также упростить свой код, поместив как можно больше общих эстетических элементов в команду самого высокого уровня. Так, например, вы, вероятно, захотите сделать что-то вроде ggmap(polska,aes(x=Long,y=Lat,color=nazwa,shape=nazwa)) + geom_point(data=....) + geom_jitter(data=....), а не повторять aes в каждом geom. - person Philip; 01.03.2016
comment
Теоретически ваш комментарий проясняет все, но все же я получил массу предупреждений и ошибок при попытке поместить aes на более высокий уровень (ggmap) ... Я обновил свой пост, добавив скрипт на основе вашего ответа, чтобы другие могли его использовать. Привет :) Хорошего дня! Спасибо еще раз. - person banshe; 02.03.2016