如何使用“ggplot2”和“gganimate”在 R 中对不断增长的正方形和不断增长的斐波那契螺旋进行动画处理?

问题描述 投票:0回答:1

我正在尝试在 R 中制作斐波那契数列的动画,其中正方形和螺旋线一起生长。我已经成功创建了两个单独的动画:

  1. 不断增长的正方形,但没有不断增长的螺旋: 正方形一一出现,但螺旋是静态的。

  2. 不断增长的螺旋,但没有不断增长的方块: 螺旋不断增长,但正方形是静止的。

我想将这两种效果组合在一个动画中,其中每个方块都以其相应的螺旋弧线出现。以下是我的尝试:

代码 1:增长正方形,不增长螺旋

library(ggplot2)
library(gganimate)

# Define a function to generate Fibonacci numbers
fibonacci <- function(n) {
  fib_seq <- numeric(n)
  fib_seq[1] <- 1
  fib_seq[2] <- 1
  for (i in 3:n) {
    fib_seq[i] <- fib_seq[i-1] + fib_seq[i-2]
  }
  return(fib_seq)
}

# Function to generate quarter circle arc data
quarter_circle_arc <- function(x, y, size, direction) {
  theta <- seq(0, pi/2, length.out = 100)
  if (direction == 1) {
    # Bottom-left arc
    data.frame(
      x = x + size * (1 - cos(theta)),
      y = y + size * (1 - sin(theta))
    )
  } else if (direction == 2) {
    # Bottom-right arc
    data.frame(
      x = x + size * (sin(theta) - 1) + size,
      y = y + size * (1 - cos(theta))
    )
  } else if (direction == 3) {
    # Top-right arc
    data.frame(
      x = x + size * (cos(theta) - 1) + size,
      y = y + size * (sin(theta) - 1) + size
    )
  } else if (direction == 0) {
    # Top-left arc
    data.frame(
      x = x + size * (1 - sin(theta)),
      y = y + size * (cos(theta) - 1) + size
    )
  }
}

# Generate the first 10 Fibonacci numbers
fib_seq <- fibonacci(10)

# Initialize the data frame for squares
squares <- data.frame(
  x = numeric(10), 
  y = numeric(10), 
  size = fib_seq, 
  direction = numeric(10),
  frame = 1:10
)

# Initialize the data frame for arcs
arcs <- data.frame(
  x = numeric(0), 
  y = numeric(0), 
  frame = integer(0)
)

# Set the initial position and direction
x <- 0
y <- 0
direction <- 1 

for (i in 1:10) {
  if (direction == 1) {
    y <- y - ifelse(x == 0, 0, fib_seq[i])
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  } else if (direction == 2) {
    x <- x + fib_seq[i-1]
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  } else if (direction == 3) {
    x <- x - fib_seq[i-2]
    y <- y + fib_seq[i-1]
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  } else if (direction == 4) {
    x <- x - fib_seq[i]
    y <- y - fib_seq[i-2]
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  }
  
  # Store the direction for the arcs
  squares[i, "direction"] <- direction
  
  # Generate the arc for the current square and append it to arcs data frame
  new_arc <- quarter_circle_arc(
    squares$x[i], squares$y[i], squares$size[i], direction = (i %% 4)
  )
  new_arc$frame <- i  # Assign the frame for animation
  arcs <- rbind(arcs, new_arc)
  
  # Update the direction
  direction <- (direction %% 4) + 1
}

# Create the base plot
p <- ggplot() +
  coord_fixed(ratio = 1) +
  theme_void()

# Plot squares and arcs with gradual appearance
p_anim <- p + 
  geom_rect(data = squares, aes(xmin = x, ymin = y, xmax = x + size, ymax = y + size, frame = frame), 
            fill = "white", color = "black") +
  geom_path(data = arcs, aes(x = x, y = y, frame = frame), color = "black") +
  transition_manual(frames = squares$frame, cumulative = TRUE)  # Keep previous frames visible

# Render the animation
animate(p_anim, nframes = 100, fps = 10)

代码 2:不断增长的螺旋,不不断增长的正方形

library(ggplot2)
library(gganimate)

# Define a function to generate Fibonacci numbers
fibonacci <- function(n) {
  fib_seq <- numeric(n)
  fib_seq[1] <- 1
  fib_seq[2] <- 1
  for (i in 3:n) {
    fib_seq[i] <- fib_seq[i-1] + fib_seq[i-2]
  }
  return(fib_seq)
}

# Function to generate quarter circle arc data
quarter_circle_arc <- function(x, y, size, direction) {
  theta <- seq(0, pi/2, length.out = 100)
  if (direction == 1) {
    # Bottom-left arc
    data.frame(
      x = x + size * (1 - cos(theta)),
      y = y + size * (1 - sin(theta))
    )
  } else if (direction == 2) {
    # Bottom-right arc
    data.frame(
      x = x + size * (sin(theta) - 1) + size,
      y = y + size * (1 - cos(theta))
    )
  } else if (direction == 3) {
    # Top-right arc
    data.frame(
      x = x + size * (cos(theta) - 1) + size,
      y = y + size * (sin(theta) - 1) + size
    )
  } else if (direction == 0) {
    # Top-left arc
    data.frame(
      x = x + size * (1 - sin(theta)),
      y = y + size * (cos(theta) - 1) + size
    )
  }
}

# Generate the first 10 Fibonacci numbers
fib_seq <- fibonacci(10)

# Initialize the data frame for squares
squares <- data.frame(
  x = numeric(10), 
  y = numeric(10), 
  size = fib_seq, 
  direction = numeric(10),
  frame = 1:10
)

# Initialize the data frame for arcs
arcs <- data.frame(
  x = numeric(0), 
  y = numeric(0), 
  frame = integer(0)
)

# Set the initial position and direction
x <- 0
y <- 0
direction <- 1 

for (i in 1:10) {
  if (direction == 1) {
    y <- y - ifelse(x == 0, 0, fib_seq[i])
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  } else if (direction == 2) {
    x <- x + fib_seq[i-1]
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  } else if (direction == 3) {
    x <- x - fib_seq[i-2]
    y <- y + fib_seq[i-1]
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  } else if (direction == 4) {
    x <- x - fib_seq[i]
    y <- y - fib_seq[i-2]
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  }
  
  # Store the direction for the arcs
  squares[i, "direction"] <- direction
  
  # Generate the arc for the current square and append it to arcs data frame
  new_arc <- quarter_circle_arc(
    squares$x[i], squares$y[i], squares$size[i], direction = (i %% 4)
  )
  new_arc$frame <- i  # Assign the frame for animation
  arcs <- rbind(arcs, new_arc)
  
  # Update the direction
  direction <- (direction %% 4) + 1
}

# Create the base plot
p <- ggplot() +
  coord_fixed(ratio = 1) +
  theme_void()

# Plot squares with gradual appearance
for (i in 1:10) {
  p <- p + 
    geom_rect(data = squares[1:i,], aes(xmin = x, ymin = y, xmax = x + size, ymax = y + size), 
              fill = "white", color = "black") +
    geom_path(data = arcs[arcs$frame <= i,],

 aes(x = x, y = y), color = "black")
}

# Animate the plot with growing spiral and preserving squares
p_anim <- p + 
  transition_reveal(arcs$frame) +
  enter_fade() + 
  exit_fade()

# Render the animation
animate(p_anim, nframes = 100, fps = 10)

我希望正方形与相应的弧线一起逐渐出现,形成不断增长的螺旋。然而,我还没能实现这一目标。

r ggplot2 animation fibonacci gganimate
1个回答
0
投票
library(ggplot2)
library(gganimate)

# Define a function to generate Fibonacci numbers
fibonacci <- function(n) {
  fib_seq <- numeric(n)
  fib_seq[1] <- 1
  fib_seq[2] <- 1
  for (i in 3:n) {
    fib_seq[i] <- fib_seq[i-1] + fib_seq[i-2]
  }
  return(fib_seq)
}

# Function to generate quarter circle arc data
quarter_circle_arc <- function(x, y, size, direction) {
  theta <- seq(0, pi/2, length.out = 100)
  if (direction == 1) {
    # Bottom-left arc
    data.frame(
      x = x + size * (1 - cos(theta)),
      y = y + size * (1 - sin(theta))
    )
  } else if (direction == 2) {
    # Bottom-right arc
    data.frame(
      x = x + size * (sin(theta) - 1) + size,
      y = y + size * (1 - cos(theta))
    )
  } else if (direction == 3) {
    # Top-right arc
    data.frame(
      x = x + size * (cos(theta) - 1) + size,
      y = y + size * (sin(theta) - 1) + size
    )
  } else if (direction == 0) {
    # Top-left arc
    data.frame(
      x = x + size * (1 - sin(theta)),
      y = y + size * (cos(theta) - 1) + size
    )
  }
}

# Generate the first 10 Fibonacci numbers
fib_seq <- fibonacci(10)

# Initialize the data frame for squares
squares <- data.frame(
  x = numeric(10), 
  y = numeric(10), 
  size = fib_seq, 
  direction = numeric(10),
  frame = 1:10
)

# Initialize the data frame for arcs
arcs <- data.frame(
  x = numeric(0), 
  y = numeric(0), 
  frame = integer(0)
)

# Set the initial position and direction
x <- 0
y <- 0
direction <- 1 

for (i in 1:10) {
  if (direction == 1) {
    y <- y - ifelse(x == 0, 0, fib_seq[i])
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  } else if (direction == 2) {
    x <- x + fib_seq[i-1]
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  } else if (direction == 3) {
    x <- x - fib_seq[i-2]
    y <- y + fib_seq[i-1]
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  } else if (direction == 4) {
    x <- x - fib_seq[i]
    y <- y - fib_seq[i-2]
    squares[i, "x"] <- x
    squares[i, "y"] <- y
  }
  
  # Store the direction for the arcs
  squares[i, "direction"] <- direction
  
  # Generate the arc for the current square and append it to arcs data frame
  new_arc <- quarter_circle_arc(
    squares$x[i], squares$y[i], squares$size[i], direction = (i %% 4)
  )
  new_arc$frame <- i  # Assign the frame for animation
  arcs <- rbind(arcs, new_arc)
  
  # Update the direction
  direction <- (direction %% 4) + 1
}
# Create the base plot
p <- ggplot() +
  coord_fixed(ratio = 1) +
  theme_void()

p <- p +
  geom_rect(
    data = squares, aes(xmin = x, ymin = y, xmax = x + size, ymax = y + size),
    fill = "white", color = "black"
  ) +
  geom_path(
    data = arcs,
    aes(x = x, y = y), color = "black"
  )


# Animate the plot with growing spiral and preserving squares
p_anim <- p +
  transition_manual(frames = frame, cumulative = TRUE) + # Keep previous frames visible
  enter_fade() +
  exit_fade()

# Render the animation
animate(p_anim, nframes = 100, fps = 10)

requested animated spiral image

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.