# Getting Started with mapycusmaximus

## Introduction

mapycusmaximus brings fisheye transformations to R’s spatial ecosystem. Just as `ggplot2` transforms how we visualize data and `dplyr` transforms how we manipulate it, mapycusmaximus transforms how we view geographic space—allowing you to magnify local detail while preserving regional context.

The package implements the Focus-Glue-Context (FGC) model, a three-zone radial transformation that:

- Magnifies features in the focus region (like zooming in)
- Smoothly transitions through the glue zone (preventing jarring distortions)
- Preserves the outer context (maintaining geographic orientation)

This vignette will show you how to use mapycusmaximus with real spatial data, following tidyverse principles of working with data.

    library(mapycusmaximus)
    library(sf)
    library(ggplot2)

    # Use a minimal theme for clean visualizations
    theme_set(theme_minimal())

## Your First Fisheye

Let’s start with the built-in Victoria LGA dataset. The goal is to magnify Melbourne while keeping the rest of Victoria visible.

    # Examine the data
    data(vic)
    vic
    #> Simple feature collection with 79 features and 1 field
    #> Geometry type: MULTIPOLYGON
    #> Dimension:     XY
    #> Bounding box:  xmin: 140.9619 ymin: -39.13442 xmax: 149.9762 ymax: -33.98064
    #> Geodetic CRS:  WGS 84
    #> First 10 features:
    #>      LGA_NAME                       geometry
    #> 1      ALPINE MULTIPOLYGON (((146.7238 -3...
    #> 2      ARARAT MULTIPOLYGON (((143.0904 -3...
    #> 3    BALLARAT MULTIPOLYGON (((143.9239 -3...
    #> 4     BANYULE MULTIPOLYGON (((145.1342 -3...
    #> 5  BASS COAST MULTIPOLYGON (((145.3214 -3...
    #> 6     BAW BAW MULTIPOLYGON (((145.7643 -3...
    #> 7     BAYSIDE MULTIPOLYGON (((144.986 -37...
    #> 8     BENALLA MULTIPOLYGON (((146.1131 -3...
    #> 9  BOROONDARA MULTIPOLYGON (((145.1039 -3...
    #> 10   BRIMBANK MULTIPOLYGON (((144.8829 -3...

The simplest fisheye uses defaults and automatically determines the center:

    # Apply fisheye transformation
    vic_warped <- sf_fisheye(
      vic,
      r_in = 0.3,        # Focus radius
      r_out = 0.6,       # Glue boundary
      zoom_factor = 2,   # Magnification strength
      squeeze_factor = 0.35
    )

    # Visualize with ggplot2
    ggplot(vic_warped) +
      geom_sf(fill = "grey90", color = "white", linewidth = 0.3) +
      labs(title = "Victoria LGAs with Default Fisheye")

A basic fisheye transformation of Victoria’s LGAs

That’s it! But to really control the transformation, you’ll want to specify a focus point.

## Specifying the Focus Point

The fisheye center determines what gets magnified. There are several ways to specify it:

### Using a Geometry

The most natural approach—pass an `sf` object and mapycusmaximus uses its centroid:

    # Extract Melbourne CBD as the focus
    melbourne <- vic[vic$LGA_NAME == "MELBOURNE", ]

    vic_melbourne <- sf_fisheye(
      vic,
      center = melbourne,      # Centroid becomes the warp center
      r_in = 0.34,
      r_out = 0.60,
      zoom_factor = 15,
      squeeze_factor = 0.35
    )

    ggplot() +
      geom_sf(data = vic_melbourne, fill = "grey92", color = "white", linewidth = 0.2) +
      geom_sf(data = melbourne, fill = NA, color = "tomato", linewidth = 0.8) +
      labs(title = "Melbourne CBD Magnified",
           subtitle = "Focus defined by Melbourne LGA geometry")

Fisheye centered on Melbourne CBD

### Using Longitude/Latitude

Specify coordinates directly in WGS84:

    # Melbourne CBD coordinates (WGS84)
    melb_coords <- c(144.9631, -37.8136)

    vic_coords <- sf_fisheye(
      vic,
      center = melb_coords,
      center_crs = "EPSG:4326",   # Explicitly state CRS
      r_in = 0.30,
      r_out = 0.55,
      zoom_factor = 12,
      squeeze_factor = 0.30
    )

    ggplot(vic_coords) +
      geom_sf(fill = "grey92", color = "white", linewidth = 0.2) +
      labs(title = "Center Specified as Lon/Lat",
           subtitle = "Coordinates: 144.96°E, 37.81°S")

Fisheye using lon/lat coordinates

### Using Projected Coordinates

If you’re already working in a projected CRS, pass coordinates directly:

    # Example: coordinates in the working CRS (meters)
    vic_projected <- sf_fisheye(
      vic,
      cx = 321000,      # Easting (meters)
      cy = 5813000,     # Northing (meters)
      r_in = 0.3,
      r_out = 0.6,
      zoom_factor = 10,
      squeeze_factor = 0.35
    )

## Understanding Parameters

The transformation is controlled by four key parameters:

### Focus and Glue Radii

`r_in` and `r_out` define the transformation zones in normalized space (roughly -1 to 1):

    # Small focus, narrow glue
    vic_tight <- sf_fisheye(vic, center = melbourne, r_in = 0.2, r_out = 0.3,
                            zoom_factor = 8, squeeze_factor = 0.35)

    # Large focus, wide glue
    vic_wide <- sf_fisheye(vic, center = melbourne, r_in = 0.4, r_out = 0.7,
                           zoom_factor = 8, squeeze_factor = 0.35)

    p1 <- ggplot(vic_tight) +
      geom_sf(fill = "grey90", color = "white", linewidth = 0.2) +
      labs(title = "Tight Focus (r_in=0.2, r_out=0.3)")

    p2 <- ggplot(vic_wide) +
      geom_sf(fill = "grey90", color = "white", linewidth = 0.2) +
      labs(title = "Wide Focus (r_in=0.4, r_out=0.7)")

    # Display side by side (requires patchwork or cowplot)
    # p1 + p2
    p1

Effect of different radius settings

    p2

Effect of different radius settings

### Zoom Factor

Controls magnification strength inside the focus:

    # Gentle zoom
    vic_gentle <- sf_fisheye(vic, center = melbourne, r_in = 0.3, r_out = 0.5,
                             zoom_factor = 3, squeeze_factor = 0.35)

    # Aggressive zoom
    vic_aggressive <- sf_fisheye(vic, center = melbourne, r_in = 0.3, r_out = 0.5,
                                 zoom_factor = 20, squeeze_factor = 0.35)

    ggplot(vic_gentle) +
      geom_sf(fill = "grey90", color = "white", linewidth = 0.2) +
      labs(title = "Gentle Magnification (zoom = 3)")

Effect of zoom factor

    ggplot(vic_aggressive) +
      geom_sf(fill = "grey90", color = "white", linewidth = 0.2) +
      labs(title = "Strong Magnification (zoom = 20)")

Effect of zoom factor

### Squeeze Factor

Controls compression in the glue zone (0 to 1):

    # Minimal squeeze (wider glue transition)
    vic_loose <- sf_fisheye(vic, center = melbourne, r_in = 0.3, r_out = 0.5,
                            zoom_factor = 8, squeeze_factor = 0.1)

    # Strong squeeze (narrow glue transition)
    vic_tight_squeeze <- sf_fisheye(vic, center = melbourne, r_in = 0.3, r_out = 0.5,
                                    zoom_factor = 8, squeeze_factor = 0.8)

    ggplot(vic_loose) +
      geom_sf(fill = "grey90", color = "white", linewidth = 0.2) +
      labs(title = "Loose Squeeze (0.1)")

    ggplot(vic_tight_squeeze) +
      geom_sf(fill = "grey90", color = "white", linewidth = 0.2) +
      labs(title = "Tight Squeeze (0.8)")

## Working with Multiple Layers

When you have multiple layers (points, lines, polygons), transform them together to ensure alignment:

    # Create centroids as a point layer
    centroids <- st_centroid(vic)

    # Add a layer identifier to each
    vic_layer <- vic |>
      dplyr::mutate(layer = "polygon")

    centroids_layer <- centroids |>
      dplyr::mutate(layer = "centroid")

    # Combine layers before transformation
    both_layers <- rbind(
      vic_layer[, c("LGA_NAME", "geometry", "layer")],
      centroids_layer[, c("LGA_NAME", "geometry", "layer")]
    )

    # Apply fisheye once to combined data
    both_warped <- sf_fisheye(
      both_layers,
      center = melbourne,
      r_in = 0.34,
      r_out = 0.60,
      zoom_factor = 12,
      squeeze_factor = 0.35
    )

    # Separate for plotting
    polygons_warped <- both_warped[both_warped$layer == "polygon", ]
    points_warped <- both_warped[both_warped$layer == "centroid", ]

    # Plot together
    ggplot() +
      geom_sf(data = polygons_warped, fill = "grey92", color = "white",
              linewidth = 0.2) +
      geom_sf(data = points_warped, color = "#2b6cb0", size = 1.2, alpha = 0.7) +
      labs(title = "Aligned Layers: Polygons and Centroids",
           subtitle = "Transformed together to ensure perfect alignment")

Multiple aligned layers with fisheye transformation

Why combine first? When layers are transformed separately, they may have different bounding boxes, leading to slightly different normalized coordinates and misalignment.

## Projection Handling

mapycusmaximus is projection-aware and handles CRS transformations automatically:

### Geographic to Projected

If your data is in longitude/latitude, the package automatically selects an appropriate projected CRS:

    # Create data in WGS84
    vic_lonlat <- st_transform(vic, "EPSG:4326")
    st_crs(vic_lonlat)$proj4string
    #> [1] "+proj=longlat +datum=WGS84 +no_defs"

    # Apply fisheye - auto-projects to GDA2020/MGA55 for Victoria
    vic_auto <- sf_fisheye(
      vic_lonlat,
      center = melbourne,
      r_in = 0.3,
      r_out = 0.5,
      zoom_factor = 10,
      squeeze_factor = 0.35
    )

    # Original CRS is restored
    st_crs(vic_auto)$proj4string
    #> [1] "+proj=longlat +datum=WGS84 +no_defs"

The package uses sensible defaults: - Victoria region → EPSG:7855 (GDA2020 / MGA Zone 55) - Other areas → UTM zones based on centroid

### Custom Projection

Override the automatic selection with `target_crs`:

    vic_custom <- sf_fisheye(
      vic_lonlat,
      center = melbourne,
      target_crs = "EPSG:3111",  # VicGrid
      r_in = 0.3,
      r_out = 0.5,
      zoom_factor = 10,
      squeeze_factor = 0.35
    )

## Advanced: Grid Diagnostics

For understanding the transformation itself, use the low-level `fisheye_fgc()` function with test grids:

    # Create a regular grid
    grid <- create_test_grid(range = c(-1, 1), spacing = 0.1)

    # Apply transformation
    warped <- fisheye_fgc(
      grid,
      r_in = 0.34,
      r_out = 0.5,
      zoom_factor = 1.3,
      squeeze_factor = 0.5
    )

    # Visualize the transformation
    plot_fisheye_fgc(grid, warped, r_in = 0.34, r_out = 0.5)

Understanding the FGC transformation with a test grid

The visualization shows: - Red zone: Focus (magnified) - Blue zone: Glue (transitional compression) - Yellow zone: Context (unchanged)

## Real-World Example: Metropolitan Focus

Here’s a complete workflow showing how to emphasize a metro area while maintaining state context:

    # 1. Define the metropolitan region
    metro_lgas <- c("MELBOURNE", "PORT PHILLIP", "STONNINGTON", "YARRA",
                    "MARIBYRNONG", "MOONEE VALLEY", "BOROONDARA",
                    "GLEN EIRA", "BAYSIDE")

    metro_region <- vic[vic$LGA_NAME %in% metro_lgas, ]
    metro_center <- st_union(metro_region) |> st_centroid()

    # 2. Add a population indicator (example)
    vic_pop <- vic |>
      dplyr::mutate(is_metro = LGA_NAME %in% metro_lgas)

    # 3. Apply fisheye
    vic_focused <- sf_fisheye(
      vic_pop,
      center = metro_center,
      r_in = 0.25,
      r_out = 0.40,
      zoom_factor = 12,
      squeeze_factor = 0.35
    )

    # 4. Create publication-ready plot
    ggplot(vic_focused) +
      geom_sf(aes(fill = is_metro), color = "white", linewidth = 0.2) +
      scale_fill_manual(
        values = c("TRUE" = "#d95f02", "FALSE" = "grey85"),
        labels = c("Metropolitan", "Regional"),
        name = NULL
      ) +
      theme_minimal() +
      theme(
        legend.position = c(0.85, 0.15),
        legend.background = element_rect(fill = "white", color = "grey70"),
        panel.grid = element_blank()
      ) +
      labs(
        title = "Metropolitan Melbourne with Regional Context",
        subtitle = "Fisheye magnification preserves spatial relationships",
        caption = "Transformation: r_in = 0.25, r_out = 0.40, zoom = 12"
      )

Complete workflow: Metropolitan Melbourne in Victorian context

## Best Practices

### Parameter Selection

Start conservative and iterate:

    # Start here
    sf_fisheye(data, r_in = 0.3, r_out = 0.5, zoom_factor = 5, squeeze_factor = 0.35)

    # Too distorted? Reduce zoom or widen glue
    sf_fisheye(data, r_in = 0.3, r_out = 0.6, zoom_factor = 3, squeeze_factor = 0.35)

    # Need more magnification? Increase zoom gradually
    sf_fisheye(data, r_in = 0.3, r_out = 0.5, zoom_factor = 10, squeeze_factor = 0.35)

### Layer Alignment

Always combine layers before transformation:

    # Good: Single transformation
    combined <- rbind(layer1, layer2, layer3)
    warped <- sf_fisheye(combined, ...)

    # Avoid: Separate transformations
    layer1_warped <- sf_fisheye(layer1, ...)  # Different normalization
    layer2_warped <- sf_fisheye(layer2, ...)  # May not align perfectly

### Reproducibility

Be explicit about parameters for reproducible analyses:

    # Explicit and reproducible
    result <- sf_fisheye(
      data,
      center = st_point(c(144.9631, -37.8136)),
      center_crs = "EPSG:4326",
      target_crs = "EPSG:7855",
      r_in = 0.34,
      r_out = 0.60,
      zoom_factor = 12,
      squeeze_factor = 0.35,
      preserve_aspect = TRUE,
      revolution = 0
    )

## Performance Tips

For large datasets:

1. Simplify geometries before transformation if appropriate
2. Remove empty geometries (done automatically, but pre-filtering helps)
3. Transform once, not repeatedly in a loop

    # Pre-process large data
    data_clean <- data |>
      filter(!st_is_empty(geometry)) |>
      st_simplify(dTolerance = 100)  # Adjust tolerance as needed

    # Transform once
    data_warped <- sf_fisheye(data_clean, ...)

## Common Issues

### Layers Don’t Align

Problem: Points and polygons don’t line up after transformation.

Solution: Transform together (see “Working with Multiple Layers”).

### Excessive Distortion

Problem: Features look overly warped.

Solution: Reduce `zoom_factor` or increase `r_out` to widen the glue zone.

### Features Overlap in Focus

Problem: Too much magnification causes overlap.

Solution: This is expected behavior. Reduce `zoom_factor` if problematic.

## Next Steps

- Advanced transformations: Explore the `revolution` parameter for rotational effects
- Interactive visualization: Use `shiny_fisheye()` for interactive parameter tuning
- Custom workflows: Combine with other sf operations in analysis pipelines

## Getting Help

- Package documentation: `?sf_fisheye`, `?fisheye_fgc`
- GitHub issues: [Report bugs or request features]
- Examples: See `?vic` for built-in datasets

## References

The Focus-Glue-Context model is based on:

- Yamamoto, D., et al. (2009). “A Focus+Glue+Context Information Visualization Technique for Web Map Services”
- Furnas, G. W. (1986). “Generalized fisheye views”

Remember: Fisheye transformations distort distances and areas. Use them for visualization and exploration, but perform quantitative analyses on the original geometries.