As part of the tidytuesday challenge this week (2024-02-27), I made an interactive timeline plot about events happened on February 29 a.k.a. ‘Leap Day’. One can get their cursor on dots to see what happened on February 29 that year.
The interactive plot below is optimized for desktop viewing.
- R script to create the above plot is in tidytuesday/2024/2024-02-27/2024-02-27 (Leap Day).R.
- This is virtually the first time creating a plot with {plotly} package, and it took me a few hours to adjust to their grammars and rules. Let’s dive into my script!
1. Data Import
Loading a dataset from tidytuesday github repository as usual ~
tuesdata <- tidytuesdayR::tt_load('2024-02-27')
events <- tuesdata$events
2. Data Wrangling
2-1. num
column introduced
I introduced a num
column to assign a unique number to each row corresponding to a specific year. This distinction allows for separate plotting of each row.
events_data <- events |>
group_by(year) |>
mutate(num = row_number())
2-2. year_int
column was added
This is to group years into intervals of 25, with a filter applied to include only those after 1900.
events_data <- events_data |>
rowwise() |>
mutate(year_int = cut(year, breaks = seq(870, 2020, by = 25), labels = FALSE, include.lowest = TRUE) |>
as.factor()
) |>
filter(year >= 1900)
2-3. tooltip
column was added
For enhanced readability in the plot’s tooltip, I created a tooltip
column. Using the base::strwrap()
function, I formatted the event descriptions with line breaks at word boundaries (determined by the specified width
parameter). The lines were then combined using the paste()
function, incorporating <br>
HTML tags for line breaks. For those using tidyverse, stringr::str_wrap()
can be a good alternative for base::strwrap()
.
events_data <- events_data |>
rowwise() |>
mutate(tooltip = glue::glue("<b>In {year}:</b><br>{event}") |>
strwrap(width = 50) |>
paste(collapse = "<br>")) |>
mutate(year_ano = as.character(year))
2-4. Assign dataset to another object
I often assign a dataset to another object to be incorporated into a plot script. This makes it easier for me to make a test plot using test datasets.
main_data <- events_data
main_data
#> # A tibble: 28 × 6
#> # Rowwise:
#> year event num year_int tooltip year_ano
#> <dbl> <chr> <int> <fct> <chr> <chr>
#> 1 1908 James Madison University is founded at… 1 42 <b>In … 1908
#> 2 1912 The Piedra Movediza (Moving Stone) of … 1 42 <b>In … 1912
#> 3 1916 Tokelau is annexed by the United Kingd… 1 42 <b>In … 1916
#> 4 1916 In South Carolina, the minimum working… 2 42 <b>In … 1916
#> 5 1920 The Czechoslovak National Assembly ado… 1 42 <b>In … 1920
#> 6 1936 The February 26 Incident in Tokyo ends. 1 43 <b>In … 1936
#> 7 1940 For her performance as Mammy in Gone w… 1 43 <b>In … 1940
#> 8 1940 Finland initiates Winter War peace neg… 2 43 <b>In … 1940
#> 9 1940 In a ceremony held in Berkeley, Califo… 3 43 <b>In … 1940
#> 10 1944 The Admiralty Islands are invaded in O… 1 43 <b>In … 1944
#> # ℹ 18 more rows
3. Plotting with {plotly}
Before plotting, hline
function was created. It takes y
parameter to decide at which y coordinate the horizontal line will be plotted.
# To add horizontal line in plotly
hline <- function(y = 1, color = text_col) {
list(
type = "line",
x0 = 0,
x1 = 1,
xref = "paper",
y0 = y,
y1 = y,
line = list(color = color)
)
}
3-1. Plotly object plot_ly()
was created
Additional plotly layers can be added by passing the preceding object to next plotly function using the pipe operator (%>%
or |>
).
3-2. The function add_markers()
was called to add a scatter plot
- The x-axis represents the year of events, while the y-axis shows the unique number assigned to events ocurring in the same year. Different y-values are for separately visualizing events in the same year.
- The tilde (
~
) makes the subsequent object to be searched within the dataframe specified indata
parameter. That is,~year
,~num
, and~tooltip
refer to the corresponding columns in the tibblemain_data
. - The
marker
parameter defines the properties of points for the scatter plot. - Setting
color = ~year_int
ensures that colors are applied by the values inyear_int
column, showing the change of time by color spread. - Setting
hoverinfo = "text"
ensures that the tooltip text of each point will be those in atooltip
column inmain_data
, as shown intext = ~tooltip
. - The
hoverlabel
parameter defines the properties of hovertext or tooltip.
Click here to see more
event_plotly <- plot_ly() |>
add_markers(data = main_data,
type = "scatter", mode = "markers",
x = ~year,
y = ~num,
text = ~tooltip,
marker = list(size = 20,
line = list(
color = "black",
width = 1
)),
color = ~year_int,
colors = cols_vec_ly,
hoverinfo = "text",
showlegend = F,
hoverlabel = list(bgcolor = "black",
bordercolor = "transparent",
font = list(family = "oswald",
size = 15,
color = "white"
),
align = "left"
)
) |>
3-3. The add_annotations()
function was used
This is to incorporate the year of each event under in the plot, as well as subtitles and captions outside the plot.
Click here to see more.
add_annotations(data = filter(main_data, num == 1),
x = ~year,
y = ~(num - 0.2),
text = ~year,
font = list(family = main_font),
textangle = -90,
showarrow = F,
textposition = "bottom center"
) |>
add_annotations(xref = "paper",
yref = "paper",
x = -0.07, y = 1.09,
showarrow = FALSE,
text = subtitle_event_ly,
font = list(family = main_font,
color = text_col,
size = 20
)
) |>
add_annotations(xref = "paper",
yref = "paper",
x = -0.07, y = -0.2,
showarrow = FALSE,
text = caption_ly,
align = "left",
font = list(family = main_font,
color = text_col,
size = 15
)
) |>
3-4. Miscellaneous layout properties were specified using layout()
function
- Background colors were specified by
plot_bgcolor
andpaper_bgcolor
parameter. - The title of the plot is added with the
title()
parameter. - The properties of the x-axis and the y-axis were defined by
xaxis
andyaxis
parameter, respectively. - The horizontal line at
y = 1
were added byshapes
parameter, usinghline()
function defined above.
Click here to see more.
layout(plot_bgcolor = bg_col,
paper_bgcolor = bg_col,
title = list(text = title_event_ly,
x = 0.02, y = 0.97,
font = list(family = main_font,
color = text_col,
size = 30)),
xaxis = list(
zerolinecolor = text_col,
zerolinewidth = 3,
nticks = 6,
range = c(1895, 2025),
tick0 = 1900,
dtick = 25,
tickmode = "linear",
gridcolor = major_grid_col,
title = list(text = "<b>Year</b>",
font = list(family = main_font,
color = text_col,
size = 15)),
tickfont = list(family = main_font,
color = text_col)
),
yaxis = list(
title = "",
zeroline = FALSE,
showline = FALSE,
showticklabels = FALSE,
showgrid = FALSE,
range = c(-0.03, 3.5)
),
shapes = list(hline(y = 1)),
autosize = TRUE,
margin = list(b = 80, t = 70, r = 10)
)
event_plotly
3-5. The event_plotly
object was saved as a HTML file
This was done using the htmlwidgets::saveWidget()
function.
htmlwidgets::saveWidget(event_plotly, file = "event_plotly.html")
4. Add Font Dependency
If you are to embed your Plotly plot to website and use a custom font, it would be better to add a font dependency in the Plotly object. I initially encountered the issue that the plot displayed the custom font in R viewer and Chrome on my computer but not in browsers on other computers. It appeared that font information should be added to the Plotly object so that the saved HTML file would have details about the designated font. Thanks to the discussion raised by ‘fnavarro94’ and commented on by ‘cttnguyen’ for their guidance in solving the issue.
First, load a font and create a CSS string as shown in the following code.
## Fonts & Colors ---------------------------------------------------
font_add_google(name = "Oswald", family = "oswald")
showtext_auto()
main_font <- "oswald"
# Font dependency for plotly
oswald_file <- showtextdb::google_fonts("Oswald")$regular_url
font_css <- paste0(
"<style type = 'text/css'>",
"@font-face { ",
"font-family: 'oswald'; ",
"src: url('", oswald_file, "'); ",
"}",
"</style>")
Then, incorporate the CSS string to your Plotly object as the following script. htmltools::htmlDependency()
function is used to add HTML dependencies like CSS.
event_plotly$dependencies <- c(
event_plotly$dependencies,
list(
htmltools::htmlDependency(
name = "oswald",
version = "0",
src = "",
head = font_css
)
)
)
This ensures that your plot displays the designated font, regardless where it is viewed.
For those who are not familiar with CSS which is a style sheet language, CSS MDN WebDocs may be helpful to understand the basics of CSS.
5. Embed Plotly to Jekyll Blog
Since this github page was built using Jekyll, you may use iframe element to incorporate Plotly object into a post.
<iframe src="/files/interactive_page/event_plotly_post.html"
height="520px" width="100%" style="border:none;"></iframe>
Leave a comment