# Geom examples

This vignette shows how to use each geometry in highdir. Every example follows the same two-step workflow:

1. `hd_spec()` — describe what the data means (columns, labels)
2. `hd_make()` — decide how to render it (geom, backend, options)

The same `hd_spec` object can be passed to `hd_make()` multiple times with different geom types, backends, or `hd_opts()` objects — there is no need to rebuild the spec.

    library(highdir)
    # ── Age-group survey dataset (bars and pie) ────────────────────────────────────
    survey <- data.frame(
      age_group = rep(c("18-24", "25-34", "35-44", "45-54", "55-64"), each = 2),
      kjonn       = rep(c("Male", "Female"), times = 5),
      pct       = c(42, 38, 55, 61, 48, 52, 60, 57, 65, 70),
      n         = c(120, 115, 200, 210, 180, 175, 160, 155, 140, 145)
    )

## Column chart

Column charts are the default geometry and work with both grouped and ungrouped data. The `n` column is shown in the highcharter tooltip alongside the percentage.

    spec_col <- hd_spec(survey,
                        x     = "age_group",
                        y     = "pct",
                        group = "kjonn",
                        n     = "n")

    opts_col <- hd_opts(
      title    = "Alcohol use by age group and kjonn",
      subtitle = "Source: Norwegian Directorate of Health",
      ylim     = c(0, 100),
      yint     = 20,
      ylab     = "Percentage (%)"
    )

    ## Alternatively using ggplot2 syntax
    # hd(survey, x = "age_group", y = "pct", group = "kjonn", n = "n") +
    #  hd_opts(title = "Alcohol use by age group and kjonn",
    #       subtitle = "Source: Norwegian Directorate of Health",
    #       ylim = c(0, 100),
    #       yint = 20,
    #       ylab = "Percentage (%)") +
    #       hd_geom_column()

### Interactive figure

    # Interactive (default)
    hd_make(spec_col, "column", opts_col)

    # alternatively
    # hd(spec_col) + hd_geom_column() + hd_opts(opts_col)

### Static figure

    # Static ggplot2
    hd_make(spec_col, "column", opts_col, mode = "static")

### Column with groups

    # Horizontal bars — flip applies to both backends
    opts_flip <- hd_opts(
      title    = "Alcohol use by age group and kjonn",
      subtitle = "Source: Norwegian Directorate of Health",
      ylim     = c(0, 100),
      flip     = TRUE
    )

    hd_make(spec_col, "column", opts_flip)

    hd_make(spec_col, "column", opts_flip, mode = "static")

## Line chart

Line charts suit time-series data. Use `smooth = TRUE` (default) for spline curves, or `FALSE` for straight segments between points. `dot_size` controls the marker radius.

    # ── Time-series dataset (single group) ────────────────────────────────────────
    # Annual alcohol consumption estimate with 95 % confidence interval.
    # data("alco1")

    # ── Time-series dataset (kjonn groups) ──────────────────────────────────────────
    # data("alco2")

    # Single series — no group column
    spec_line1 <- hd_spec(alco1,
                          x    = "year",
                          y    = "adj_mean"
                          )

    opts_line <- hd_opts(
      title    = "Alcohol consumption over time",
      subtitle = "Source: Norwegian Directorate of Health",
      ylim     = c(0, 50),
      ylab = "Litres per capita"
    )

    # Straight segments
    hd_make(spec_line1, "line", opts_line, smooth = FALSE)

    hd_make(spec_line1, "line", opts_line, smooth = FALSE, mode = "static")

### Interactive figure

    # Spline (smooth) — default
    hd_make(spec_line1, "line", opts_line)

### Static

    # Spline (smooth) — default
    hd_make(spec_line1, "line", opts_line, mode = "static")

    # Grouped by kjonn
    spec_line2 <- hd_spec(alco2,
                          x     = "year",
                          y     = "adj_mean",
                          group = "kjonn")

    # Larger markers, straight lines
    hd_make(spec_line2, "line", opts_line, smooth = FALSE, dot_size = 6)
    hd_make(spec_line2, "line", opts_line, smooth = FALSE, dot_size = 6,
            mode = "static")

    # Highcharter only: custom per-group marker shapes
    hd_make(spec_line2, "line", opts_line,
            line_symbols = c("circle", "square"))

## Ranked bar chart

A ranked bar chart sorts bars by value so comparisons across categories are immediate. Use `ranked_bar` when the order of categories matters more than their nominal labels - for example, ranking regions by a health indicator.

Automatic label placement is one of the key features of this geom. In the ggplot2 backend, value labels are placed inside a bar when the bar is long enough to fit the text, and outside when the bar is too short. The cut-off is calculated per bar from the label character width relative to the axis range, so the placement is fully automatic — no manual threshold is needed.

    # Regional health indicator dataset
    regions <- data.frame(
      region = c("Oslo", "Viken", "Vestland", "Rogaland",
                 "Trondelag", "Innlandet", "Agder",
                 "Nordland", "Troms og Finnmark"),
      rate   = c(68.4, 71.2, 87.8, 64.5, 61.3, 6.1, 54.2, 49.8, 42.1),
      n      = c(402, 448, 681, 318, 297, 251, 198, 177, 148)
    )

    spec_rb <- hd_spec(regions,
                       x    = "region",
                       y    = "rate",
                       n    = "n")

    opts_rb <- hd_opts(
      title    = "Health indicator by region",
      subtitle = "Source: Norwegian Directorate of Health",
      ylab     = "Rate per 100 000",
      flip     = TRUE
    )

    # Static ggplot2 — value labels placed inside or outside bars automatically
    hd_make(spec_rb, "ranked_bar", opts_rb, mode = "static")

    # Interactive — default ascending order (lowest bar at bottom)
    hd_make(spec_rb, "ranked_bar", opts_rb)

Pass `ascending = FALSE` to flip the sort order so the highest-ranked category appears at the top:

    hd_make(spec_rb, "ranked_bar", opts_rb, ascending = FALSE)
    hd_make(spec_rb, "ranked_bar", opts_rb, ascending = FALSE, mode = "static")

Use `aim` to draw a dashed reference line at a target value. The line is drawn in a contrasting brand colour so it reads clearly against the bars:

    # Draw a dashed target line at rate = 60
    hd_make(spec_rb, "ranked_bar", opts_rb, aim = 60, mode = "static")

    # Draw a dashed target line at rate = 60
    hd_make(spec_rb, "ranked_bar", opts_rb, aim = 60)

Use `vs` to highlight one specific category with a contrasting fill colour. The argument accepts a partial string match against the `x` column, so `vs = "Oslo"` will match `"Oslo"` exactly, and `vs = "Troms"` would match `"Troms og Finnmark"`:

    # Highlight Oslo as the comparison reference
    hd_make(spec_rb, "ranked_bar", opts_rb, vs = "Oslo")
    hd_make(spec_rb, "ranked_bar", opts_rb, vs = "Oslo", mode = "static")

    # Combine: descending order + target line + comparison highlight
    hd_make(spec_rb, "ranked_bar", opts_rb,
            ascending = FALSE,
            aim       = 60,
            vs        = "Oslo")

    hd_make(spec_rb, "ranked_bar", opts_rb,
            ascending = TRUE,
            aim       = 60,
            vs        = "Oslo",
            backend   = "static")

The `n` column in `hd_spec()` appends sample sizes to category labels in the ggplot2 backend (`"Oslo (N=502)"`) and shows them in the highcharter tooltip. Omit `n` from `hd_spec()` if you do not want sample sizes displayed:

    spec_rb_no_n <- hd_spec(regions,
                            x    = "region",
                            y    = "rate")

    # No N= labels in ggplot2; no N line in HC tooltip
    hd_make(spec_rb_no_n, "ranked_bar", opts_rb, mode = "static")
    hd_make(spec_rb_no_n, "ranked_bar", opts_rb)

## Arearange chart

Arearange is designed for displaying a central estimate alongside a confidence interval or min/max band. `ymin` and `ymax` are required — they name the columns that define the lower and upper bounds of the shaded band.

    # Single series
    spec_ar1 <- hd_spec(alco1,
                        x    = "year",
                        y    = "adj_enhet")

    opts_ar <- hd_opts(
      title    = "Alcohol consumption with 95% CI",
      subtitle = "Source: Norwegian Directorate of Health",
      ylim     = c(0, 30),
      ylab = "Number of units alcohol"
    )

### Interactive

    hd_make(spec_ar1, "arearange", opts_ar,
            ymin = "lower_enhet", ymax = "upper_enhet")

### Static

    hd_make(spec_ar1, "arearange", opts_ar,
            ymin = "lower_enhet", ymax = "upper_enhet", mode = "static")

    # Grouped by kjonn
    spec_ar2 <- hd_spec(alco2,
                        x     = "year",
                        y     = "adj_enhet",
                        group = "kjonn")

    hd_make(spec_ar2, "arearange", opts_ar,
            ymin = "lower_enhet", ymax = "upper_enhet")

    hd_make(spec_ar2, "arearange", opts_ar,
            ymin = "lower_95CI", ymax = "upper_95CI", mode = "static")

## Pie chart

Pie charts map one categorical column to slice labels and one numeric column to slice values. Pass `inner_size = "50%"` (or any CSS percentage) to draw a donut chart. The `group` column is ignored for pie charts — use `x` for labels and `y` for values.

    # Category share dataset (pie)
    drinking_freq <- data.frame(
      category = c("Never", "Rarely", "Monthly", "Weekly", "Daily"),
      pct      = c(18, 25, 30, 20, 7))

    spec_pie <- hd_spec(drinking_freq,
                        x    = "category",
                        y    = "pct")

    opts_pie <- hd_opts(
      title    = "Drinking frequency",
      subtitle = "Source: Norwegian Directorate of Health",
      ylab = "Share (%)"
    )

### Donut

    # Donut interactive
    hd_make(spec_pie, "pie", opts_pie, inner_size = "50%")

    # Donut static
    hd_make(spec_pie, "pie", opts_pie, inner_size = "50%", mode = "static")

### Solid pie

    # Solid pie
    hd_make(spec_pie, "pie", opts_pie)
    hd_make(spec_pie, "pie", opts_pie, mode = "static")

## Stacked column chart

Stacked column charts display multiple series grouped into named stacks. Each stack is a separate pile of bars; series that share the same stack accumulate on top of each other.

The data must be in long format with one row per `(x, group, facet)` combination:

- `x` — the category axis (e.g. medal type)
- `y` — the numeric value
- `group` — the series label shown in the legend (e.g. country)
- `facet` — the column that assigns rows to a stack group (e.g. continent)

    # Olympics all-time medal table
    olympics <- data.frame(
      Country   = c("Norway", "Norway", "Norway",
                    "Germany", "Germany", "Germany",
                    "United States", "United States", "United States",
                    "Canada", "Canada", "Canada"),
      Continent = c("Europe", "Europe", "Europe",
                    "Europe", "Europe", "Europe",
                    "North America", "North America", "North America",
                    "North America", "North America", "North America"),
      Medal     = rep(c("Gold", "Silver", "Bronze"), times = 4),
      Count     = c(148, 133, 124,
                    102,  98,  65,
                    113, 122,  95,
                     77,  72,  80)
    )

    spec_st <- hd_spec(olympics,
                       x     = "Medal",
                       y     = "Count",
                       group = "Country")

    opts_st <- hd_opts(
      title    = "Olympic Games all-time medal table, grouped by continent",
      subtitle = "Source: Olympics",
      ylab     = "Count medals"
    )

    # Interactive — stacked column
    hd_make(spec_st, "stacked_column", opts_st)

    # Interactive — stacks are separated by continent
    hd_make(spec_st, "stacked_column", opts_st, facet = "Continent")

    # Static ggplot2 — continents become facet panels
    hd_make(spec_st, "stacked_column", opts_st,
            facet   = "Continent",
            mode = "static")

The `stacking` argument controls how values accumulate. `"normal"` (default) shows absolute values; `"percent"` rescales each stack to 100 % so you can compare compositions across stacks:

    # 100% stacked — shows share within each continent, not absolute counts
    hd_make(spec_st, "stacked_column", opts_st,
            facet    = "Continent",
            stacking = "percent")

    ## Static
    hd_make(spec_st, "stacked_column", opts_st,
            facet    = "Continent",
            stacking = "percent",
            backend  = "static")

The same `hd_opts()` controls — title, axis labels, colours, and theme — work identically for stacked columns as for every other geom:

    # Custom colour palette and Norwegian labels
    opts_no <- hd_opts(
      title    = "Olympiske medaljer etter kontinent",
      subtitle = "Kilde: OL-statistikk",
      ylab     = "Antall medaljer",
      colors   = c("#025169", "#7C145C", "#C68803", "#047FA4")
    )

    hd_make(spec_st, "stacked_column", opts_no, facet = "Continent")
    hd_make(spec_st, "stacked_column", opts_no,
            facet   = "Continent",
            mode = "static")

## Reusing a spec across geoms

Because `hd_spec()` and `hd_opts()` are separate from `hd_make()`, the same data description can be rendered as any geometry — no code duplication.

    # One spec, three geoms
    spec_shared <- hd_spec(alco2,
                           x     = "year",
                           y     = "adj_mean",
                           group = "kjonn")

    opts_shared <- hd_opts(
      title    = "Alcohol consumption by kjonn",
      subtitle = "Source: Norwegian Directorate of Health",
      ylim     = c(0, 50),
      ylab  = "Litres per capita"
    )

    hd_make(spec_shared, "column",    opts_shared)
    hd_make(spec_shared, "line",      opts_shared)
    hd_make(spec_shared, "arearange", opts_shared,
            ymin = "lower_95CI", ymax = "upper_95CI")

## Reusing opts across languages

An `hd_opts()` object only controls presentation. Create one per language and pair it with the same spec.

    opts_no <- hd_opts(
      title    = "Alkoholbruk over tid",
      subtitle = "Kilde: Helsedirektoratet",
      caption  = "Tall om alkohol",
      ylim     = c(0, 50)
    )

    opts_en <- hd_opts(
      title    = "Alcohol use over time",
      subtitle = "Source: Norwegian Directorate of Health",
      caption  = "Annual health report",
      ylim     = c(0, 50)
    )

    spec_ts <- hd_spec(alco2,
                       x     = "year",
                       y     = "adj_mean",
                       group = "kjonn")

    hd_make(spec_ts, "line", opts_no)
    hd_make(spec_ts, "line", opts_en)

## Theming

Use `hd_set_theme()` once per session to apply a consistent visual style across all figures. Per-figure overrides are set via `hd_opts(hc_theme = ..., gg_theme = ...)`.

    # Session-wide defaults
    hd_set_theme(
      hc_theme = "gridlight",
      gg_theme = "classic",
      colors   = c("#025169", "#7C145C", "#C68803")
    )

    hd_make(spec_ts, "line", opts_en)
    hd_make(spec_ts, "line", opts_en, mode = "static")

    # Per-figure override — does not change the session default
    hd_make(spec_ts, "line",
            hd_opts(title = "Dark theme", hc_theme = "darkunica"),
            mode = "dynamic")

    # Reset to package defaults
    hd_set_theme(hc_theme = "default", gg_theme = "classic", colors = NULL)

## Saving figures

`hd_save()` exports highcharter figures to HTML or JSON and ggplot2 figures to PNG, SVG, or PDF. The format is inferred from the file extension.

    hc_fig <- hd_make(spec_ts, "line", opts_en)
    gg_fig <- hd_make(spec_ts, "line", opts_en, mode = "static")

    hd_save(hc_fig, "alcohol_line.html")
    hd_save(hc_fig, "alcohol_line.json")

    hd_save(gg_fig, "alcohol_line.png")
    hd_save(gg_fig, "alcohol_line.svg")