Happy Chinese New Year 2025!!!
Happy CNY 2025 🎉🧧!
On my way to Hangzhou Xiaoshan International Airport for my return to Sydney, the streets were beautifully adorned with red lanterns 🏮 hanging from the streetlights. Inspired by this enchanting sight, I created the figure below in R during the trip (with help from ChatGPT—and a lot of iterations 😁). It definitely helped pass the time while I was waiting (endlessly) at the airport and enduring nearly 10 hours on the plane!!!
Wishing everyone a Happy Chinese New Year of the Snake 🐍 2025!🧨🎇🎉🧧
Source code for creating the above figure:
library(ggplot2)
library(dplyr)
library(tibble)
Step 1: Create a red lantern by coding all the components that make up the lantern.
<- tibble(
lantern_body x = cos(seq(0, 2 * pi, length.out = 100)),
y = sin(seq(0, 2 * pi, length.out = 100)) * 0.6 # Oval shape
)
# Decorative gold band at the top and bottom
<- tibble(
gold_band_top x = c(-0.8, 0.8, 0.8, -0.8),
y = c(0.6, 0.6, 0.5, 0.5)
)
<- tibble(
gold_band_bottom x = c(-0.8, 0.8, 0.8, -0.8),
y = c(-0.5, -0.5, -0.6, -0.6)
)
# Tassels at the bottom
<- tibble(
tassels x = c(-0.5, -0.3, 0, 0.3, 0.5),
xend = c(-0.5, -0.3, 0, 0.3, 0.5),
y = rep(-0.6, 5),
yend = rep(-1.0, 5)
)
# Hanging string at the top
<- tibble(
hanging_string x = c(0, 0),
y = c(0.6, 0.75) # Longer hanging string for traditional look
)
# Chinese knot at the top
<- tibble(
chinese_knot x = c(0, 0.1, -0.1, 0),
y = c(0.75, 0.85, 0.85, 0.75)
)
# Star-like lights (small golden stars on the lantern)
<- tibble(
stars x = c(0.2, -0.5, 0.6, -0.4, 0.3),
y = c(0.5, 0.6, -0.4, -0.6, -0.7),
size = c(2, 1.5, 1.8, 1, 1.7)
)
# Additional decorative curved lines on the lantern body
<- tibble(
curved_lines x = c(0, 0.5, 1, 0.5, 0),
y = c(0.3, 0.5, 0.3, -0.5, -0.7)
)
# More golden dots along the body of the lantern
<- tibble(
dots x = c(-0.3, 0.4, -0.4, 0.5, 0.2),
y = c(0.4, 0.5, -0.4, -0.5, -0.6)
)
# Adding vertical semi-circle curved lines
<- tibble(
semi_circles_vertical x = c(-0.6, -0.4, 0, 0.4, 0.7), # X positions for vertical curves
y_start = rep(0.5, 5), # Start at the top of the lantern
y_end = rep(-0.5, 5), # End at the bottom of the lantern
curvature = c(-0.5, 0.5, -0.5, 0.5, -0.5) # Same curvature for a semi-circle effect
)
Step 2: Create a function to arrange the positions (x and y) of multiple lanterns within a single figure.
<- function(offset_x = 0, offset_y = 0) {
create_lantern_layers list(
# Lantern body
geom_polygon(
data = lantern_body %>% mutate(x = x + offset_x, y = y + offset_y),
aes(x = x, y = y),
fill = "red", color = "darkred", size = 1.5
),# Gold band at the top
geom_polygon(
data = gold_band_top %>% mutate(x = x + offset_x, y = y + offset_y),
aes(x = x, y = y),
fill = "gold", color = "goldenrod", size = 1.5
),# Gold band at the bottom
geom_polygon(
data = gold_band_bottom %>% mutate(x = x + offset_x, y = y + offset_y),
aes(x = x, y = y),
fill = "gold", color = "goldenrod", size = 1.5
),# Tassels at the bottom
geom_segment(
data = tassels %>% mutate(x = x + offset_x, xend = xend + offset_x, y = y + offset_y, yend = yend + offset_y),
aes(x = x, y = y, xend = xend, yend = yend),
color = "goldenrod", size = 1.5
),# Hanging string
geom_segment(
data = hanging_string %>% mutate(x = x + offset_x, y = y + offset_y),
aes(x = x, y = y, xend = x, yend = y + 0.2),
color = "gold", size = 1.2
),# Chinese knot at the top
geom_polygon(
data = chinese_knot %>% mutate(x = x + offset_x, y = y + offset_y),
aes(x = x, y = y),
fill = "gold", color = "goldenrod", size = 1.5
),# Tiny stars/lights around the lantern
geom_point(
data = stars %>% mutate(x = x + offset_x, y = y + offset_y),
aes(x = x, y = y, size = size),
color = "gold", alpha = 0.8,
show.legend = FALSE
),# Add vertical semi-circle curved lines on the lantern body
geom_curve(
aes(x = offset_x - 0.5, y = offset_y + 0.5, xend = offset_x - 0.5, yend = offset_y - 0.5),
curvature = 0.5, color = "yellow", size = 1, alpha = 0.8
),geom_curve(
aes(x = offset_x - 0.2, y = offset_y + 0.5, xend = offset_x - 0.2, yend = offset_y - 0.5),
curvature = 0.5, color = "yellow", size = 1, alpha = 0.8
),geom_curve(
aes(x = offset_x, y = offset_y + 0.5, xend = offset_x, yend = offset_y - 0.5),
curvature = 0, color = "yellow", size = 1, alpha = 0.8
),geom_curve(
aes(x = offset_x + 0.2, y = offset_y + 0.5, xend = offset_x + 0.2, yend = offset_y - 0.5),
curvature = -0.5, color = "yellow", size = 1, alpha = 0.8
),geom_curve(
aes(x = offset_x + 0.5, y = offset_y + 0.5, xend = offset_x + 0.5, yend = offset_y - 0.5),
curvature = -0.5, color = "yellow", size = 1, alpha = 0.8
),# Dots along the lantern body
geom_point(
data = dots %>% mutate(x = x + offset_x, y = y + offset_y),
aes(x = x, y = y),
color = "gold", size = 4, alpha = 0.8
)
) }
Step 3: Combine all lanterns into a single plot.
<- ggplot() +
lanterns_plot # Add eight lanterns with different offsets
create_lantern_layers(-1.5, 1) +
create_lantern_layers(1.5, 1) +
create_lantern_layers(-1.5, -1) +
create_lantern_layers(1.5, -1) +
create_lantern_layers(-1.5, -3) +
create_lantern_layers(1.5, -3) +
create_lantern_layers(-1.5, -5) +
create_lantern_layers(1.5, -5) +
# Fixed axis and black background
coord_fixed() +
theme_void() +
theme(panel.background = element_rect(fill = "black")) +
# Add the "Happy Chinese New Year!" message at the top
annotate("text", x = 0, y = 2.5, label = "Happy Chinese New Year 2025!!!", size = 14, color = "gold", fontface = "bold", hjust = 0.5)