R + ggplot + pdf device + LaTeX:是否可以一次嵌入字体
R + ggplot + pdf device + LaTeX: is it possible to embed fonts one time
我有一个 r-scipt,它通过以下方式生成 PDF
...
- 100 多张图表是用
baseplot
和 ggplot
制作的。这些图表是使用 pdf
设备生成的。我使用 pdf
的原因是我需要嵌入字体(在 tex 标签中使用自定义字体)。
- 生成图表后,我调用生成
.tex
的 Sweave
以将所有图表收集在一起。
- 之后我调用
MikTeX
生成 PDF。
事实证明,生成图表所需的 75-95% 的时间都被 embed_fonts
调用占用了。有没有办法减少 embed_fonts
(这似乎是 ghostscript 的包装)调用?理想的 vatiant 是只嵌入调用一次。这可能吗?
也许您可以使用应该嵌入字体的 cairo_pdf
设备。
cairo_pdf
似乎比 pdf
慢但比 pdf + embedFonts
快。
当然,只在最终的 pdf 文档中嵌入字体会是更好的解决方案...
library(microbenchmark)
res_pdf <- microbenchmark({
f = tempfile(fileext = '.pdf')
pdf(f); pairs(iris); dev.off()
})
res_embed <- microbenchmark({
f = tempfile(fileext = '.pdf')
pdf(f); pairs(iris); dev.off()
embedFonts(f)
})
res_cairo <- microbenchmark({
f = tempfile(fileext = '.pdf')
cairo_pdf(f); pairs(iris); dev.off()
})
res_pdf
#> Unit: milliseconds
#> min lq mean median uq max neval
#> 16.67764 17.0388 18.05949 17.32904 18.18776 60.2542 100
res_embed
#> Unit: milliseconds
#>
#> min lq mean median uq max neval
#> 250.046 252.7647 257.4749 255.2785 259.4858 303.0072 100
res_cairo
#> Unit: milliseconds
#>
#> min lq mean median uq max neval
#> 84.25745 86.60512 88.42902 88.36698 89.5705 111.5881 100
另一种解决方案是使用出色的 tikzDevice
包将您的绘图输出为 TikZ。
来自设备设置为 tikz
的 rmarkdown document we can include a knitr 块。
example.Rmd
---
output:
pdf_document:
latex_engine: xelatex
header-includes:
- \renewcommand{\familydefault}{\sfdefault}
- \usepackage{tikz}
---
```{r setup, include=FALSE}
library(tikzDevice)
# setting the package options so that the font metrics are calculated correctly
options(
tikzLatexPackages = c(
getOption("tikzLatexPackages"),
"\renewcommand{\familydefault}{\sfdefault}"
)
)
```
# My plot
This text will be set in the default *sans serif* and so will the text found
within the chart below.
```{r, echo=FALSE, dev='tikz'}
pairs(iris)
```
您可以将我的 \renewcommand{\familydefault}{\sfdefault}
替换为设置所选字体所需的任何乳胶命令,例如 \usepackage{charter}
。请注意,您必须像我上面的示例一样转义 \
。
example.pdf
备选
你可能想提前用另一个脚本生成所有的图,因为你有这么多,而不是在文档生成时内联knitting。我这样做是为了大量 运行 份报告(1,000 多份),每份报告大约有 20 个图。
# a more simple example due to output size
library(tikzDevice)
mpg <- mtcars$mpg
tikz(file = "example.tex"); hist(mpg); dev.off()
example.tex
% Created by tikzDevice version 0.10.1.2 on 2018-02-21 23:32:57
% !TEX encoding = UTF-8 Unicode
\begin{tikzpicture}[x=1pt,y=1pt]
\definecolor{fillColor}{RGB}{255,255,255}
\path[use as bounding box,fill=fillColor,fill opacity=0.00] (0,0) rectangle (216.81,216.81);
\begin{scope}
\path[clip] ( 0.00, 0.00) rectangle (216.81,216.81);
\definecolor{drawColor}{RGB}{0,0,0}
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.20] at (120.41,188.07) {\bfseries Histogram of mpg};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (120.41, 15.60) {mpg};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 10.80,114.41) {Frequency};
\end{scope}
\begin{scope}
\path[clip] ( 0.00, 0.00) rectangle (216.81,216.81);
\definecolor{drawColor}{RGB}{0,0,0}
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 54.47, 61.20) -- (186.34, 61.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 54.47, 61.20) -- ( 54.47, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 80.85, 61.20) -- ( 80.85, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (107.22, 61.20) -- (107.22, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (133.59, 61.20) -- (133.59, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (159.96, 61.20) -- (159.96, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (186.34, 61.20) -- (186.34, 55.20);
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 54.47, 39.60) {10};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 80.85, 39.60) {15};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (107.22, 39.60) {20};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (133.59, 39.60) {25};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (159.96, 39.60) {30};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (186.34, 39.60) {35};
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20, 65.14) -- ( 49.20,163.67);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20, 65.14) -- ( 43.20, 65.14);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20, 81.56) -- ( 43.20, 81.56);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20, 97.98) -- ( 43.20, 97.98);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20,114.40) -- ( 43.20,114.40);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20,130.83) -- ( 43.20,130.83);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20,147.25) -- ( 43.20,147.25);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20,163.67) -- ( 43.20,163.67);
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80, 65.14) {0};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80, 81.56) {2};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80, 97.98) {4};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80,114.40) {6};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80,130.83) {8};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80,147.25) {10};
\end{scope}
\begin{scope}
\path[clip] ( 49.20, 61.20) rectangle (191.61,167.61);
\definecolor{drawColor}{RGB}{0,0,0}
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 54.47, 65.14) rectangle ( 80.85,114.40);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 80.85, 65.14) rectangle (107.22,163.67);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (107.22, 65.14) rectangle (133.59,130.83);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (133.59, 65.14) rectangle (159.96, 81.56);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (159.96, 65.14) rectangle (186.34, 97.98);
\end{scope}
\end{tikzpicture}
N.B. This is not a complete .tex
file and is rather designed to be brought in using \input{example.tex}
or otherwise embedded into a complete document. Also, be mindful of the font metric calculations, the saved .tex
file may render strangely with different fonts if the metrics are significantly out.
我尝试对第 3 步生成的 PDF 执行 embed_fonts
,而不是对第 1 步生成的每个图形调用它,这似乎没问题
我有一个 r-scipt,它通过以下方式生成 PDF
...
- 100 多张图表是用
baseplot
和ggplot
制作的。这些图表是使用pdf
设备生成的。我使用pdf
的原因是我需要嵌入字体(在 tex 标签中使用自定义字体)。 - 生成图表后,我调用生成
.tex
的Sweave
以将所有图表收集在一起。 - 之后我调用
MikTeX
生成 PDF。
事实证明,生成图表所需的 75-95% 的时间都被 embed_fonts
调用占用了。有没有办法减少 embed_fonts
(这似乎是 ghostscript 的包装)调用?理想的 vatiant 是只嵌入调用一次。这可能吗?
也许您可以使用应该嵌入字体的 cairo_pdf
设备。
cairo_pdf
似乎比 pdf
慢但比 pdf + embedFonts
快。
当然,只在最终的 pdf 文档中嵌入字体会是更好的解决方案...
library(microbenchmark)
res_pdf <- microbenchmark({
f = tempfile(fileext = '.pdf')
pdf(f); pairs(iris); dev.off()
})
res_embed <- microbenchmark({
f = tempfile(fileext = '.pdf')
pdf(f); pairs(iris); dev.off()
embedFonts(f)
})
res_cairo <- microbenchmark({
f = tempfile(fileext = '.pdf')
cairo_pdf(f); pairs(iris); dev.off()
})
res_pdf
#> Unit: milliseconds
#> min lq mean median uq max neval
#> 16.67764 17.0388 18.05949 17.32904 18.18776 60.2542 100
res_embed
#> Unit: milliseconds
#>
#> min lq mean median uq max neval
#> 250.046 252.7647 257.4749 255.2785 259.4858 303.0072 100
res_cairo
#> Unit: milliseconds
#>
#> min lq mean median uq max neval
#> 84.25745 86.60512 88.42902 88.36698 89.5705 111.5881 100
另一种解决方案是使用出色的 tikzDevice
包将您的绘图输出为 TikZ。
来自设备设置为 tikz
的 rmarkdown document we can include a knitr 块。
example.Rmd
---
output:
pdf_document:
latex_engine: xelatex
header-includes:
- \renewcommand{\familydefault}{\sfdefault}
- \usepackage{tikz}
---
```{r setup, include=FALSE}
library(tikzDevice)
# setting the package options so that the font metrics are calculated correctly
options(
tikzLatexPackages = c(
getOption("tikzLatexPackages"),
"\renewcommand{\familydefault}{\sfdefault}"
)
)
```
# My plot
This text will be set in the default *sans serif* and so will the text found
within the chart below.
```{r, echo=FALSE, dev='tikz'}
pairs(iris)
```
您可以将我的 \renewcommand{\familydefault}{\sfdefault}
替换为设置所选字体所需的任何乳胶命令,例如 \usepackage{charter}
。请注意,您必须像我上面的示例一样转义 \
。
example.pdf
备选
你可能想提前用另一个脚本生成所有的图,因为你有这么多,而不是在文档生成时内联knitting。我这样做是为了大量 运行 份报告(1,000 多份),每份报告大约有 20 个图。
# a more simple example due to output size
library(tikzDevice)
mpg <- mtcars$mpg
tikz(file = "example.tex"); hist(mpg); dev.off()
example.tex
% Created by tikzDevice version 0.10.1.2 on 2018-02-21 23:32:57
% !TEX encoding = UTF-8 Unicode
\begin{tikzpicture}[x=1pt,y=1pt]
\definecolor{fillColor}{RGB}{255,255,255}
\path[use as bounding box,fill=fillColor,fill opacity=0.00] (0,0) rectangle (216.81,216.81);
\begin{scope}
\path[clip] ( 0.00, 0.00) rectangle (216.81,216.81);
\definecolor{drawColor}{RGB}{0,0,0}
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.20] at (120.41,188.07) {\bfseries Histogram of mpg};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (120.41, 15.60) {mpg};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 10.80,114.41) {Frequency};
\end{scope}
\begin{scope}
\path[clip] ( 0.00, 0.00) rectangle (216.81,216.81);
\definecolor{drawColor}{RGB}{0,0,0}
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 54.47, 61.20) -- (186.34, 61.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 54.47, 61.20) -- ( 54.47, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 80.85, 61.20) -- ( 80.85, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (107.22, 61.20) -- (107.22, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (133.59, 61.20) -- (133.59, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (159.96, 61.20) -- (159.96, 55.20);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (186.34, 61.20) -- (186.34, 55.20);
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 54.47, 39.60) {10};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 80.85, 39.60) {15};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (107.22, 39.60) {20};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (133.59, 39.60) {25};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (159.96, 39.60) {30};
\node[text=drawColor,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at (186.34, 39.60) {35};
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20, 65.14) -- ( 49.20,163.67);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20, 65.14) -- ( 43.20, 65.14);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20, 81.56) -- ( 43.20, 81.56);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20, 97.98) -- ( 43.20, 97.98);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20,114.40) -- ( 43.20,114.40);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20,130.83) -- ( 43.20,130.83);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20,147.25) -- ( 43.20,147.25);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 49.20,163.67) -- ( 43.20,163.67);
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80, 65.14) {0};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80, 81.56) {2};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80, 97.98) {4};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80,114.40) {6};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80,130.83) {8};
\node[text=drawColor,rotate= 90.00,anchor=base,inner sep=0pt, outer sep=0pt, scale= 1.00] at ( 34.80,147.25) {10};
\end{scope}
\begin{scope}
\path[clip] ( 49.20, 61.20) rectangle (191.61,167.61);
\definecolor{drawColor}{RGB}{0,0,0}
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 54.47, 65.14) rectangle ( 80.85,114.40);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] ( 80.85, 65.14) rectangle (107.22,163.67);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (107.22, 65.14) rectangle (133.59,130.83);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (133.59, 65.14) rectangle (159.96, 81.56);
\path[draw=drawColor,line width= 0.4pt,line join=round,line cap=round] (159.96, 65.14) rectangle (186.34, 97.98);
\end{scope}
\end{tikzpicture}
N.B. This is not a complete
.tex
file and is rather designed to be brought in using\input{example.tex}
or otherwise embedded into a complete document. Also, be mindful of the font metric calculations, the saved.tex
file may render strangely with different fonts if the metrics are significantly out.
我尝试对第 3 步生成的 PDF 执行 embed_fonts
,而不是对第 1 步生成的每个图形调用它,这似乎没问题