| ---
|
| title: "Customization Tutorial"
|
| subtitle: "Colors, themes, and advanced styling options"
|
| ---
|
|
|
| ```{r}
|
| #| label: setup
|
| #| include: false
|
| # Flexible path: works from project root (Quarto) or quarto/tutorials/ (RStudio interactive)
|
| setup_path <- if (file.exists("quarto/_setup.R")) "quarto/_setup.R" else "../_setup.R"
|
| source(setup_path)
|
| ```
|
|
|
| ## Color Palettes
|
|
|
| jigsawR works seamlessly with all viridis color palettes.
|
|
|
| ### Viridis Options
|
|
|
| ```{r}
|
| #| label: viridis-palettes
|
| #| fig-align: center
|
| #| fig-height: 6
|
| make_palette_demo <- function(pal) {
|
| ggplot() +
|
| geom_puzzle_hex(
|
| aes(fill = after_stat(piece_id)),
|
| rings = 3, seed = 42
|
| ) +
|
| scale_fill_viridis_c(option = pal, guide = "none") +
|
| coord_fixed() +
|
| theme_puzzle() +
|
| labs(title = pal)
|
| }
|
|
|
| print((make_palette_demo("viridis") + make_palette_demo("magma") + make_palette_demo("plasma")) /
|
| (make_palette_demo("inferno") + make_palette_demo("cividis") + make_palette_demo("turbo")))
|
| ```
|
|
|
| ### Custom Color Scales
|
|
|
| Use any ggplot2 color scale:
|
|
|
| ```{r}
|
| #| label: custom-colors
|
| #| layout-ncol: 2
|
| #| fig-cap:
|
| #| - "Gradient Blue to Cyan"
|
| #| - "Brewer Spectral"
|
|
|
| # Custom gradient
|
| print(ggplot() +
|
| geom_puzzle_rect(
|
| aes(fill = after_stat(piece_id)),
|
| cols = 4, rows = 3,
|
| width = 240, height = 180,
|
| seed = 42
|
| ) +
|
| scale_fill_gradient(
|
| low = "#2193b0",
|
| high = "#6dd5ed",
|
| guide = "none"
|
| ) +
|
| coord_fixed() +
|
| theme_puzzle() +
|
| labs(title = "Gradient"))
|
|
|
| # Brewer palette
|
| print(ggplot() +
|
| geom_puzzle_rect(
|
| aes(fill = factor(after_stat(piece_id))),
|
| cols = 4, rows = 3,
|
| width = 240, height = 180,
|
| seed = 42
|
| ) +
|
| scale_fill_brewer(palette = "Spectral", guide = "none") +
|
| coord_fixed() +
|
| theme_puzzle() +
|
| labs(title = "Brewer"))
|
| ```
|
|
|
| ## Themes
|
|
|
| ### Minimal Themes
|
|
|
| ```{r}
|
| #| label: minimal-themes
|
| #| layout-ncol: 2
|
| #| fig-cap:
|
| #| - "theme_puzzle()"
|
| #| - "theme_minimal()"
|
|
|
| print(ggplot() +
|
| geom_puzzle_hex(
|
| aes(fill = after_stat(piece_id)),
|
| rings = 2, diameter = 150, seed = 42
|
| ) +
|
| scale_fill_viridis_c(guide = "none") +
|
| coord_fixed() +
|
| theme_puzzle() +
|
| labs(title = "theme_puzzle()"))
|
|
|
| print(ggplot() +
|
| geom_puzzle_hex(
|
| aes(fill = after_stat(piece_id)),
|
| rings = 2, diameter = 150, seed = 42
|
| ) +
|
| scale_fill_viridis_c(name = "Piece") +
|
| coord_fixed() +
|
| theme_minimal() +
|
| labs(title = "theme_minimal()"))
|
| ```
|
|
|
| ### Dark Themes
|
|
|
| ```{r}
|
| #| label: dark-theme
|
| #| fig-align: center
|
| ggplot() +
|
| geom_puzzle_hex(
|
| aes(fill = after_stat(piece_id)),
|
| rings = 3, diameter = 200, seed = 42
|
| ) +
|
| scale_fill_viridis_c(option = "plasma") +
|
| coord_fixed() +
|
| theme_dark() +
|
| theme(
|
| panel.grid = element_blank(),
|
| plot.background = element_rect(fill = "#1a1a1a"),
|
| legend.background = element_rect(fill = "#1a1a1a"),
|
| legend.text = element_text(color = "white"),
|
| legend.title = element_text(color = "white")
|
| ) +
|
| labs(title = "Dark Theme", fill = "Piece ID")
|
| ```
|
|
|
| ### Custom Themes
|
|
|
| ```{r}
|
| #| label: custom-theme
|
| #| fig-align: center
|
| # Extend theme_puzzle() with custom settings
|
| theme_puzzle_custom <- function() {
|
| theme_puzzle() +
|
| theme(
|
| plot.title = element_text(
|
| hjust = 0.5,
|
| size = 16,
|
| face = "bold",
|
| margin = margin(b = 10)
|
| ),
|
| plot.subtitle = element_text(
|
| hjust = 0.5,
|
| size = 12,
|
| color = "gray50",
|
| margin = margin(b = 20)
|
| ),
|
| legend.position = "bottom",
|
| legend.title = element_text(size = 10),
|
| legend.text = element_text(size = 8),
|
| plot.margin = margin(20, 20, 20, 20)
|
| )
|
| }
|
|
|
| ggplot() +
|
| geom_puzzle_conc(
|
| aes(fill = after_stat(ring)),
|
| rings = 4, diameter = 250, seed = 42
|
| ) +
|
| scale_fill_viridis_c(option = "cividis", name = "Ring") +
|
| coord_fixed() +
|
| theme_puzzle_custom() +
|
| labs(
|
| title = "Concentric Puzzle",
|
| subtitle = "4 rings, 250mm diameter"
|
| )
|
| ```
|
|
|
| ## Legends
|
|
|
| ### Legend Position
|
|
|
| ```{r}
|
| #| label: legend-position
|
| #| layout-ncol: 2
|
| #| fig-cap:
|
| #| - "Legend bottom"
|
| #| - "Legend inside"
|
|
|
| # Bottom legend
|
| print(ggplot() +
|
| geom_puzzle_rect(
|
| aes(fill = after_stat(piece_id)),
|
| cols = 4, rows = 3,
|
| width = 200, height = 150,
|
| seed = 42
|
| ) +
|
| scale_fill_viridis_c(name = "Piece") +
|
| coord_fixed() +
|
| theme_minimal() +
|
| labs(title = "Bottom") +
|
| theme(legend.position = "bottom"))
|
|
|
| # Inside plot
|
| print(ggplot() +
|
| geom_puzzle_rect(
|
| aes(fill = after_stat(piece_id)),
|
| cols = 4, rows = 3,
|
| width = 200, height = 150,
|
| seed = 42
|
| ) +
|
| scale_fill_viridis_c(name = "Piece") +
|
| coord_fixed() +
|
| theme_minimal() +
|
| labs(title = "Inside") +
|
| theme(
|
| legend.position = c(0.85, 0.85),
|
| legend.background = element_rect(fill = "white", color = "gray80")
|
| ))
|
| ```
|
|
|
| ### Custom Legend Labels
|
|
|
| ```{r}
|
| #| label: custom-legend-labels
|
| #| fig-align: center
|
| ggplot() +
|
| geom_puzzle_conc(
|
| aes(fill = after_stat(ring)),
|
| rings = 3, diameter = 200, seed = 42
|
| ) +
|
| scale_fill_viridis_c(
|
| option = "magma",
|
| name = "Ring Number",
|
| labels = c("Center", "Ring 1", "Ring 2"),
|
| breaks = c(0, 1, 2)
|
| ) +
|
| coord_fixed() +
|
| theme_minimal() +
|
| theme(legend.position = "right")
|
| ```
|
|
|
| ## Annotations
|
|
|
| ### Add Text
|
|
|
| ```{r}
|
| #| label: annotation-text
|
| #| fig-align: center
|
| ggplot() +
|
| geom_puzzle_hex(
|
| aes(fill = after_stat(ring)),
|
| rings = 3, diameter = 250, seed = 42
|
| ) +
|
| annotate(
|
| "text",
|
| x = 0, y = 0,
|
| label = "CENTER",
|
| size = 5,
|
| fontface = "bold",
|
| color = "white"
|
| ) +
|
| scale_fill_viridis_c(option = "plasma", guide = "none") +
|
| coord_fixed() +
|
| theme_puzzle() +
|
| labs(title = "Annotated puzzle")
|
| ```
|
|
|
| ### Add Labels with geom_text
|
|
|
| ```{r}
|
| #| label: annotation-labels
|
| #| fig-align: center
|
| # Get piece data
|
| puzzle <- generate_puzzle(
|
| type = "hexagonal",
|
| grid = c(2),
|
| size = c(150),
|
| seed = 42
|
| )
|
|
|
| ggplot() +
|
| geom_puzzle_hex(
|
| aes(fill = after_stat(piece_id)),
|
| rings = 2, diameter = 150, seed = 42
|
| ) +
|
| scale_fill_viridis_c(guide = "none") +
|
| coord_fixed() +
|
| theme_puzzle() +
|
| labs(title = "7 Hexagonal Pieces")
|
| ```
|
|
|
| ## Borders and Outlines
|
|
|
| ### Add Borders
|
|
|
| ```{r}
|
| #| label: borders-basic
|
| #| fig-align: center
|
| ggplot() +
|
| geom_puzzle_rect(
|
| aes(fill = after_stat(piece_id)),
|
| cols = 3, rows = 3,
|
| width = 200, height = 200,
|
| seed = 42,
|
| color = "black", # Border color
|
| linewidth = 0.5 # Border width
|
| ) +
|
| scale_fill_viridis_c(option = "plasma", guide = "none") +
|
| coord_fixed() +
|
| theme_puzzle() +
|
| labs(title = "With borders")
|
| ```
|
|
|
| ### Thick Borders for Emphasis
|
|
|
| ```{r}
|
| #| label: borders-thick
|
| #| fig-align: center
|
|
|
| make_border_demo <- function(lw, label) {
|
| ggplot() +
|
| geom_puzzle_hex(
|
| aes(fill = after_stat(piece_id)),
|
| rings = 2, seed = 42,
|
| color = "white",
|
| linewidth = lw
|
| ) +
|
| scale_fill_viridis_c(option = "magma", guide = "none") +
|
| coord_fixed() +
|
| theme_puzzle() +
|
| labs(title = label)
|
| }
|
|
|
| print(make_border_demo(0.25, "Thin borders") + make_border_demo(1.5, "Thick borders"))
|
| ```
|
|
|
| ## Alpha Transparency
|
|
|
| ```{r}
|
| #| label: alpha-transparency
|
| #| fig-align: center
|
|
|
| make_alpha_demo <- function(a, label) {
|
| ggplot() +
|
| geom_puzzle_voronoi(
|
| aes(fill = after_stat(piece_id)),
|
| n_cells = 15,
|
| seed = 42,
|
| alpha = a
|
| ) +
|
| scale_fill_viridis_c(option = "turbo", guide = "none") +
|
| coord_fixed() +
|
| theme_puzzle() +
|
| labs(title = label)
|
| }
|
|
|
| print(make_alpha_demo(1.0, "alpha = 1.0 (opaque)") + make_alpha_demo(0.5, "alpha = 0.5 (semi-transparent)"))
|
| ```
|
|
|
| ## Saving High-Quality Output
|
|
|
| ### PNG (Raster)
|
|
|
| ```{r}
|
| #| label: save-png
|
| #| fig-align: center
|
| p <- ggplot() +
|
| geom_puzzle_hex(
|
| aes(fill = after_stat(piece_id)),
|
| rings = 4, diameter = 300, seed = 42
|
| ) +
|
| scale_fill_viridis_c(option = "plasma", guide = "none") +
|
| coord_fixed() +
|
| theme_puzzle()
|
| print(p)
|
|
|
| # ggsave("puzzle.png", p, width = 8, height = 8, dpi = 150)
|
| # ggsave("puzzle_hq.png", p, width = 8, height = 8, dpi = 300)
|
| # ggsave("puzzle_print.png", p, width = 12, height = 12, dpi = 600)
|
| ```
|
|
|
| ### SVG (Vector)
|
|
|
| ```{r}
|
| #| label: save-svg
|
| #| eval: false
|
| # Vector format - infinite scalability
|
| ggsave("puzzle.svg", p, width = 8, height = 8)
|
| ```
|
|
|
| ### PDF (Vector, Print-ready)
|
|
|
| ```{r}
|
| #| label: save-pdf
|
| #| eval: false
|
| ggsave("puzzle.pdf", p, width = 8, height = 8)
|
| ```
|
|
|
| ## Summary
|
|
|
| You've learned:
|
|
|
| - ✅ Using viridis and custom color palettes
|
| - ✅ Applying and customizing themes
|
| - ✅ Configuring legends
|
| - ✅ Adding annotations and labels
|
| - ✅ Using borders and transparency
|
| - ✅ Saving high-quality output
|
|
|
| ## Next Steps
|
|
|
| - [Fusion Groups Tutorial](fusion-groups.qmd) - Merge pieces
|
| - [Gallery](../gallery/rectangular.qmd) - More visual examples
|
| |