---
title: "Donut maps with DonutMap"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Donut maps with DonutMap}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 5
)
```

DonutMap creates donut charts positioned on a map from tidy data. The package
has three main workflows:

1. `donut_polygons()` creates an `sf` polygon layer.
2. `donut_map()` creates a static `ggplot2` map.
3. `donut_leaflet()` creates an interactive `leaflet` map with clickable
   donut segments and optional links or curved trajectories.

The examples below use a Natural Earth boundary loaded with `rnaturalearth`
(Natural Earth, n.d., <https://www.naturalearthdata.com/>). The point-level
category values and origin-destination trajectories are simulated for
demonstration.

```{r setup}
library(DonutMap)
library(ggplot2)
library(sf)

set.seed(20260522)
```

## Example data

The input data are tidy: each row gives a value for one category at one
location. Locations can be supplied either as longitude and latitude columns or
as an `sf` object.

```{r data}
sites <- data.frame(
  site = c("Site A", "Site B", "Site C", "Site D", "Site E"),
  lon = c(-73.57, -71.21, -72.75, -68.52, -66.82),
  lat = c(45.50, 46.81, 45.40, 48.45, 50.22)
)

categories <- c("Walking", "Transit", "Car")

demo <- merge(
  sites,
  data.frame(category = categories),
  by = NULL
)

demo$value <- c(
  32, 48, 120,
  55, 80, 95,
  28, 70, 110,
  20, 44, 76,
  18, 30, 58
)

demo$category <- factor(demo$category, levels = categories)

flows <- data.frame(
  from = c(
    "Site A", "Site A", "Site B", "Site B",
    "Site C", "Site C", "Site D", "Site E"
  ),
  to = c(
    "Site B", "Site C", "Site D", "Site A",
    "Site E", "Site B", "Site E", "Site C"
  ),
  trips = c(180, 90, 120, 75, 70, 55, 60, 45),
  flow_category = c(
    "Transit", "Car", "Walking", "Transit",
    "Car", "Walking", "Walking", "Transit"
  )
)

category_colours <- c(
  Walking = "#1b9e77",
  Transit = "#7570b3",
  Car = "#d95f02"
)
```

For a background map, this vignette crops the Natural Earth Canada boundary to
eastern Canada. The donut values and flow values remain simulated.

```{r map-data}
canada <- rnaturalearth::ne_countries(
  country = "Canada",
  returnclass = "sf"
)

eastern_canada <- sf::st_crop(
  canada,
  sf::st_bbox(
    c(xmin = -81, ymin = 44, xmax = -62, ymax = 53.5),
    crs = sf::st_crs(4326)
  )
)
```

## Static map

`donut_map()` returns a normal `ggplot` object, so additional `ggplot2` layers,
scales, labels, and themes can be added afterwards. The `flows` argument adds
links between donut locations. `flow_group` colours those links by a column in
the flow table, which is useful for showing the municipality, mode, or class of
each connection. Use `flow_curvature = 0` for straight links, and larger
positive or negative values for curved trajectories.

```{r static-map}
donut_map(
  demo,
  site,
  category,
  value,
  lon = lon,
  lat = lat,
  map = eastern_canada,
  crs = 3347,
  radius_range = c(25000, 70000),
  colours = category_colours,
  flows = flows,
  from = from,
  to = to,
  flow_value = trips,
  flow_group = flow_category,
  flow_colours = category_colours,
  flow_linewidth_range = c(0.3, 2.2),
  flow_curvature = 0.22,
  flow_arrow = TRUE
) +
  labs(
    title = "Simulated mobility composition by site",
    fill = "Mode",
    linewidth = "Trips"
  ) +
  theme(legend.position = "right")
```

## Interactive map

`donut_leaflet()` returns a `leaflet` htmlwidget. Donut segments and trajectory
lines, including arrowheads, can be clicked to open popups, and hover labels
are enabled by default. When `flow_group` is supplied, both the trajectory lines
and their arrowheads are coloured by group. By default, interactive donuts are
constructed in EPSG:3857, the display projection used by Leaflet, which keeps
the sector boundaries visually regular on screen. Leaflet simplification is
also disabled for donut polygons so the sector borders are not simplified after
the widget is rendered.

```{r interactive-map}
donut_leaflet(
  demo,
  site,
  category,
  value,
  lon = lon,
  lat = lat,
  map = eastern_canada,
  radius_range = c(25000, 70000),
  n = 160,
  colours = category_colours,
  flows = flows,
  from = from,
  to = to,
  flow_value = trips,
  flow_group = flow_category,
  flow_colours = category_colours,
  flow_weight_range = c(1, 7),
  flow_curvature = 0.22,
  flow_arrow = TRUE,
  flow_arrow_size = 45000,
  flow_opacity = 0.75
)
```

## Trajectory geometries

`flow_lines()` returns the trajectory layer directly as an `sf` object. This is
useful when you want to build a custom map layer or inspect the geometry before
plotting.

```{r trajectory-layer}
trajectories <- flow_lines(
  flows,
  demo,
  from,
  to,
  trips,
  site,
  group = flow_category,
  lon = lon,
  lat = lat,
  crs = 3347,
  flow_curvature = 0.22,
  flow_n = 40
)

trajectories
```

## Using the geometry layer directly

For more specialized workflows, `donut_polygons()` returns the donut segments as
valid `sf` polygons.

```{r sf-layer}
donuts <- donut_polygons(
  demo,
  site,
  category,
  value,
  lon = lon,
  lat = lat,
  crs = 3347,
  radius_range = c(25000, 70000)
)

donuts
```

You can use that object with any package that accepts `sf` polygons.

```{r sf-plot}
plot(donuts["category"])
```
