Load ggplot2 — provides the visualization functions and grants access to the built-in msleep dataset
2
Load msleep into the active environment from ggplot2 — makes the dataset available by name for all subsequent code
3
Inspect the structure — shows column names, R data types, and a preview of values for all 11 variables
4
Summarise four key numeric columns — returns min, Q1, median, mean, Q3, and max, plus NA counts for each
tibble [83 × 11] (S3: tbl_df/tbl/data.frame)
$ name : chr [1:83] "Cheetah" "Owl monkey" "Mountain beaver" "Greater short-tailed shrew" ...
$ genus : chr [1:83] "Acinonyx" "Aotus" "Aplodontia" "Blarina" ...
$ vore : chr [1:83] "carni" "omni" "herbi" "omni" ...
$ order : chr [1:83] "Carnivora" "Primates" "Rodentia" "Soricomorpha" ...
$ conservation: chr [1:83] "lc" NA "nt" "lc" ...
$ sleep_total : num [1:83] 12.1 17 14.4 14.9 4 14.4 8.7 7 10.1 3 ...
$ sleep_rem : num [1:83] NA 1.8 2.4 2.3 0.7 2.2 1.4 NA 2.9 NA ...
$ sleep_cycle : num [1:83] NA NA NA 0.133 0.667 ...
$ awake : num [1:83] 11.9 7 9.6 9.1 20 9.6 15.3 17 13.9 21 ...
$ brainwt : num [1:83] NA 0.0155 NA 0.00029 0.423 NA NA NA 0.07 0.0982 ...
$ bodywt : num [1:83] 50 0.48 1.35 0.019 600 ...
sleep_total awake bodywt brainwt
Min. : 1.90 Min. : 4.10 Min. : 0.005 Min. :0.00014
1st Qu.: 7.85 1st Qu.:10.25 1st Qu.: 0.174 1st Qu.:0.00290
Median :10.10 Median :13.90 Median : 1.670 Median :0.01240
Mean :10.43 Mean :13.57 Mean : 166.136 Mean :0.28158
3rd Qu.:13.75 3rd Qu.:16.15 3rd Qu.: 41.750 3rd Qu.:0.12550
Max. :19.90 Max. :22.10 Max. :6654.000 Max. :5.71200
NA's :27
1. Environment Setup & Data Processing
First, let’s load the necessary libraries and organize our data. We will calculate the average sleep (mean_sleep) grouped by order.
Show the code
library(tidyverse)
1
Load the tidyverse — brings in dplyr for data wrangling, forcats for factor reordering, and ggplot2 for the full plot pipeline
1.1 Grouping & Summarizing
We use group_by(order) to categorize the animals and summarise() to calculate the average sleep for each group.
Show the code
# Data Preparationsleep_data <- msleep %>%group_by(order) %>%summarise(mean_sleep =mean(sleep_total))
1
Pipe msleep into a chain of transformations and store the summarised result as sleep_data
2
Partition all 83 rows by taxonomic order — each unique order becomes a separate group for downstream calculations
3
Collapse each group to a single row containing mean_sleep, the arithmetic mean of sleep_total for that order
1.2 Factor Reordering
To make the visualization aesthetically pleasing, we use fct_reorder(). This sorts the categories from lowest to highest based on the mean sleep values.
Overwrite sleep_data in place — appends the reordering step without creating a new object
2
fct_reorder() converts order to a factor whose levels are sorted by mean_sleep ascending — ggplot2 reads factor levels for axis ordering, so this produces a naturally sorted lollipop chart
2. Step-by-Step Plot Evolution
Step 1: The Basic Canvas
We start by defining the X and Y axes and adding labels.
Show the code
plot_step1 <- sleep_data %>%ggplot(aes(order, mean_sleep)) +labs(title ="Average Sleep Time of Mammals by Order",x ="",y ="Hours")plot_step1
1
Initialize the canvas — order to the x-axis and mean_sleep to the y-axis; no geometry is added yet so only the coordinate system and axes render
2
Attach labels — the empty string for x suppresses the redundant axis title while y = "Hours" clarifies the measurement unit
Step 2: Styling (Custom Theme & Dark Mode)
Now we will darken the background and change text colors to create a “Neon Vibe.”
2.1 Axis Labels Style
We will tilt the X-axis labels by 45° for better readability and apply specific hex codes for color.
Remove all major grid lines — a clean black panel is more visually impactful than gridded clutter on a dark theme
2
Remove all minor grid lines — keeps the panel completely bare so only the lollipop geometry draws the eye
3
Hide the legend — the sorted x-axis labels already identify each mammal order, making a legend redundant
Step 3: The Lollipop Base (Reference Line & Sticks)
We add a benchmark line for the overall average sleep and connecting “sticks” for each point.
Show the code
plot_step3 <- plot_step2 +# Horizontal line for overall average sleepgeom_hline(yintercept =mean(msleep$sleep_total),color ="#d580ff", linewidth =1) +# Segments to show distance from the mean linegeom_segment(aes(x = order,y =mean(msleep$sleep_total), xend = order, yend = mean_sleep), color ="#d580ff")plot_step3
1
Draw a horizontal reference line at the grand mean of all 83 mammals’ sleep — serves as the shared baseline that each lollipop stick grows from or shrinks toward
2
Draw vertical segments from the grand mean up (or down) to each order’s mean_sleep — these are the “sticks” of the lollipop, visually encoding how far each order deviates from the average
Step 4: Adding Color Gradient Points
We place points at the end of the sticks that change color based on the amount of sleep.
Place filled circles at the tip of every stick with size = 5; mapping color to mean_sleep enables a gradient that encodes sleep duration as a second visual channel
2
Define the gradient range — orders with the least sleep get deep purple while the highest-sleep orders receive bright lavender #eabfff, creating a natural glow effect
Step 5: The Final Touch (Annotations & Arrows)
Finally, we add an explanatory text and a curved arrow for better storytelling.
Show the code
final_plot <- plot_step4 +# Adding explanatory textannotate("text", x =4, y =max(msleep$sleep_total) -4,label ="Average sleep\nfor all mammals", color ="#eabfff", size =4, fontface ="bold", hjust =0) +# Adding a curved arrow pointing to the mean linegeom_curve(aes(x =3.7, y =max(msleep$sleep_total) -5,xend =1.5, yend =mean(msleep$sleep_total)), color ="#eabfff", curvature =0.5, arrow =arrow(length =unit(0.07, "npc"), type ="open"))final_plot
1
Place a two-line bold label at x = 4 near the top of the chart; hjust = 0 left-aligns the text from that anchor so it reads naturally into open whitespace
2
Draw a curved arrow from just below the text annotation down to the mean reference line — guides the reader’s eye from the label to the exact benchmark it describes
Key Visual Toolkit (Cheat Sheet)
fct_reorder(): Used to sort categories based on numeric values.
theme(panel.background = ...): Customizes the internal plot background.
geom_segment(): Creates the “sticks” for the lollipop chart.
**geom_curve() & annotate()**: Highlights or explains specific parts of the graph.
scale_color_gradient(): Shows color shifts for continuous data.
Congratulations! You have successfully transformed a simple plot into a high-end visualization.