---
title: "Background"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Background}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

## The problem

The `scales` package provides a family of easy to use functions
like `scales::label_number` or `scales::label_percent` to format numbers in
decimal format, as percentages or currencies, which could also be
passed to the `labels` argument of `ggplot2`s family of scale functions to
format axes or legends.

However, let's say you have to prepare a report or charts where you have to use
country-specific style conventions to display numbers which differ from the
default anglo-american style.

While that could be achieved with the `scales` package as well, in practice
formatting numbers and styling axes quickly becomes
cumbersome and annoying as you always have to

* set the decimal and grouping marks (if deviating from the defaults) so you end up with
  ```
  scales::label_number(big.mark = ".", decimal.mark = ",")(x)
  ```
  to format a number `x` in decimal format according to style conventions found
  in many European countries.

* provide a suitable labeller function to the `labels` argument of
  `scale_xxx_yyy` so you end up with
  ```
  scale_x_continuous(
    labels = scales::label_percent(big.mark = ".", decimal.mark = ",")
  )
  ```
  to display numbers on the x axis as percentages using the style convention
  found in many European countries.

As of `scales` 1.4.0 (released 2025-04-24), you no longer have to repeat
`big.mark`/`decimal.mark` on every single call within a session — a new
`scales::number_options(decimal.mark = ",", big.mark = ".")` sets these (and
`style_positive`/`style_negative`, and currency-specific equivalents) as
global defaults for every subsequent `label_number()`/`label_currency()` call.
That closes part of the gap above for a *single* country's conventions
applied for the rest of a session — but it's still one global default at a
time. It doesn't help if you need several countries' conventions side by
side in the same report or chart (like the G20 example in the
[README](https://trekonom.github.io/countryscales/)), and it doesn't touch
the harder problems `countryscales` also handles under the hood: correct
currency symbol/sign positioning and locale-correct percent-sign placement
and spacing.

## The solution

A first and simple solution to this problem would be to add some simple wrappers
at the beginning of your R script or R markdown document like
```
my_label_number <- function() {
  scales::label_number(big.mark = ".", decimal.mark = ",")
}
```
But then you end up copy and pasting from one report to the next, so sooner or
later you probably put these helpers inside package.

And that's the goal of `countryscales`: Providing out-of-the-box helpers to
format numbers using country-specific style conventions.

```{r, include = FALSE}
x <- 12345689.987654321
```

As a first example consider formatting a number according to style
conventions used in Germany and several other European countries where a
dot (`.`) is used as the big mark or grouping mark or thousands separator
and a comma (`,`) as the decimal mark.

Using `scales::label_number` this requires switching the default decimal and big
marks:
```{r}
library(scales)

label_number(big.mark = ".", decimal.mark = ",", accuracy = .1)(x)
```

Using `countryscales` this could be achieved with less typing using
`countryscales::label_number_de`:

```{r}
library(countryscales)

label_number_de(accuracy = .1)(x)
```

To provide an example of using `countryscales` with `ggplot2` let's first
prepare a small example dataset of the top 10 countries according to population
size:

```{r top-10-pop}
top10_pop <- gapminder15[order(-gapminder15$pop), c("country", "pop")]
top10_pop$pct <- top10_pop$pop / sum(top10_pop$pop)
top10_pop <- head(top10_pop, 10)
```

As a basic example let's make a simple barchart of population size by country

```{r}
library(ggplot2)

p <- ggplot(top10_pop, aes(pop, reorder(country, pop))) +
  geom_col() +
  theme_minimal() +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank()
  ) +
  labs(
    x = NULL, y = NULL,
    title = "Top 10 of countries by population size in 2015",
    caption = "Data: gapminder.org"
  )
```
While this chart is fine it's not ready for publication. Let's say we want to
display population sizes on the x axis in decimal format and additionally add
the share of each country on World population formatted as percentages as labels
to the bars using German style conventions.

Using `scales` this could be achieved like so:

```{r style-scales}
lbl_pct <- label_percent(big.mark = ".", decimal.mark = ",", accuracy = .1)
lbl_num <- label_number(big.mark = ".", decimal.mark = ",")
p +
  # Add percentages to bars using German style conventions
  geom_text(
    aes(label = lbl_pct(pct)),
    hjust = 1.1, size = 8 / .pt, color = "white") +
  # Format numbers as percentages
  scale_x_continuous(
    labels = lbl_num,
    expand = c(0, 0, .05, 0))
```

As this simple example shows displaying numbers in decimal format or as
percentages requires some typing, especially if you want to or have to deviate
from default decimal and grouping marks.

That's where `countryscales` comes in handy as using `label_percent_de` and
`scale_x_number_de` the same could be achieved with less typing like so:

```{r style-countryscales}
p +
  # Add percentages to bars using German style conventions
  geom_text(
    aes(
      label = label_percent_de(accuracy = .1)(pct)
    ),
    hjust = 1.1, size = 8 / .pt, color = "white"
  ) +
  # Format numbers as percentages
  scale_x_number_de(expand = c(0, 0, .05, 0))
```

## Beyond Germany

Every example above uses `label_number_de()`/`scale_x_number_de()`, but
that's just the tip of the iceberg. Under the hood, all of these delegate
to a general-purpose locale engine, `label_number_locale()`/
`scale_x_number_locale()` (and their `_percent_`/`_currency_`
counterparts), which work with any of the `r nrow(countryscales::locales)`
locale codes `countryscales` supports -- run `show_locales()` to list them
all. On top of that engine, `countryscales` also ships the same
ready-to-use `_de()`-style convenience family for 27 countries, from
Argentina to the United States (see the
[reference index](https://trekonom.github.io/countryscales/reference/index.html#countries)
for the full list).

Getting locale-specific formatting right also involves more than just the
decimal and grouping marks shown here: correct currency symbol and sign
positioning (which side of the number, with or without a space) and
locale-correct percent-sign placement and spacing are full of exceptions
that `scales::label_number()`/`label_currency()` don't attempt to solve.
`countryscales` handles these under the hood using a modified version of
`label_number()` -- see the
[README's Credits section](https://trekonom.github.io/countryscales/index.html#credits)
for the full story.
