2015-10-23 3 views
0

Я использовал пакет alphahull, чтобы очертить точки на карте. Я рисую контуры с помощью geom_segment.Заполнение alphahull ggplot2

Мой вопрос: как заполнить разграничение, заданное сегментом цветом?

Вот воспроизводимый пример:

set.seed(2) 
dat <- data.frame(x = rnorm(20, 10, 5), y = rnorm(20, 20, 5), z = c(rep(1, 6), rep(2, 4))) 

library(ggplot2) 
library(alphahull) 
alpha <- 100 
alphashape1 <- ashape(dat[which(dat$z==1), c("x", "y")], alpha = alpha) 
alphashape2 <- ashape(dat[which(dat$z==2), c("x", "y")], alpha = alpha) 

map <- ggplot(dat, aes(x = x, y = y)) + 
geom_point(data = dat, aes(x = x, y = y, colour = as.factor(dat$z))) + 
geom_segment(data = data.frame(alphashape1$edges), aes(x = x1, y = y1, xend = x2, yend = y2, colour = levels(as.factor(dat$z))[1])) + 
geom_segment(data = data.frame(alphashape2$edges), aes(x = x1, y = y1, xend = x2, yend = y2, colour = levels(as.factor(dat$z))[2])) 
map 

enter image description here

ответ

1

Я считаю, что это работает без необходимости графа опс:

fortify.ashape <- function(ashape_res) { 
    xdf <- data.frame(ashape_res$edges) 
    xdf <- do.call(
    rbind, 
    lapply(1:nrow(xdf), function(i) { 
     rbind(
     data.frame(x=xdf$x1[i], y=xdf$y1[i]), 
     data.frame(x=xdf$x2[i], y=xdf$y2[i]) 
    ) 
    }) 
) 
    xdf <- xdf[order(-1 * atan2(
    xdf$y - mean(range(xdf$y)), 
    xdf$x - mean(range(xdf$x)))), c("x", "y")] 
    xdf <- rbind.data.frame(xdf[nrow(xdf),], xdf[1:(nrow(xdf)-1),]) 
    xdf 
} 

alphashape1 <- ashape(dat[which(dat$z == 1), c("x", "y")], alpha = 15) 
alphashape2 <- ashape(dat[which(dat$z == 2), c("x", "y")], alpha = 15) 

ggplot() + 
    geom_point(data = dat, aes(x = x, y = y, colour = as.factor(dat$z))) + 
    geom_polygon(data=alphashape1, aes(x, y), fill="red", alpha=2/3) + 
    geom_polygon(data=alphashape2, aes(x, y), fill="blue", alpha=2/3) 

enter image description here

+0

Это выглядит аккуратнее с этой функцией. Как возможно, что он работает, не помещая 'geom_polygon (data = fortify.ashape (alphashape1), aes (x, y), fill =" red ", alpha = 2/3)' хотя? –

+0

ggplot2 всегда будет пытаться автоматически укрепить классифицированные объекты и (к счастью!) Результат 'ashape()' является классом-классом 'ashape'. Это более легкий способ использования пользовательских объектов без использования пользовательского 'Geom' – hrbrmstr

0

Это потому, что функция ashape возвращает только сегменты, а не в любом порядке.

Единственный способ, который я нашел для восстановления заказа, - это использование информации о узле для формирования графика, а затем поиск кратчайшего пути по этому графу.

Подробный пример: https://rpubs.com/geospacedman/alphasimple - код нуждается в обертывании в одну функцию, что должно быть довольно легко сделать. После того, как ваш порядок будет отсортирован, geom_polygon будет рисовать его с заполненным затенением в ggplot2.

0

Основываясь на ответе Spacedman, я заказал отдельно два набора точек и придумал это решение. Его можно оптимизировать с помощью функции, которая делает это для каждой группы автоматически.

set.seed(2) 
dat <- data.frame(x = rnorm(20, 10, 5), y = rnorm(20, 20, 5), z = c(rep(1, 6), rep(2, 4))) 

library(ggplot2) 
library(alphahull) 
alpha <- 100 
alphashape1 <- ashape(dat[which(dat$z==1), c("x", "y")], alpha = alpha) 
alphashape2 <- ashape(dat[which(dat$z==2), c("x", "y")], alpha = alpha) 

map <- ggplot(dat, aes(x = x, y = y)) + 
geom_point(data = dat, aes(x = x, y = y, colour = as.factor(dat$z))) + 
geom_segment(data = data.frame(alphashape1$edges), aes(x = x1, y = y1, xend = x2, yend = y2, colour = levels(as.factor(dat$z))[1])) + 
geom_segment(data = data.frame(alphashape2$edges), aes(x = x1, y = y1, xend = x2, yend = y2, colour = levels(as.factor(dat$z))[2])) 
map  

alpha <- 15 # transparency argument 
    # First contour 
    alphashape1 <- ashape(dat[which(dat$z == 1), c("x", "y")], alpha = alpha) 
    alphashape1_ind <- alphashape1$edges[, c("ind1", "ind2")] 
    class(alphashape1_ind) = "character" 
    alphashape1_graph <- graph.edgelist(alphashape1_ind, directed = FALSE) 
    cut_graph1 <- alphashape1_graph - E(alphashape1_graph)[1] # Cut the first edge 
    ends1 <- names(which(degree(cut_graph1) == 1)) # Get two nodes with degree = 1 
    path1 <- get.shortest.paths(cut_graph1, ends1[1], ends1[2])$vpath[[1]] 
    path_nodes1 <- as.numeric(V(alphashape1_graph)[path1]$name) 

    # Second contour 
    alphashape2 <- ashape(dat[which(dat$z == 2), c("x", "y")], alpha = alpha) 
    alphashape2_ind <- alphashape2$edges[, c("ind1", "ind2")] 
    class(alphashape2_ind) = "character" 
    alphashape2_graph <- graph.edgelist(alphashape2_ind, directed = FALSE) 
    cut_graph2 <- alphashape2_graph - E(alphashape2_graph)[1] # Cut the first edge 
    ends2 <- names(which(degree(cut_graph2) == 1)) # Get two nodes with degree = 1 
    path2 <- get.shortest.paths(cut_graph2, ends2[1], ends2[2])$vpath[[1]] 
    path_nodes2 <- as.numeric(V(alphashape2_graph)[path2]$name) 

    # Updating of previous plot (see question) 
    map + 
     geom_polygon(data = dat[which(dat$z == 1), c("x", "y")][path_nodes1, ], aes(x = x, y = y), 
        fill = "red", colour = "red", size = 0.5, alpha = 0.3) + 
     geom_polygon(data = dat[which(dat$z == 2), c("x", "y")][path_nodes2, ], 
        aes(x = x, y = y), colour = "blue", fill = "blue", size = 0.5, alpha = 0.3) 

enter image description here