1

I have measured the length and width of ~2000 seeds for my university project. I want to plot their shapes for an easy to interpret visual representation.

They are elliptical, but the ends are pointed so ellipse functions don't quite work.

See image for an idea of the seed shape.

enter image description here

  • 2
    Create two functions with far-offset centers? (*"Is there an R function?"* No, I don't think so.) – r2evans Jul 18 '21 at 23:41
  • What about two `geom_curve()`s back to back? https://ggplot2.tidyverse.org/reference/geom_segment.html#examples – Mark Neal Jul 19 '21 at 00:43
  • I'm not following something, though: you have data to plot, why do you need to contrive a shape when the shape will be defined by the data? – r2evans Jul 19 '21 at 02:38
  • (BTW, my first comment on *"two functions"* should really be *"two circles/functions"*, distracted-typing ...) – r2evans Jul 19 '21 at 02:39
  • This sounds like a violin plot. It is a box plot that uses kernel density estimation instea of a rectangle. There are base R and ggplot2 implementations. – dcarlson Jul 19 '21 at 03:41
  • If you want to try the `geom_curve()` approach, this might be helpful: https://www.r-bloggers.com/2021/07/adding-lines-or-other-geoms-to-a-ggplot-by-calling-a-custom-function/ – Mark Neal Jul 20 '21 at 04:32
  • Now we’ve solved the problem, @Oscar, I think you could usefully change the question to: “is there a custom geometry or function for creating a plot with a pointed ellipse or lens?” That might make it clearer for the next searchers. – Mark Neal Jul 23 '21 at 02:18

2 Answers2

3

EDIT: Added coord_fixed() to ensure aspect ratio is correct, and some dummy points to stretch canvas.

Does this work? It is back to back geom_curves().

#Stackoverflow seed lens geom_curve
#question from:
#https://stackoverflow.com/questions/68433803/is-there-a-function-in-r-for-creating-an-ellipse-with-pointed-ends#comment120943747_68433803
#assistance from:
#https://stackoverflow.com/a/55627647/4927395

library(tidyverse)

df <- tribble(
  ~seed, ~h, ~w, ~row,
  #----|----|---|---
  "Oak", 5,  4,   1,
  "Soy", 2,  2,   2,
  "Rye", 4,  1,   3
)


df <- df %>% mutate(curvature = w/h)

ggplot() + 
  lapply(split(df, 1:nrow(df)), function(dat) {
    geom_curve(data = dat, aes(x = row, y = -h/2, xend = row, yend = h/2), curvature = dat["curvature"]) }
  ) +
  lapply(split(df, 1:nrow(df)), function(dat) {
    geom_curve(data = dat, aes(x = row, y = h/2, xend = row, yend = -h/2), curvature = dat["curvature"]) }
  )+
  geom_point(aes(x=-2, y=0), colour = NA)+
  geom_point(aes(x=5, y=0), colour = NA)+
  geom_label(data = df, aes(x=row, y = 0, label = seed))+
  coord_fixed(ratio = 1) +
  #coord_cartesian(xlim = c(-2,nrow(df)+2))
  ylab(NULL)+


ggsave("seeds.png")

and the result: seeds image

Mark Neal
  • 996
  • 16
  • 52
1

Here is a partial answer to get you started. The shape you described is called a "lens" and is the intersection of two equal radius circles. See https://mathworld.wolfram.com/Circle-CircleIntersection.html for derivations of equations for its dimensions, areas etc. It is also formed byt two "segments" back to back. We can use the equations from here https://mathworld.wolfram.com/CircularSegment.html for how the height and width of a segment relate to the radius.

Using these equations we can plot intersecting circles that provide an intersection of the required height and width:

height = 10
width = 3

a = height
h = width/2

R = function(a, h) (a^2/(8*h)) + h/2 # radius of circles
D = function(r, h) 2*r - 2*h # distance between circle centers
r = R(a, h)
d = D(r, h)

plot(NA, asp=1, xlim=c(-h,h), ylim=c(-a/2,a/2) )
plotrix::draw.circle(-d/2,0,r)
plotrix::draw.circle(d/2,0,r)

enter image description here

I leave it as an exercise for you to use create a function that draws a polygon only around the intersection (I did say it is a partial answer :-)

dww
  • 30,425
  • 5
  • 68
  • 111