Saving ggplot with expression and unicode in axis title with cairo

Viewed 559

I'd like to save the following plot:

library(ggplot2)

myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab(expression(~delta^13*C~"[\211]"))

ggsave(myplot, 
       filename = "myplot.png", 
       type = "cairo")

But I get the following error:

Error in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y,  : 
  Metric information not available for this family/device

The problem must be the combination of expression and unicode, as those two work:

myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab("[\211]")

myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab(expression(~delta^13*C))

How can I solve this problem?

Edit: I'd like to print the "per mille"-symbol. Apparently its unicode is U2030 and I had mistakenly assumed that "\211" would be a unicode, but must be something else.

Edit 2: In the meantime, I found this question with a similar problem. There, a suggestion is to save the plot with encoding = "MacRoman", which unfortuantely does not work for me:

Error in png_dev(..., res = dpi, units = "in") : 
  unused argument (encoding = "MacRoman")

Edit 3:

> capabilities()["cairo"]
cairo 
 TRUE 
> sessionInfo()
R version 4.0.1 (2020-06-06)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

Matrix products: default

locale:
[1] LC_COLLATE=German_Germany.1252  LC_CTYPE=German_Germany.1252    LC_MONETARY=German_Germany.1252 LC_NUMERIC=C                   
[5] LC_TIME=German_Germany.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] patchwork_1.1.1 ggplot2_3.3.5   dplyr_1.0.7  
2 Answers

Which unicode symbol are you trying to actually use. I guess it is only your syntax for specifying the unicode symbol that is wrong.

Try this code:

myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab(expression(~delta^13*C~"\U0211"))

ggsave(myplot, 
       filename = "myplot.png", 
       type = "cairo")

This works perfectly for me.

Gives a plot that looks like this: enter image description here

You use "\U0211". So "\U for specifying you want unicode and then the code.

Look here for the unicode symbols: https://en.wikipedia.org/wiki/List_of_Unicode_characters

It's the first column you have to input to get the right symbol. So e.g. for U+020F you write "\U020F"

Update

Here an example with the new information about your unicode symbol

myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab(expression(~delta^13*C~"\U2030"))

 ggsave(myplot, 
           filename = "myplot.png", 
           type = "cairo")

Gives me this plot:

enter image description here

Would you mind trying the exact code above? Also try to run without saving - since the saving of the plot actually shouldn't be the issue.

So also try to just run

library("ggplot2")
ggplot(iris) +
      geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
      ylab(expression(~delta^13*C~"\U2030"))

There, take a look if the y-axis label is displayed correctly.

If it still does not work:

It might also be, that the font you are using does not contain the unicode char you are trying to use.

Then add the following to your plot code:

ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab(expression(~delta^13*C~"\U2030")) +
  theme(text=element_text(family="Arial Unicode MS"))

The "Arial Unicode MS" can actually be any font that is available and includes the unicode char in the form that you want it.

Maybe these hints already solve the problem - if not just write another comment, maybe you additionally need some further steps.

Further steps:

Since it still did not work and you mention it seems to be specific to saving with type = cairo try the following:

First provide some more info and check for cairo with this command:

capabilities()["cairo"]

Result should be true.

Then post us some information about your system

sessionInfo()

As these font and plotting things are often dependent on your OS.

Then we make 100% sure, that we have the fonts/unicode symbols available:

library(ggplot2)
install.packages("extrafont")
library("extrafont")
font_import()
loadfonts()
fonts()

The call to fonts() should now gibe output, which fonts are available.

Maybe you can post these infos additionally, that we can give you further steps.

Afterwards you can try again, using extrafonts() alone sometimes already solves the problem:

library("ggplot2")
library("extrafont")
font_import()
loadfonts()

myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab(expression(~delta^13*C~"\U2030")) +
  theme(text=element_text(family="Arial Unicode MS"))
  
ggsave(myplot, 
       filename = "myplot.png", 
       type = "cairo")

As I said capabilities()["cairo"] must have returned true and family="Arial Unicode MS" must be some font that fonts() returned

Also worth trying a different grDevice after getting extrafont ready

library("extrafont")
font_import()
loadfonts()

myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab(expression(~delta^13*C~"\U2030")) +
  theme(text=element_text(family="Arial Unicode MS"))
  
ggsave(myplot, 
       filename = "myplot.png", 
       type = "cairo-png")

There are also more you can try ... here is a very interesting article about saving graphics on different OS. Interestingly depending on your OS and graphic device exported figures look slightly different.

Just read in your comment you want to use Cairo to increase the quality. Try if it works with ragg instead of Cairo - the quality might be even better.

ragg provides a set of high quality and high performance raster devices, capable of producing png, tiff, or ppm files, or a matrix of raw color values directly within R.

ragg is part of our broader effort to improve graphics performance and quality in R at all levels of the stack

library(ragg)

myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab(expression(~delta^13*C~"\U2030")) +
  theme(text=element_text(family="Arial Unicode MS"))

ggsave(
       filename = "myplot3.png",
       myplot,
       device = ragg::agg_png( 
         width = 3000,
         height = 3000, 
         units = "px",
         res = 500)
)

Since you still had now some issues with expression, you can also combine this also with ggtext. Then there is no need for expression.

myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab("\U03B4<sup>13</sup>C\U2030") +
  theme(
    axis.title.y = element_markdown(size = 11, lineheight = 1.2)
  )

ggsave(
       filename = "myplot4.png",
       myplot,
       device = ragg::agg_png( 
         width = 3000,
         height = 3000, 
         units = "px",
         res = 500)
)

Using the package ggtext basically enables you to do all kind of things with your axis title (bold, multiple colors, different sizes, ... all in one label). See also ggtext manual.

Certain unicodes only work with certain fonts. Here is a list of fonts that work with unicode u2030.

The package emojifont makes it easier to use certain unicodes, by rendering the font/family you need to make it possible to save your file. That way you skip having to find the correct font and installing it in your OS.

library(ggplot2)
install.packages('emojifont')
library(emojifont)



myplot <- ggplot(iris) +
  geom_point(aes(x = Sepal.Width, y = Sepal.Length)) +
  ylab(expression(~delta^13*C~"[\u2030]"))


myplot

ggsave(my_plot, 
       filename = "myplot.png", 
       type = "cairo")

It also works with \u211.

Related