Is there an option to set "," as default decimal point for axis labels in ggplot?

Viewed 165

When making a graph, ggplot2 has a lot of sensible defaults for scales that require extra work when trying to achieve the same result using scales.

An example:

library("ggplot2")
ggplot(mtcars, aes(drat, mpg)) + geom_point()

Note that this plot has one digit behind the decimal mark.

However, I live in the Netherlands and we're used to using a comma as decimal mark. This is easily done within scale_x_continuous:

ggplot(mtcars, aes(drat, mpg)) + 
  geom_point() + 
  scale_x_continuous(labels = scales::label_number(big.mark = ".", decimal.mark = ","))

What bugs me about this solution is that this also increases the number of digits: there's an extra, rather unnecessary, 0 at the end of each label. Of course, this can also be solved within scales::label_number(), by setting accuracy = 0.1 but that requires iteration (plotting and re-plotting to set the more sensible number of digits).

Is there an option to fix the default decimal mark used by ggplot? I'm looking for a solution where

ggplot(mtcars, aes(drat, mpg)) + 
  geom_point()

returns the same plot as

ggplot(mtcars, aes(drat, mpg)) + 
  geom_point() + 
  scale_x_continuous(labels = scales::label_number(
    big.mark = ".", 
    decimal.mark = ",",
    accuracy = 0.1
  ))
3 Answers

Not specific to ggplot2 but you can set the output decimal point character globally using options(OutDec = ",").

From the help page:

OutDec: character string containing a single character. The preferred character to be used as the decimal point in output conversions, that is in printing, plotting, format and as.character but not when deparsing nor by sprintf nor formatC (which are sometimes used prior to printing.)

library(ggplot2)

options(OutDec= ",")

ggplot(mtcars, aes(drat, mpg)) + 
  geom_point()

enter image description here

The key seems to be that format (from base R) and scales::number use different rules. We can revert to using format ...

myf <- function(x, ...) format(x, big.mark = ".", decimal.mark = ",", ...)
ggplot(mtcars, aes(drat, mpg)) +
  geom_point() +
  scale_x_continuous(labels = myf)

If you want to make these labels the global default I think you can do this:

scale_x_continuous <- function(..., labels = myf) {
  do.call(ggplot2::scale_x_continuous, c(list(...), labels = labels))
}

A more general solution is to write a {scales} compatible labelling function label_format() that calls base::format() under the hood, and then to make a specialized version with the Dutch punctuation conventions.

library(ggplot2)
library(scales)

ggplot(mtcars, aes(drat, mpg)) + 
  geom_point()

# Use base::format as a {scales}-compatible labels function
label_format <- function(...) {
  function(x) do.call(format, c(list(x = x), list(...)))
}

# Specialized version for Dutch punctuation
label_format_NL <- function(...) {
  label_format(big.mark = ".", decimal.mark = ",", ...)
}

ggplot(mtcars, aes(drat, mpg)) + 
  geom_point() + 
  scale_x_continuous(labels = label_format_NL())

If you don't like having to specify the labels for every axis, you can override ggplot2::continuous_scale like this e.g.

continuous_scale <- function(...) {
  do.call(
    ggplot2::continuous_scale, 
    c(list(labels = label_format_NL()), list(...))
  )
}

ggplot(mtcars, aes(drat, mpg)) + 
  geom_point()

Personally, I'd use the explicit scale_AESTHETIC_continous(labels = label_format_NL()) since that keeps your changes localized. Overriding options() or continuous_scale() is the moral equivalent of global variables, not recommended.

Related