ggplot2 PDF输出中的Unicode字符

Posted

技术标签:

【中文标题】ggplot2 PDF输出中的Unicode字符【英文标题】:Unicode Characters in ggplot2 PDF Output 【发布时间】:2012-09-27 21:41:45 【问题描述】:

如何在使用 ggplot2 创建的 PDF 图中将 Unicode 字符用于标签、标题和类似内容?

考虑以下示例:

library(ggplot2)
qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ")
ggsave("t.pdf")

情节的标题使用 Unicode 字符(小型大写字母),在输出中显示为 ...。该问题仅出现在 pdf 绘图中;如果我将最后一行替换为ggsave("t.png"),则输出符合预期。

我做错了什么?我拥有的 R 脚本采用 UTF-8 编码。一些系统信息:

R version 2.14.1 (2011-12-22)
Platform: x86_64-pc-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=C                 LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

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

在寻找这个问题的解决方案时,我发现了一些evidence,R 使用单字节编码进行多字节编码,例如用于 PDF 或 postscript 输出的 UTF-8。我还找到了一些建议,例如,能够获得Euro sign working,但没有通用的解决方案。

【问题讨论】:

cairo_pdf("t.pdf"); ...; dev.off() 为我工作...见***.com/questions/5886018/… 【参考方案1】:

正如 Ben 所建议的,cairo_pdf() 是你的朋友。它还允许您通过 family 参数在 PDF 中嵌入非 postscript 字体(即 TTF/OTF)(如果您碰巧没有包含要使用的字形的任何 postscript 字体,则至关重要)。例如:

library(ggplot2)
cairo_pdf("example.pdf", family="DejaVu Sans")
qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ")
dev.off()

...给出如下所示的 PDF:

另见this question;虽然它看起来与标题没有直接关系,但其中有很多关于让字体在 R 中做你想做的事情。

EDIT cmets 中的每个请求,这里是特定于 windows 的代码:

library(ggplot2)
windowsFonts(myCustomWindowsFontName=windowsFont("DejaVu Sans"))
cairo_pdf("example.pdf", family="myCustomWindowsFontName")
qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ")
dev.off()

要使用基本图形命令cairo_pdf(),首先使用windowsFonts() 命令定义字体系列就足够了,如上所示。当然,请确保您使用系统上实际拥有的字体,并且该字体实际上具有您需要的所有字形。

T以下 cmets 中有关 DLL 文件的说明是我必须执行的操作,以使 library(Cairo) 中的 Cairo()CairoPDF() 命令在 Windows 上工作。那么:

library(ggplot2)
library(Cairo)
windowsFonts(myCustomWindowsFontName=windowsFont("DejaVu Sans"))
CairoPDF("example.pdf")
par(family="myCustomWindowsFontName")
qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ")
dev.off()

【讨论】:

谢谢,这适用于我在 Linux 上。我还没有在 Windows 上使用它,既没有使用您提供的代码,也没有使用CairoPDF 让 Cairo 包在 Windows 上运行是一件棘手的事情。我为它写了一个小教程here。这有帮助吗? 要让 Cairo 库在 Windows 上运行,请转到 this page,单击 Windows(32/64 位),并在“必需的第三方依赖项”下下载 zlib、cairo、 libpng、fontconfig、freetype 和 expat。解压并收集所有DLL并放入:C:\Program Files\R\R-2.14.0\bin\i386(或在64位系统上C:\Program Files\R\R-2.14.0\bin\x64) .还将 fonts.conf 文件从 fontconfig zip 文件移动到 C:\Program Files\R\R-2.14.0\etc\i386\fonts\。在 64 位系统上,将路径名中的“i386”替换为“x64”;无论您的 R 版本是什么,也可以低于 2.14.0。 感谢您的帮助,但它仍然不适合我。我遵循了您的所有步骤,但是当我执行上面示例中的代码时,标题仍然是垃圾。轴标签正常工作(使用不同字体时也是如此),只是使用 Unicode 字符的标题被弄乱了。输出是“空设备”,不确定是否符合预期。 添加了特定于 Windows 的代码,取自 this question 已在原始答案中提到。如果 that 不起作用,那么您的 R 版本可能是在不支持基于 cairo 的图形的情况下编译的。【参考方案2】:

截至 2020 年和 R 版本 4.0.3,cairo_pdf() 不再是您在 Mac OS X 上的朋友,至少就西里尔文而言 - 请参阅失败图库如下。

TL;DR

如果您必须有西里尔文,只需返回良好的 ole png 驱动程序。 (和你的抗锯齿图告别。)

R -e 'png(filename = "ftw.png"); library(ggplot2); qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ"); dev.off()'
open ftw.png

或者,如果您将Rmarkdown 与 knitr 一起使用:

R -e 'rmarkdown::render("foo.Rmd", "pdf_document", output_file="foo.pdf", runtime = "static", output_options = list(dev = "png"))'

失败画廊

开罗的“现代”方法在 v4.0.3 中失败,如下所示。请注意,这不是(或不仅仅是)字体嵌入或渲染问题,因为从生成的 PDF 中选择和粘贴文本也会产生乱码输出。

准备步骤:

    install the latest R(4.0.3 或更高版本,所有capabilities() 都显示TRUER -e 'install.packages(c("Cairo", "ggplot2"), repos="https://cloud.r-project.org")'

原版配置

R -e 'library(ggplot2); qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ"); ggsave("fail1.pdf")'
open fail1.pdf

单独使用cairo_pdf()

R -e 'cairo_pdf("fail2.pdf"); library(ggplot2); qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ"); dev.off()'
open fail2.pdf

cairo_pdf() 与自定义(假定符合Unicode)字体一起使用

R -e 'cairo_pdf("fail3.pdf", family = "Arial Unicode MS"); library(ggplot2); qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ"); dev.off()'
open fail3.pdf

Comic Sans 的另一次尝试:

R -e 'cairo_pdf("fail3bis.pdf", family = "Comic Sans MS"); library(ggplot2); qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ"); dev.off()'
open fail3bis.pdf

还有一些...

使用较旧的“黑暗和暴风雨之夜”版本(3.6.2):

/Library/Frameworks/R.framework/Versions/3.6/Resources/bin/R -e 'cairo_pdf("fail4.pdf", family = "Arial Unicode MS"); library(ggplot2); qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ"); dev.off()'
open fail4.pdf

按照@drammock 的建议使用DejaVu Sans

R -e 'cairo_pdf("fail5.pdf", family = "DejaVu Sans"); library(ggplot2); qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ"); dev.off()'
open fail5.pdf

旧 R 上的 DejaVu Sans:

/Library/Frameworks/R.framework/Versions/3.6/Resources/bin/R -e 'cairo_pdf("fail5bis.pdf", family = "DejaVu Sans"); library(ggplot2); qplot(Sepal.Length, Petal.Length, data=iris, main="Aʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ"); dev.off()'
open fail5bis.pdf

【讨论】:

字体“符合 unicode”并不意味着它在每个代码点都包含字形。如果您使用我的答案(DejaVu Sans)中显示的字体,它会失败吗?我的答案中的许多小型大写字形都在 unicode 的“语音扩展”块中,Comic Sans 或 Arial MS 中很可能不存在。 @drammock DejaVu Sans 确实是最接近工作的一种(就成功渲染字形的数量而言,与 Arial Unicode MS 并列)。更新了失败图库。 奇怪的是,即使使用 DejaVu Sans 也无法正常工作。 DejaVu Sans 字形表 (dejavu.sourceforge.net/samples/DejaVuSans.pdf) 的第 22 页表明它确实至少有 ᴄ,ᴅ,ᴇ 字形,这些字形并没有出现在您面前(我没有检查每个字形)。值得注意的是,所有失败的代码点都是U+1xxx,而所有成功的代码点都是U+0xxx,所以我怀疑是编码问题而不是字体问题。 我很高兴我不是唯一一个遇到这个问题的人。让我感觉不那么孤单了【参考方案3】:

如果您使用ggsave(...),您可以致电ggsave(..., device=cairo_pdf)

您需要先安装并加载 Cairo 绑定。

install.packages("Cairo")
library(Cairo)

这是full example(不是我的作品)。

【讨论】:

Cairo 包和grDevices::cairo_pdf 有什么关系?

以上是关于ggplot2 PDF输出中的Unicode字符的主要内容,如果未能解决你的问题,请参考以下文章

PDF 中的 Unicode

使用PHP json_encode时输出阿拉伯语(Unicode)字符

Ruby 输出 Unicode 字符

iText PDF中的Unicode字符

比较准确完整的中文字符正则校验

Unicode Python 字符串中的字节数