我有一堆使用 Matplotlib 的 PGF 后端制作的图表。为了避免在样式发生变化时使用 Matplotlib 重新生成所有这些图表,我更喜欢\input
直接在文档中使用 PGF 文件。这很好,但这意味着 arXiv 不允许我的 16 MB 源。
有没有办法可以像处理 TikZ 文件一样将 PGF 文件外部化?我真的想避免重新生成所有图,因为这非常耗时。
答案1
一种解决方法是生成一个单独的 PDF pgfpicture
,每页一个,然后将输入替换为\includegraphics
。standalone
该类使这变得简单,例如:
\documentclass{standalone}
\usepackage{pgf}
\standaloneenv{pgfpicture}
\begin{document}
\input{onefigure.pgf}
\input{anotherfigure.pgf}
\end{document}
将其保存为 egfigs.tex
并进行编译。在您的手稿中,将\includegraphics[page=1]{figs}
其替换为\input{onefigure}
,其他的类似操作。当然,如果愿意的话,您可以为每个图创建一个 PDF。
答案2
我遇到了同样的问题,并编写了自己的包来自动处理它。你可以找到它这里。如果您不想安装该软件包,您可以将此代码放入您的序言中:
\makeatletter
\edef\@figdir{_pgfcache}
\catcode`\#=11
\catcode`\|=6
\newcommand{\@basicpgfpreamble}[1]{%
\unexpanded{%
\documentclass{standalone}^^J
\usepackage{pgf}^^J
\let\oldpgfimage\pgfimage^^J
\renewcommand{\pgfimage}[2][]{\oldpgfimage[#1]{|1/#2}}^^J
}%
}
\catcode`\#=6
\catcode`\|=12
\let\@pgfpreamble\@basicpgfpreamble
\newcommand{\setpgfpreamble}[1]{%
\renewcommand{\@pgfpreamble}[1]{\@basicpgfpreamble{##1}\unexpanded{#1}}
}
\newcounter{@pgfcounter}
\newwrite\@pgfout
\newread\@pgfin
\newcommand{\importpgf}[3][]{%
\IfFileExists{#2/#3}{}{\errmessage{importpgf: File #2/#3 not found}}%
\edef\@figfile{\jobname-\the@pgfcounter}%
\providecommand{\@writetempfile}{}%
\renewcommand{\@writetempfile}[1]%
{%
\immediate\openout\@pgfout=##1%
\immediate\write\@pgfout{\@pgfpreamble{#2}}%
\immediate\write\@pgfout{\string\begin{document}}%
\immediate\openin\@pgfin=#2/#3%
\begingroup\endlinechar=-1%
\loop\unless\ifeof\@pgfin%
\readline\@pgfin to \@fileline%
\ifx\@fileline\@empty\else%
\immediate\write\@pgfout{\@fileline}%
\fi%
\repeat%
\endgroup%
\immediate\closein\@pgfin%
\immediate\write\@pgfout{\string\end{document}}%
\immediate\closeout\@pgfout%
}%
\def\@compile%
{%
\immediate\write18{pdflatex -interaction=batchmode -output-directory="\@figdir" \@figdir/\@figfile.tex}%
}%
\IfFileExists{\@figdir/\@figfile.pdf}%
{%
\@writetempfile{\@figdir/tmp.tex}%
\edef\@hashold{\pdfmdfivesum file {\@figdir/\@figfile.tex}}%
\edef\@hashnew{\pdfmdfivesum file {\@figdir/tmp.tex}}%
\ifnum\pdfstrcmp{\@hashold}{\@hashnew}=0%
\relax%
\else%
\@writetempfile{\@figdir/\@figfile.tex}%
\@compile%
\fi%
}%
{%
\@writetempfile{\@figdir/\@figfile.tex}%
\@compile%
}%
\IfFileExists{\@figdir/\@figfile.pdf}%
{\includegraphics[#1]{\@figdir/\@figfile.pdf}}%
{\errmessage{Error during compilation of figure #2/#3}}%
\stepcounter{@pgfcounter}%
}
\makeatother
这为您提供了两个命令,\setpgfpreamble
并且\importpgf
.\importpgf
执行两件事:
检查名为 的文件夹中是否已存在图形的预编译 PDF 版本
_figurecache
(您可能需要创建此文件夹)。如果是,它只会使用 包含该 PDF\includegraphics
。如果没有,它会调用pdflatex
编译图形,然后包含它。如果图形的来源发生变化(通过文件的 MD5 校验和检查),也会重新编译图形。它会修补
\pgfimage
PGF 图形中的命令,因此您可以包含使用 Matplotlib 创建的栅格化部分,即使它们位于子文件夹中(如上所述这里)。
您可以像这样使用命令:
\importpgf{path/to/file}{myfigure.pgf}
使用\setpgfpreamble
,您可以定义编译 PGF 图像所需的附加包(例如字体或数学包):
\setpgfpreamble{%
\usepackage{libertine}
\usepackage{amsmath}
\usepackage{siunitx}
}
唯一的依赖项是standalone
和pgf
包。如果您有大量图形,第一次编译将需要很长时间,但后续编译将快得多。
注意事项:它可能不太便携(仅在您使用 PDFLaTeX 时才有效;pdflatex
可执行文件必须在您的路径上;并且您必须使用 进行编译-shell-escape
)。此外,错误检查是有限的,因此如果您遇到麻烦,请检查文件夹中的日志_figurecache
以查找错误(您可能忘记包含 包\setpgfpreamble
)。
答案3
这是一个不太好的解决方案,可能在任何情况下都行不通。其思路是先用环境替换pgfpicture
环境tikzpicture
,然后使用外部化。
为此,您可以:
- 使用包在宏中读取您的文件
catchfile
; patchcmd
使用来修补此宏etoolbox
以替换pgfpicture
为tikzpicture
;- 把所有这些都放入一个
\mypgfimport
设置的宏中\tikzsetfigurename
。
以下是代码:
% ------------------------------------
% example file blablatest.pgf
\begin{filecontents}{blablatest.pgf}
\begin{pgfpicture}
\pgfpathsvg{M 0 0 l 20 0 0 20 -20 0 q 10 0 10 10
t 10 10 10 10 h -50 z}
\pgfusepath{stroke}
\end{pgfpicture}
\end{filecontents}
% ------------------------------------
\documentclass[border=7mm]{standalone}
\usepackage{catchfile}
\usepackage{etoolbox}
\usepackage{tikz}
\usepgflibrary{svg.path}
\usetikzlibrary{external}\tikzexternalize
\def\mypgfimport#1{%
\tikzsetfigurename{#1}
\CatchFileDef{\tempmacro}{#1.pgf}{}%
\patchcmd{\tempmacro}{\begin{pgfpicture}}{\begin{tikzpicture}[red]}{}{}%
\patchcmd{\tempmacro}{\end{pgfpicture}}{\end{tikzpicture}}{}{}%
\tempmacro%
}
\begin{document}
\mypgfimport{blablatest}
\end{document}