# Making Dot Density Maps

    library(dots)
    library(ggplot2)
    library(sf)
    #> Linking to GEOS 3.13.1, GDAL 3.11.0, PROJ 9.6.0; sf_use_s2() is TRUE

## The `dots` Package

Dot density maps are useful to display the relative distribution of people across geographies. These maps are often used in election research and litigation to highlight the distribution of voters where choropleths tell a different story. `dots` simplifies this process, allowing for a tidy, simple interface. Maps can be created automatically with `dots::dots()`. The points behind these maps can be generated with `dots::dots_points()`.

Now, various methods for creating random points exist in different R ecosystems, notably in `terra`, `sf`, and `sp`. Each of these different inputs and produce completely different outputs. To standardize these to one interface, `dots` creates a set of wrapper `engine_*` functions. Each `engine_*` function takes the same arguments: `shp` and `col`. Shape is an `sf` tibble and `col` is the string name of a column in `shp`. Within each of the engine functions, additional work is done to standardize the outputs so that they will be largely comparable.

## Making Dot Density Maps

To make a dot density map, we need a shapefile with populations, votes, or some other numeric attribute tied to each geography. Here, we load 2020 Census data for Suffolk County, MA, included with the `dots` package.

    data("suffolk")

To make a basic dot density map for the Hispanic voting age population, we can run the following:

    dots::dots(shp = suffolk, cols = vap_hisp)

This works because `vap_hisp` is a numeric column in `suffolk`. Any numeric column would work. We can even use multiple columns. `cols` uses `tidyselect` to select multiple columns. For example, to make a map using the White and Hispanic voting age population, we could do the following:

    dots::dots(shp = suffolk, cols = c(vap_hisp, vap_white))

Now, the points here are a bit crowded, so we can raise the number of adults that each point stands for by increasing the `divisor` argument. The default is 250, but here we will raise it to 1250.

    dots::dots(shp = suffolk, cols = c(vap_hisp, vap_white), divisor = 1250)

The color of the dots uses the color aesthetic, so we can change it using different `scale_color` functions:

    dots::dots(shp = suffolk, cols = c(vap_hisp, vap_white), divisor = 1250) +
      scale_color_brewer(name = 'Race/Ethnicity', palette = 'Accent')

Now, this is kind of bland, but it is a `ggplot` output, so we can update it using any of the regular tools. For example, we can clean up the background and give it clearer labels.

    dots::dots(shp = suffolk, cols = c(vap_hisp, vap_white), divisor = 1250) +
      scale_color_brewer(name = 'Race/Ethnicity', palette = 'Accent') +
      labs(
        title = 'White and Hispanic Adults in Suffolk County, MA',
        caption = 'One point per 1250 adults.'
      ) +
      theme_void()

The downside of using the automatic plot generated by `dots::dots()` is that it limits us to a few plot defaults. If we switch to `dots::dots_points()`, we can make more specific choices by generating the plot.

To make the same basic plot, we could run the following:

    dots::dots_points(shp = suffolk, cols = c(vap_hisp, vap_white), divisor = 1250)  |>
      ggplot() +
      geom_sf(data = suffolk, fill = NA, color = 'black') +
      geom_sf(aes(color = dots_type)) +
      scale_color_brewer(name = 'Race/Ethnicity', palette = 'Accent') +
      labs(
        title = 'White and Hispanic Adults in Suffolk County, MA',
        caption = 'One point per 1250 adults.'
      ) +
      theme_void()

Then, we can customize additional aspects of it, again using `ggplot2` functions.

    dots::dots_points(shp = suffolk, cols = c(vap_hisp, vap_white), divisor = 1250)  |>
      dplyr::mutate(dots_type = dplyr::case_when(
        dots_type == 'vap_white' ~ 'White',
        dots_type == 'vap_hisp' ~ 'Hispanic'
      )) |>
      ggplot() +
      geom_sf(data = suffolk, fill = NA, color = 'black') +
      geom_sf(aes(color = dots_type), size = 0.75) + # change size
      scale_color_brewer(name = 'Race/Ethnicity', palette = 'Accent') +
      labs(
        title = 'White and Hispanic Adults in Suffolk County, MA',
        caption = 'One point per 1250 adults.'
      ) +
      theme_void()