Reputation: 11
Sometimes it is necessary to create plots of a set of data in two or more languages. It is of course possible to manually type ggplot layers to make axis titles and guide legend labels publication-ready but I would like to add some automation to reduce the amount of code needed.
Instead of adding layers to replace e.g. variable names in the axis label, I would like to just wrap the ggplot
call inside a function like replace_labels(plot,target_language)
that would automatically look the strings up in a dictionary I have defined. I have written some code that almost works but the problem is that
scales
objects etc. and runs into low-level problems like label width and layoutbreaks = c("something", "or", "other")
etc. and recreate the plot object using theseI also considered replacing the strings in the data.frame
but that is not a good solution because I would need to write the ggplot
calls for each language which seems like unnecessary code replication to me. Any suggestions how to internationalize plots elegantly without needing to rewrite ggplot?
Edit: added a slightly modified example created by mdag02.
library(ggplot2)
language <- list(
fr_FR = list(
title = "Iris",
subtitle = "Le jeu de données connu",
caption = "French",
x = "Longueur des sépales, cm",
y = "Largeur des sépales, cm",
labels = c(setosa = "Setosa", versicolor = "Versicolor", virginica = "Virginica"),
legend = "Espèce",
labeller = function(variable,value) c(setosa = "Setosa", versicolor = "Versicolor", virginica = "Virginica")[value]
),
en_US = list(
title = "Iris",
subtitle = "The famous dataset",
caption = "English",
x = "Sepal Length, cm",
y = "Sepal Width, cm",
labels = c(setosa = "Setosa", versicolor = "Versicolor", virginica = "Virginica"),
legend = "Species",
labeller = function(variable,value) c(setosa = "Setosa", versicolor = "Versicolor", virginica = "Virginica")[value]
)
)
for (l in names(language)) {
message(l)
current <- language[[l]]
print(ggplot(data = subset(iris,
Species %in% c("virginica","versicolor")),
aes(x = Sepal.Length,
y = Sepal.Width)) +
geom_point() +
facet_grid(~Species,labeller = current$labeller)+
scale_colour_discrete(labels = current$labels,
name = current$legend) +
labs(
title = current$title,
subtitle = current$subtitle,
caption = paste(current$caption, format(Sys.Date(), "%Y-%m-%d")),
x = current$x,
y = current$y))
ggsave(file = paste0("iris_", l, ".png"), width = 21, height = 13, units = "cm", scale = 0.8)
}
I would like to make it so that I only need to write code up to the geom such as geom_point
and let the computer handle the label replacement formatting, e.g. scale_colour_discrete
like so:
ggplot(data = subset(iris,
Species %in% c("virginica","versicolor")),
aes(x = Sepal.Length,
y = Sepal.Width)) +
geom_point() +
facet_grid(~Species)
I could get in that direction by encapsulating the formatting layers in a variable like myformats
but a drawback of this method is that if I want to manually change colors, then I need to re-introduce the label replacement code because my manual formatting will override the label replacements in the myformats
variable.
Also, if I decide that I want to plot Petal.Width
instead, then I need to remember to change the label in both dictionaries and the ggplot
call. I'm terrible at remembering so I would again prefer to leave it to the computer.
Upvotes: 1
Views: 778
Reputation: 1175
You could loop through a list of strings :
library(ggplot2)
language <- list(
fr_FR = list(
title = "Iris",
subtitle = "Le jeu de données connu",
caption = "French",
x = "Longueur",
y = "Largeur"
),
en_US = list(
title = "Iris",
subtitle = "The famous dataset",
caption = "English",
x = "Length",
y = "Width"
)
)
for (l in names(language)) {
message(l)
current <- language[[l]]
ggplot(data = iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() +
geom_smooth() +
labs(
title = current$title,
subtitle = current$subtitle,
caption = paste(current$caption, format(Sys.Date(), "%Y-%m-%d")),
x = current$x,
y = current$y)
ggsave(file = paste0("iris_", l, ".svg"), width = 21, height = 13, units = "cm", scale = 0.8)
}
Upvotes: 2