knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
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 ggplot2s 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), 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.
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.
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:
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:
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:
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
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:
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:
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))
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
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
for the full story.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.