I'm doing an analysis of data saved in Postgres and SQLite databases. There, a lot of columns have underscores as separator. E.g. area_m2, area_ha. Plotting with ggplot2, I have no problems with the standard graphics device. With tikzDevice, the underscore is recognized as special LaTeX character and thus creation of the plot fails:
Error in getMetricsFromLatex(TeXMetrics, verbose = verbose) :
TeX was unable to calculate metrics for:
area_ha
Run the following commands for diagnosis:
tikzTest()
tikzTest("area_ha")
Common reasons for failure include:
* The string contains a character which is special to LaTeX unless
escaped properly, such as % or $.
* The string makes use of LaTeX commands provided by a package and
the tikzDevice was not told to load the package.
The TeX and log files used for the calculation can help diagnose the
problem. If these files are missing, rerun the plot and make sure to
keep the R session open.
TeX file: tikzStringWidthCalc.tex
Log file: tikzStringWidthCalc.log
Consider following MWE:
\documentclass{article}
\usepackage{booktabs}
\usepackage{tikz}
\begin{document}
<<setup, include=FALSE>>=
library(ggplot2)
library(knitr)
library(kableExtra)
require(tikzDevice)
options(tikzDefaultEngine='luatex', tikzSymbolicColors = FALSE)
@
\begin{figure}
<<plot1, echo=FALSE, results='asis'>>=
tikz(console = TRUE, width = 5, height = 3)
ggplot(mtcars, aes(x=hp, y=mpg, color=cyl)) +
geom_point()
dummy <- dev.off()
@
\caption{ggplot output}
\end{figure}
\begin{figure}
<<plot2, echo=FALSE, results='asis'>>=
tikz(console = TRUE, width = 5, height = 3)
df <- mtcars
colnames(df)[2] <- "cyl_inder"
ggplot(df, aes(x=hp, y=mpg, color=`cyl_inder`)) +
geom_point()
dummy <- dev.off()
@
\caption{ggplot\_with\_underscore}
\end{figure}
The underscore is meant for indices in math mode: $v_{i}$, in regular text, it needs to be escaped \verb+\_+.
<<tab-mtcars, echo=FALSE, results='asis'>>=
kbl(df, booktabs = TRUE, caption = "Data frame with underscore character")
@
\begin{figure}
<<plot3, echo=FALSE, results='asis'>>=
tikz(console = TRUE, width = 5, height = 3)
df <- mtcars
colnames(df)[2] <- "cyl inder"
ggplot(df, aes(x=hp, y=mpg, color=`cyl inder`)) +
geom_point()
dummy <- dev.off()
@
\caption{ggplot with spaces}
\end{figure}
\end{document}
plot2 won't work, because the underscore is not escaped.
escaping the character works to a certain degree, but I would also have to permanently escape the character in the column name:
<<plot2, echo=FALSE, results='asis'>>=
tikz(console = TRUE, width = 5, height = 3)
df <- mtcars
colnames(df)[2] <- "cyl\\_inder"
ggplot(df, aes(x=hp, y=mpg, color=`cyl\\_inder`)) +
geom_point()
dummy <- dev.off()
@
Is there a way to escape the character without altering the column name?
Is there a way to escape the character without altering the column name?
Starting with ggplot2 v4, there are a couple of new labelling options that decouple column names from rendered labels (ggplot2 4.0.0 blog post):
- default label from column's "label" attribute and
- a label dictionary that can be passed to labs()
Starting with underscores in column names:
library(ggplot2)
mtcars_ <- setNames(mtcars, paste0(names(mtcars),"_"))[,1:4]
str(mtcars_)
#> 'data.frame': 32 obs. of 4 variables:
#> $ mpg_ : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
#> $ cyl_ : num 6 6 4 6 8 6 8 4 4 6 ...
#> $ disp_: num 160 160 108 258 360 ...
#> $ hp_ : num 110 110 93 110 175 105 245 62 95 123 ...
p_ <-
mtcars_ |>
ggplot(aes(x=hp_, y=mpg_, color=cyl_)) +
geom_point() +
theme_minimal() +
theme(legend.position = "bottom") +
labs(title = "p_:\nlabels from column names")
We can add / manipulate "label" attribute of columns:
## Set `label` attribute for columns
# ( check {tinylabels}, {Hmisc}, etc for more polished approaches )
mtcars_label_attr <-
Map(
mtcars_,
names(mtcars_) |> paste("from label attr"),
f = \(col, name) `attr<-`(col, "label", gsub("_", "\\_", name, fixed = TRUE))
) |>
as.data.frame()
str(mtcars_label_attr)
#> 'data.frame': 32 obs. of 4 variables:
#> $ mpg_ : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
#> ..- attr(*, "label")= chr "mpg\\_ from label attr"
#> $ cyl_ : num 6 6 4 6 8 6 8 4 4 6 ...
#> ..- attr(*, "label")= chr "cyl\\_ from label attr"
#> $ disp_: num 160 160 108 258 360 ...
#> ..- attr(*, "label")= chr "disp\\_ from label attr"
#> $ hp_ : num 110 110 93 110 175 105 245 62 95 123 ...
#> ..- attr(*, "label")= chr "hp\\_ from label attr"
# replace plot's data frame with the one with label attributes.
# Regarding lifecycle warning, `?ggplot2::add_gg` sill states:
# "To replace the current default data frame, you must use %+%,
# due to S3 method precedence issues".
p_label_attr <-
p_ %+%
mtcars_label_attr +
labs(title = "p_label_attr:\nlabels from column attributes")
#> Warning: <ggplot> %+% x was deprecated in ggplot2 4.0.0.
#> ℹ Please use <ggplot> + x instead.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
#> generated.
Or use a dictionary for labels:
## Use labels dictionary with labs()
labels_dict <-
names(mtcars_) |>
paste("from labs dictionary") |>
gsub(x = _, "_", "\\_", fixed = TRUE) |>
setNames(names(mtcars_))
labels_dict
#> mpg_ cyl_
#> "mpg\\_ from labs dictionary" "cyl\\_ from labs dictionary"
#> disp_ hp_
#> "disp\\_ from labs dictionary" "hp\\_ from labs dictionary"
p_labels_dict <-
p_ +
labs(dictionary = labels_dict) +
labs(title = "p_labels_dict:\nlabels from labels dictionary")
Results :
patchwork::wrap_plots(p_, p_label_attr, p_labels_dict)
xfun::session_info(dependencies = FALSE)
#> R version 4.5.1 (2025-06-13 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 11 x64 (build 26100)
#>
#> Locale:
#> LC_COLLATE=English_United Kingdom.utf8
#> LC_CTYPE=English_United Kingdom.utf8
#> LC_MONETARY=English_United Kingdom.utf8
#> LC_NUMERIC=C
#> LC_TIME=English_United Kingdom.utf8
#>
#> Package version:
#> ggplot2_4.0.0 crayon_1.5.3 patchwork_1.3.2 vctrs_0.6.5
#> cli_3.6.5 knitr_1.50 rlang_1.1.6 xfun_0.53
#> generics_0.1.4 textshaping_1.0.3 S7_0.2.0 labeling_0.4.3
#> glue_1.8.0 htmltools_0.5.8.1 ragg_1.5.0 scales_1.4.0
#> rmarkdown_2.29 grid_4.5.1 tibble_3.3.0 evaluate_1.0.5
#> fastmap_1.2.0 yaml_2.3.10 lifecycle_1.0.4 compiler_4.5.1
#> dplyr_1.1.4 fs_1.6.6 RColorBrewer_1.1-3 pkgconfig_2.0.3
#> rstudioapi_0.17.1 systemfonts_1.2.3 farver_2.1.2 digest_0.6.37
#> R6_2.6.1 tidyselect_1.2.1 reprex_2.1.1 curl_7.0.0
#> pillar_1.11.1 magrittr_2.0.4 tools_4.5.1 withr_3.0.2
#> gtable_0.3.6 xml2_1.4.0
Created on 2025-10-06 with reprex v2.1.1