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:
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)
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")
)
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")
)
CodePudding user response:
There are really two questions here:
- How do I extract a polygon from a ggplot?
- 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))
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')