Introduction

In this document, I collect some equations that generate curves that I like.

If you like mathematical art, I would recommend looking at the work of Hamid Naderi Yeganeh, who builds beautiful images based on mathematical concepts.

The butterfly curve

The butterfly curve is defined in the paper by Fay (1989). This curve is described according to the following parametric equations:

\(x=sin(t)\Big(e^{cos(t)}-2 \, cos(4t)-sin^5\big(\frac{t}{12}\big)\Big)\)

\(y=cos(t)\Big(e^{cos(t)}-2 \,cos(4t)-sin^5\big(\frac{t}{12}\big)\Big)\)

t is in the range: \([0, 12\pi]\)

# the function butterfly generates a data frame
# by evaluating the parametric equations that
# define the rose curve in the range of 0 to 12pi
butterfly <- function(n=1000){
  data.frame(t = seq(0,12*pi,length.out = n)) %>%
    mutate(x = sin(t)*(exp(cos(t))-2*cos(4*t)-(sin(t/12))^5),
           y = cos(t)*(exp(cos(t))-2*cos(4*t)-(sin(t/12))^5))
}
# Plot a butterfly curve
df_butter <- butterfly()

df_butter %>% ggplot() + geom_path(data = df_butter,aes(x,y)) + coord_equal() + 
  theme_void() 
The butterfly curve (Fay, 1989)

Figure 1: The butterfly curve (Fay, 1989)

The rose

This curve is described by the following parametric equations:

\(x=cos(k \, \theta) \, cos(\theta)\)

\(y=cos(k \, \theta) \, sin(\theta)\)

rose_curve <- function(n,d) {
  data.frame(theta = seq(0, 32*pi,pi/180)) %>%
    mutate(x = cos(n/d*theta)*cos(theta),
           y = cos(n/d*theta)*sin(theta)) %>%
    select(x, y)
}

Rose curves for the combination of n and d values, which define \(k=n/d\).

n and d span in the range \([1,10]\)

df_rose <- data.frame(x = numeric(0), y = numeric(0), n = integer(0), d = integer(0))

for(n in 1:10) {
  for(d in 1:10) {
    df_temporary <- rose_curve(n, d) %>% mutate(n = n, d = d)
    df_rose <- rbind(df_rose, df_temporary)
  }
}

p <- ggplot() +
  geom_path(aes(x, y), df_rose, size = 0.35, lineend = "round") + facet_grid(d ~ n) +
  coord_equal() + theme_void()

p
Rose curves

Figure 2: Rose curves

Hypocycloids

Refer to the Wolfram MathWorld article for details about hypocycloids.

When \(x(0)=a\), the parametric equations defining the hypocycloid are:

\(x=(a-b)\,cos(t) + b\,cos\big(\frac{a-b}{b}t\big)\)

\(y=(a-b)\,sin(t) - b\,sin\big(\frac{a-b}{b}t\big)\)

hypocycloid <- function(n = 200, a_inc,b_inc,t_inc){
  a0 = seq(1,n)
  b0 = seq(1,n)
  t0 = seq(0,n-1)
  for (i in 2:n) {
    a0[i]=a0[i-1]+a_inc
    b0[i]=b0[i-1]+b_inc
    t0[i]=t0[i-1]+t_inc
  }
  data.frame(a0,b0,t0) %>%
    mutate(  x0 = (a0 - b0)*cos(t0) + b0 * cos((a0/b0-1)*t0),
             y0 = (a0 - b0)*sin(t0) - b0 * sin((a0/b0-1)*t0),
             x1 = c(x0[2:n],x0[1]),
             y1 = c(y0[2:n],y0[1])) %>%
    select(x0,y0,x1,y1,t0)
}
# Uncomment the following lines so the parameters take random values.

# a_inc <- sample(seq(-100,100),1,replace=TRUE)/10
# b_inc <- sample(seq(-100,100),1,replace=TRUE)/10
# t_inc <- sample(seq(-100,100),1,replace=TRUE)/10

# I particulary like the plot generated by the following set of parameters 
a_inc <- 1.9
b_inc <- 6.3
t_inc <- -7


df_hypo <- hypocycloid(a_inc = a_inc,b_inc = b_inc,t_inc = t_inc) 

df_hypo %>% ggplot(aes(x=x0,y=y0)) +
  geom_curve(aes(xend=x1,yend=y1)) +
  scale_x_continuous(expand = c(0.1,0.1)) +
  scale_y_continuous(expand = c(0.1,0.1)) +
  coord_equal() +
  theme_void()
A hypocycloid

Figure 3: A hypocycloid

Clifford attractors

Clifford attractors are defined by the following equations:

\(x_{n+1}=sin(a\,y_n) + c\, cos(a\,x_n)\)

\(y_{n+1}=sin(b\,x_n) + d\, cos(b\,y_n)\)

The above equations determine the (X,Y) locations of discrete steps of a particle starting from point (x0,y0) and according to the parameters a, b, c and d.

The function pickover is based on the implementation of Antonio Sánchez Chinchón. The only difference is that pickover is based enterily on R, whereas Sánchez Chinchón defined his function in C++ by means of the rcpp package.

# n is set to 1M
# a, b, c and d are the parameters of the equations
pickover <- function(n=10000000,a,b,c,d){
  x <- vector("numeric", n)
  y <- vector("numeric", n)
  x[1] <- 0
  y[1] <- 0
  for(i in 2:n) {
    x[i] <- sin(a * y[i-1]) + c * cos(a * x[i-1])
    y[i] <- sin(b * x[i-1]) + d * cos(b * y[i-1])
  }
  df <- data.frame(x = x, y = y)
}
# Set the values of the parameters
a = 1.2516757480973668; b = -1.1851629292227903; c = 1.4603558653849573; d = -1.3708149174574649

df_clifford <- pickover(a=a,b=b,c=c,d=d)

df_clifford %>% ggplot(aes(x, y)) + 
  geom_point(color="black", shape=46, alpha=.01) + coord_equal() + theme_void()
A plot defined by Clifford attractors

Figure 4: A plot defined by Clifford attractors

References

Fay, Temple H. 1989. “The Butterfly Curve.” Journal Article. The American Mathematical Monthly 96 (5): 442–43. https://doi.org/10.1080/00029890.1989.11972217.