Introduction to csstyle

library(csstyle)
#> csstyle 2026.7.1
#> https://niphr.github.io/csstyle/
library(ggplot2)

Overview

csstyle standardizes graphs, tables, and reports to follow Core Surveillance visual guidelines. The design is intentionally narrow: rather than exposing every ggplot2 option, the package offers a small set of outputs that look the same regardless of who produces them or when.

The package covers four areas:

  • ggplot2 themes and color scales
  • Color palettes defined centrally and applied consistently
  • Number and date formatting in both Norwegian and international journal styles
  • Small utility functions for common axis tasks

Themes

The main theme function is theme_cs(), which applies a clean Core Surveillance appearance to any ggplot2 plot:

# Basic scatter plot with Core Surveillance theme
ggplot(mtcars, aes(x = mpg, y = hp)) +
  geom_point() +
  theme_cs() +
  labs(
    title = "Engine Power vs Fuel Efficiency",
    x = "Miles per Gallon",
    y = "Horsepower"
  )

A few arguments adjust the layout without breaking the overall style:

# Theme with bottom legend and vertical x-axis labels
ggplot(mtcars, aes(x = factor(cyl), y = mpg, fill = factor(cyl))) +
  geom_boxplot() +
  theme_cs(legend_position = "bottom", x_axis_vertical = TRUE) +
  labs(title = "MPG by Number of Cylinders", fill = "Cylinders")

Color palettes

The package ships several predefined palettes. You can inspect them directly:

# View available colors
head(colors$named_colors)
#>        H1        H2        H3        H4        H5        H6 
#> "#393C61" "#0975B5" "#2EA1C0" "#709900" "#B11643" "#FC5F56"

# Display all palettes
display_all_palettes()

Apply a palette to a plot with scale_color_cs() or scale_fill_cs():

# Using the primary color palette
ggplot(mtcars, aes(x = mpg, y = hp, color = factor(cyl))) +
  geom_point(size = 3) +
  scale_color_cs(palette = "primary") +
  theme_cs() +
  labs(color = "Cylinders")

# Using the warning palette for fills
ggplot(mtcars, aes(x = factor(cyl), fill = factor(cyl))) +
  geom_bar() +
  scale_fill_cs(palette = "warning") +
  theme_cs() +
  labs(title = "Car Count by Cylinders", fill = "Cylinders")

Number formatting

All number formatting functions come in two parallel families that reflect their intended audience: Norwegian conventions for domestic reports, and journal conventions for international academic publications. See the “Journal formatting” section below for a side-by-side comparison.

Norwegian number format

The format_num_as_nor_* functions use a comma for the decimal separator, a space for thousands, and "IK" (ikke kjent) for missing values:

# Format numbers with Norwegian conventions
numbers <- c(1234.56, 9876.54, 123.45, NA)

# Basic number formatting (0, 1, 2 decimal places)
format_num_as_nor_num_0(numbers)
#> [1] "1235" "9877" "123"  "IK"
format_num_as_nor_num_1(numbers)
#> [1] "1234,6" "9876,5" "123,5"  "IK"
format_num_as_nor_num_2(numbers)
#> [1] "1234,56" "9876,54" "123,45"  "IK"

# Percentage formatting
percentages <- c(12.34, 56.78, 90.12)
format_num_as_nor_perc_1(percentages)
#> [1] "12,3 %" "56,8 %" "90,1 %"

# Per 100k population rates
rates <- c(123.45, 678.90)
format_num_as_nor_per100k_1(rates)
#> [1] "123,5 /100k" "678,9 /100k"

Date formatting

Norwegian date format

The format_date_as_nor() and format_datetime_as_nor() functions produce dates in the Norwegian dd.mm.yyyy style:

# Current date
format_date_as_nor()
#> [1] "02.07.2026"

# Specific dates
test_date <- as.Date("2023-12-25")
format_date_as_nor(test_date)
#> [1] "25.12.2023"

# Datetime formatting
test_datetime <- as.POSIXct("2023-12-25 14:30:00")
format_datetime_as_nor(test_datetime)
#> [1] "25.12.2023 kl. 14:00"

# Filename-safe datetime
format_datetime_as_file(test_datetime)
#> [1] "2023_12_25_143000"

Journal formatting

For academic publications the package provides a parallel set of functions that follow international conventions: a decimal point, comma thousands separator, "NA" for missing values, and ISO 8601 dates.

Number format comparison

# Compare Norwegian vs Journal formatting
numbers <- c(1234.56, 9876.54, NA)

# Norwegian format (space thousands, comma decimal, "IK" for NA)
format_num_as_nor_num_1(numbers)
#> [1] "1234,6" "9876,5" "IK"

# Journal format (comma thousands, decimal point, "NA" for NA)
format_num_as_journal_num_1(numbers)
#> [1] "1,234.6" "9,876.5" "NA"

# Percentage comparison
percentages <- c(12.34, 56.78)

# Norwegian: "12,3 %" vs Journal: "12.3%"
format_num_as_nor_perc_1(percentages)
#> [1] "12,3 %" "56,8 %"
format_num_as_journal_perc_1(percentages)
#> [1] "12.3%" "56.8%"

# Per 100k comparison  
rates <- c(123.45, 678.90)

# Norwegian: "123,5 /100k" vs Journal: "123.5/100k"
format_num_as_nor_per100k_1(rates)
#> [1] "123,5 /100k" "678,9 /100k"
format_num_as_journal_per100k_1(rates)
#> [1] "123.5/100k" "678.9/100k"

Date format comparison

test_date <- as.Date("2023-12-25")
test_datetime <- as.POSIXct("2023-12-25 14:30:00")

# Norwegian format: "25.12.2023"
format_date_as_nor(test_date)
#> [1] "25.12.2023"

# Journal format (ISO 8601): "2023-12-25"
format_date_as_journal(test_date)
#> [1] "2023-12-25"

# Datetime comparison
format_datetime_as_nor(test_datetime)     # "25.12.2023 kl. 14:00"
#> [1] "25.12.2023 kl. 14:00"
format_datetime_as_journal(test_datetime)  # "2023-12-25 14:30:00"
#> [1] "2023-12-25 14:30:00"

Log scale transformations

Both families include inverse log transformation variants, useful when axis values are on a log scale and you want to display the original units in labels:

log_values <- c(1, 2, 3)

# Log2 transformations (2^1, 2^2, 2^3 = 2, 4, 8)
format_num_as_nor_invlog2_1(log_values)      # "2,0", "4,0", "8,0"
#> [1] "2,0" "4,0" "8,0"
format_num_as_journal_invlog2_1(log_values)  # "2.0", "4.0", "8.0"
#> [1] "2.0" "4.0" "8.0"

# Log10 transformations (10^1, 10^2, 10^3 = 10, 100, 1000)  
format_num_as_journal_invlog10_1(log_values) # "10.0", "100.0", "1,000.0"
#> [1] "10.0"    "100.0"   "1,000.0"

Utility functions

Pretty breaks

pretty_breaks() generates axis break positions that round to human-friendly values:

ggplot(mtcars, aes(x = mpg, y = hp)) +
  geom_point() +
  scale_y_continuous(breaks = pretty_breaks(n = 4)) +
  theme_cs()

Every nth label

On crowded discrete axes, every_nth() keeps only every nth tick label and drops the rest:

ggplot(mtcars, aes(x = rownames(mtcars), y = mpg)) +
  geom_col() +
  scale_x_discrete(breaks = every_nth(n = 4)) +
  theme_cs() +
  set_x_axis_vertical()

Further reading

Function-level documentation is available via help(package = "csstyle") or individual help pages such as ?theme_cs, ?scale_color_cs, and ?format_num_as_nor_num_1.