Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constrict ggplot ellips to realistic/possible values

Tags:

r

ggplot2

ggproto

When plotting an ellips with ggplot is it possible to constrain the ellips to values that are actually possible?

For example, the following reproducible code and data plots Ele vs. Var for two species. Var is a positive variable and cannot be negative. Nonetheless, negative values are included in the resulting ellips. Is it possible to bound the ellips by 0 on the x-axis (using ggplot)?

More specifically, I am picturing a flat edge with the ellipsoids truncated at 0 on the x-axis.

library(ggplot2)
set.seed(123)
df <- data.frame(Species = rep(c("BHS", "MTG"), each = 100),
                 Ele = c(sample(1500:3000, 100), sample(2500:3500, 100)),
                 Var = abs(rnorm(200)))

ggplot(df, aes(Var, Ele, color = Species)) +
  geom_point() +
  stat_ellipse(aes(fill = Species), geom="polygon",level=0.95,alpha=0.2) 

enter image description here

like image 328
B. Davis Avatar asked Jan 20 '26 18:01

B. Davis


1 Answers

You could edit the default stat to clip points to a particular value. Here we change the basic stat to trim x values less than 0 to 0

StatClipEllipse <- ggproto("StatClipEllipse", Stat,
    required_aes = c("x", "y"),
    compute_group = function(data, scales, type = "t", level = 0.95,
       segments = 51, na.rm = FALSE) {
           xx <- ggplot2:::calculate_ellipse(data = data, vars = c("x", "y"), type = type,
               level = level, segments = segments)
           xx %>% mutate(x=pmax(x, 0))
      }
)

Then we have to wrap it in a ggplot stat that is identical to stat_ellipe except that it uses our custom Stat object

stat_clip_ellipse <- function(mapping = NULL, data = NULL,
                         geom = "path", position = "identity",
                         ...,
                         type = "t",
                         level = 0.95,
                         segments = 51,
                         na.rm = FALSE,
                         show.legend = NA,
                         inherit.aes = TRUE) {
  layer(
    data = data,
    mapping = mapping,
    stat = StatClipEllipse,
    geom = geom,
    position = position,
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(
      type = type,
      level = level,
      segments = segments,
      na.rm = na.rm,
      ...
    )
  )
}

then you can use it to make your plot

ggplot(df, aes(Var, Ele, color = Species)) +
  geom_point() +
  stat_clip_ellipse(aes(fill = Species), geom="polygon",level=0.95,alpha=0.2) 

enter image description here

This was inspired by the source code for stat_ellipse.

like image 90
MrFlick Avatar answered Jan 22 '26 08:01

MrFlick