In this post, I’m taking deeper dive into a dataset of Pentomino puzzle solutions using R. This time, I’m switching gears from the sf package, but to explore graph theory concepts with tidygraph and ggraph. Why? Because Pentomino solutions aren’t just puzzles; they’re networks waiting to be uncovered! 🌐
Graphs and graph-based data structures with tidygraph and visualization with ggraph
Arranging Multiple Plots effortlessly with patchwork. The wrap_plots() function function was a lifesaver, sparing me from the monotony of typing plot1 + plot2 + … repeatedly! 🙌
Setups and Pakcages Used
# Load required librarieslibrary(tidyverse) # Data wrangling and general utilitieslibrary(ggraph) # Graph visualizationlibrary(tidygraph) # Graph data structure (tbl_graph) + graph algorithmslibrary(ggforce) # Extra geoms for ggplot2library(cowplot) # Additional plotting helperslibrary(patchwork) # Combine multiple ggplots effortlessly!
Original Solution Dataset
I’ve saved solution as csv file from earlier blog posts. So just retriving the dataset. Solution looks like below.
Reading Solution Dataset
### Read solution data frame from Github pento_sol <-read_csv("https://raw.githubusercontent.com/chichacha/pentomino/refs/heads/main/pentomino_solution.csv")sample_n(pento_sol, size=5) |> knitr::kable("markdown")
To make our graphs visually fun, I’m just using retro-inspired color palette and assign unique colors to each Pentomino piece.
Prepping Color Palette
# Just Prepping some color paletteretro <-c("#00A0B0", "#6A4A3C", "#CC333F", "#EB6841", "#EDC951")retro12 <-colorRampPalette(retro)(12)retro13 <-c(retro12,"#ffffff")#Assigning names to each color allows direct mapping with scale_color_manual() or scale_fill_manual()piece <-c("F","I","L","N","P","T","U","V","W","X","Y","Z")names(retro12) <- piecenames(retro13) <-c(piece,".")retro12 |>enframe() |>ggplot(aes(x=name,y=1)) +geom_tile(aes(fill=I(value))) +geom_text(aes(label=name), color="white",vjust=-0.5) +geom_text(aes(label=value), color="white",vjust=1, size=3) +theme_nothing()
Converting Solution to (x,y) Positions 📐
Next, we’ll transform each solution into (x, y) coordinates. This step is crucial for graph creation. I’ve listed a visualization & table of some 3x5 Pentomino solutions, mapped to their (x, y) position.
Converting Solution Texts to Data Frame with Coordinates
### Convert Solution to XY position data framepento_sol_df <- pento_sol |>mutate(solution_num =row_number()) |>mutate(sol_text =str_split(sol_text, " ")) |>unnest(sol_text) |>group_by(solution_num) |>mutate(y =row_number()) |>ungroup() |>mutate(sol_text =str_split(sol_text, "")) |>unnest(sol_text) |>group_by(solution_num, y) |>mutate(x =row_number()) |>ungroup()# Split the data into chunks programmaticallytables <- pento_sol_df |>filter(dim =="5×3", sol_idx ==1) |>select(dim, sol_text, x, y) |>group_split(x)pento_sol_df |>filter(dim =="5×3", sol_idx %in%c(1:6)) |>mutate(sol_idx=if_else(sol_idx==1, str_c("1. See Table Below"), as.character(sol_idx))) |>ggplot(aes(x=x,y=y)) +geom_point(aes(color=sol_text),size=10) +geom_text(aes(label=sol_text), color="#fffff3") +scale_color_manual(values=retro12, guide="none") +theme_minimal() +facet_wrap(~sol_idx,ncol=6) +coord_fixed() +scale_x_continuous(expand=expansion(add=1)) +scale_y_continuous(expand=expansion(add=1))
dim
sol_text
x
y
5×3
L
1
1
5×3
L
1
2
5×3
L
1
3
5×3
L
1
4
5×3
V
1
5
dim
sol_text
x
y
5×3
L
2
1
5×3
N
2
2
5×3
N
2
3
5×3
N
2
4
5×3
V
2
5
dim
sol_text
x
y
5×3
N
3
1
5×3
N
3
2
5×3
V
3
3
5×3
V
3
4
5×3
V
3
5
Storing the Solution in Nested Table
Use nest(.by = c(solution_num, dim)) to store each solution’s data in a list column. That way, each row in pento_min corresponds to one puzzle solution, containing the relevant (x, y, sol_text) data in a nested data frame.
Store solution in nested way
pento_min <- pento_sol_df |>filter(sol_text !=".") |># exclude the "." cellsselect(x, y, sol_text, solution_num, dim) |>nest(.by =c(solution_num, dim))
Creating Graphs with tidygraph & ggraph 📈
To visualize the connections between pieces, we’ll use tidygraph to create graph objects and ggraph for plotting.
Function: Data Frame to Graph Conversion
This function converts a solution’s data frame into a graph by identifying adjacent cells.