Home > OS >  Centroid of a countour plot ggplot
Centroid of a countour plot ggplot

Time:04-09

Good morning everyone,

I need to plot the centroid of a contour plot. Consider this code as an example:

library(ggplot2)
set.seed(1)
df <- data.frame(x = rnorm(50), y = rnorm(50))
ggplot()  
geom_density2d(data = df, aes(x, y), color = "#ff0000", bins = 5) 
geom_point()  
theme(axis.title= element_blank(), panel.border = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), axis.line = element_line(size = 0.5, linetype = "solid", colour = "black"), panel.background = element_rect(fill = "white", colour = "white", size = 10, linetype = "solid"), text = element_text(family = "sans"))

I obtain an image like this:

enter image description here

How can i find and draw the centroid of this figure?

Thanks in advance!!

CodePudding user response:

It is an interesting yet hard exercise. geom_density2d is just plotting lines based on point densities, according to certain parameters (bins = 5). You can approximate the "center of mass" of your points using spatial analysis:

library(ggplot2)
set.seed(1)
df <- data.frame(x = rnorm(50), y = rnorm(50))

# Spatial analysis
library(sf)
library(raster)

# Your points as spatial
points <- st_as_sf(df, coords=c("x", "y"))

# Create a raster (grid 100x100)
rast <- raster(points, ncols=10, nrows=10)
# Count the number of points on each pixel
rasterized <- rasterize(points, rast, fun="count")

plot(rasterized)

enter image description here

So with that we have detected which pixel (square) has more points, hence this square has the higher density of points. Now we can extract the coordinates of that pixel and plot that:


df_points <- as.data.frame(rasterized, xy=TRUE, na.rm=TRUE)
cent <- df_points[df_points$layer == max(df_points$layer), ]
cent$label <- "centroid?"


ggplot()  
  geom_density2d(data = df, aes(x, y), color = "#ff0000", bins = 5)  
  geom_point(data=cent, aes(x, y, color=label))  
  scale_color_manual(values="green")   
  # For contrast only
  geom_sf(data=points, alpha=0.15)  
  theme(
    axis.title = element_blank(),
    panel.border = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), axis.line = element_line(size = 0.5, linetype = "solid", colour = "black"), panel.background = element_rect(fill = "white", colour = "white", size = 10, linetype = "solid"), text = element_text(family = "sans")
  )

enter image description here

The point on cent is not the centroid of the contour plot, but represent where the higher concentration of points can be located.

You can also compute the mean of your coordinates...

ggplot()  
  geom_density2d(data = df, aes(x, y), color = "#ff0000", bins = 5)  
  geom_point(aes(mean(df$x), mean(df$y)))  
  # For contrast only
  geom_sf(data=points, alpha=0.15)  
  theme(
    axis.title = element_blank(),
    panel.border = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), axis.line = element_line(size = 0.5, linetype = "solid", colour = "black"), panel.background = element_rect(fill = "white", colour = "white", size = 10, linetype = "solid"), text = element_text(family = "sans")
  )


enter image description here Hope that helps!

CodePudding user response:

There are really two questions here:

  1. How do I extract a polygon from a ggplot?
  2. How do I work out the centroid of a polygon?

If we start with the plot from your code:

set.seed(1)

df <- data.frame(x = rnorm(50), y = rnorm(50))

p <- ggplot()  
  geom_density2d(data = df, aes(x, y), color = "#ff0000", bins = 5) 
  geom_point()  
  theme(axis.title= element_blank(), 
        panel.border = element_blank(), 
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), 
        axis.line = element_line(size = 0.5, 
                                 linetype = "solid", colour = "black"), 
        panel.background = element_rect(fill = "white", colour = "white", 
                                        size = 10, linetype = "solid"), 
        text = element_text(family = "sans"))

Then we can get a data frame of the x, y co-ordinates of all 4 polygons making up the contours in your ggplot by doing:

contours <- layer_data(p)

As noted in the comments, since there are multiple contour lines, there are multiple centroids. I assume you are looking for the centroid of the central contour. We can get that by doing:

contours <- contours[contours$piece == 5,]
pracma::poly_center(contours$x, contours$y)
#> [1]  0.1131070 -0.1200828

So to plot the centroid, we need only do:

p   geom_point(aes(x = 0.1131070, y = -0.1200828))

enter image description here

Note that this is not the same as the mean of x and mean of y:

p   
  geom_point(aes(x = 0.1131070, y = -0.1200828))  
  geom_point(aes(x = mean(df$x), y = mean(df$y)), colour = 'green')

enter image description here

  • Related