![为什么在删除/注释掉一张 tikzpicture 后,Tikzexternalize 需要这么长时间?我该如何解决?](https://linux22.com/image/460815/%E4%B8%BA%E4%BB%80%E4%B9%88%E5%9C%A8%E5%88%A0%E9%99%A4%2F%E6%B3%A8%E9%87%8A%E6%8E%89%E4%B8%80%E5%BC%A0%20tikzpicture%20%E5%90%8E%EF%BC%8CTikzexternalize%20%E9%9C%80%E8%A6%81%E8%BF%99%E4%B9%88%E9%95%BF%E6%97%B6%E9%97%B4%EF%BC%9F%E6%88%91%E8%AF%A5%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3%EF%BC%9F.png)
我正在使用 tikzpictures 和 pgfplots 创建带有解决方案的练习表。我充分利用了外部化库以加快编译时间。但是,我注意到,编辑文档中现有的 tikzpicture 对编译时间的减慢影响比简单地注释掉一个特定的 tikzpicture 要小得多。在下面的示例中(初始编译之后),更改要绘制的函数的方程式需要我的计算机 3 秒钟来编译 pdf,而注释掉整个中间 tikzpicture 会导致编译时间约为 13 秒,尽管实际上渲染的时间更少。
\documentclass{article}
\usepackage{float}
\usepackage{tikz}
\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}
\pgfplotsset{compat=1.18}
\usepgfplotslibrary{external}
\tikzexternalize[prefix=tikzcache/]
\begin{document}
Some text to pose a question.
\begin{figure}[H]
\begin{tikzpicture}
\foreach \i in {1,...,2000} {
\draw[thin,rounded corners=8pt] ({\i*0.05},0) -- ({\i*0.05},2) -- ({1+\i*0.05},3.25) -- ({2+\i*0.05},2) -- ({2+\i*0.05},0) -- ({\i*0.05},2) -- ({2+\i*0.05},2) -- ({\i*0.05},0) -- ({2+\i*0.05},0);
}
\end{tikzpicture}
\caption{A time consuming tikzpicture to represent several tikz pictures.}
\end{figure}
The particular question/solution with tikzpicture editing/commenting out/deleting.
\begin{figure}[H]
% \begin{tikzpicture}
% \begin{axis}[
% axis lines = middle,
% axis on top = true,
% grid = both,
% ]
% \addplot[very thick, samples=30, smooth,domain=-5:5]{1-x}; % edit the equation for the function here
% \end{axis}
% \end{tikzpicture}
\end{figure}
Some more text to pose a question.
\begin{figure}[H]
\begin{tikzpicture}
\foreach \i in {1,...,2000} {
\draw[thin,rounded corners=8pt] ({\i*0.05},0) -- ({\i*0.05},2) -- ({1+\i*0.05},3.25) -- ({2+\i*0.05},2) -- ({2+\i*0.05},0) -- ({\i*0.05},2) -- ({2+\i*0.05},2) -- ({\i*0.05},0) -- ({2+\i*0.05},0);
}
\end{tikzpicture}
\caption{Another time consuming tikzpicture to represent several tikz pictures.}
\end{figure}
\end{document}
我查看了外部化库的手册,怀疑它可能与不同 tikzpicture 的索引有关。删除/注释掉 tikzpicture 会导致外部化库对每个 tikzpicture 进行计数,因此删除的 tikzpicture 之后的所有 tikzpicture 都必须重新编译,即使它们没有改变。事实上,第一次编译上面没有中间 tikzpicture 的示例需要我的计算机 25 秒,大约是注释掉中间 tikzpicture 后时间的两倍。
有办法解决这个问题吗?我可以向外部化库明确说明后续的 tikzpictures 没有改变吗,例如通过tikzcache/
更好地链接以前生成的文件?
答案1
正如其他人所指出的,没有内置方法可以自动执行此操作。如果将每张图片放入单独的文件中,则可以在此基础上自动为外部化的图片分配名称。或者,您可以尝试两个支持外部化的新软件包之一:memoize
或robust-externalize
。两者都使用哈希而不是连续 ID,因此插入或删除图片不会导致重新编译所有后续图片。此外,两者都旨在将除tikzpicture
s 之外的其他内容外部化。
下面是一个示例memoize
。我首先编译了包含 2 张图片的版本。这产生了两个新的外部人员。然后我取消注释中间的那个。下一次编译只产生了一个新的外部。由于现在的图片三与原来的图片二完全相同,因此无需重新编译。
\documentclass{article}
\usepackage{memoize}
\mmzset{%
path={dir=memos},
mkdir,
}
\usepackage{float}
\usepackage{tikz}
\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}
\pgfplotsset{compat=1.18}
\begin{document}
Some text to pose a question.
\begin{figure}% don't use H
\begin{tikzpicture}
\foreach \i in {1,...,2000} {
\draw[thin,rounded corners=8pt] ({\i*0.05},0) -- ({\i*0.05},2) -- ({1+\i*0.05},3.25) -- ({2+\i*0.05},2) -- ({2+\i*0.05},0) -- ({\i*0.05},2) -- ({2+\i*0.05},2) -- ({\i*0.05},0) -- ({2+\i*0.05},0);
}
\end{tikzpicture}
\caption{A time consuming tikzpicture to represent several tikz pictures.}
\end{figure}
The particular question/solution with tikzpicture editing/commenting out/deleting.
\begin{figure}% don't use H
\begin{tikzpicture}
\begin{axis}[
axis lines = middle,
axis on top = true,
grid = both,
]
\addplot[very thick, samples=30, smooth,domain=-5:5]{1-x}; % edit the equation for the function here
\end{axis}
\end{tikzpicture}
\end{figure}
Some more text to pose a question.
\begin{figure}% don't use H
\begin{tikzpicture}
\foreach \i in {1,...,2000} {
\draw[thin,rounded corners=8pt] ({\i*0.05},0) -- ({\i*0.05},2) -- ({1+\i*0.05},3.25) -- ({2+\i*0.05},2) -- ({2+\i*0.05},0) -- ({\i*0.05},2) -- ({2+\i*0.05},2) -- ({\i*0.05},0) -- ({2+\i*0.05},0);
}
\end{tikzpicture}
\caption{Another time consuming tikzpicture to represent several tikz pictures.}
\end{figure}
\end{document}
我目前无法使用memoize
,因此我仍在使用external
库,但我的大多数图片都在外部文件中,我使用以下包装器根据这些文件名获取外部名称。这并不能完全消除不必要的重新编译(或缺少必要的编译)的问题,但它确实有很大帮助。
% tikzlibrarycfrexternal.code.tex
\RequirePackage{svn-prov}
\ProvidesFileSVN{$Id: tikzlibrarycfrexternal.code.tex 8646 2019-10-04 16:38:17Z cfr $}
% addaswyd o ateb: http://tex.stackexchange.com/a/334290/ i gwestiwn rpapa: http://tex.stackexchange.com/q/334250/
% RHYBUDD! ref. sylwad David Carlisle https://chat.stackexchange.com/transcript/message/42967388#42967388
% rhaid cynnwys % ar ôl \begin{document}% i osgoi space ychwanegol ***
\RequirePackage{etoolbox,currfile,xparse}
\@ifclassloaded{standalone}{\relax}{\RequirePackage{standalone}}
\usetikzlibrary{external}
\ExplSyntaxOn
\tl_new:N \g_enext_figurename_tl
\tl_new:N \l_enext_tmpa_tl
\seq_new:N \l_enext_tmpa_seq
\cs_new_protected_nopar:Nn \enext_settofilename:
{% RHYBUDD: yn fewnol % \l__file_base_name_str
% hopefully allows use of \file_input as well as \input
\seq_set_split:NnV \l_enext_tmpa_seq { / } { \g_file_curr_name_str } % \l__file_base_name_str
\seq_pop_right:NN \l_enext_tmpa_seq \l_enext_tmpa_tl
\enext_tikzsetfigurename:x { \l_enext_tmpa_tl- }
}
\cs_new_protected_nopar:Nn \enext_settofilename:n
{% RHYBUDD: \l__ior_file_name_tl yn fewnol % \l__file_base_name_str
\seq_set_split:Nnn \l_enext_tmpa_seq { / } { #1 }
\seq_pop_right:NN \l_enext_tmpa_seq \l_enext_tmpa_tl
\enext_tikzsetfigurename:x { \l_enext_tmpa_tl- }
}
\cs_new_protected_nopar:Nn \enext_tikzsetfigurename:n
{
\tikzsetfigurename { #1 }
}
\cs_generate_variant:Nn \enext_tikzsetfigurename:n { x }
\cs_new_protected_nopar:Nn \enext_tikzsetnextfilename:n
{
\tikzsetnextfilename { #1 }
}
\cs_generate_variant:Nn \enext_tikzsetnextfilename:n { V }
\cs_new_protected_nopar:Nn \enext_setfigurename:
{
\enext_settofilename:
\enext_tikzsetnextfilename:V \g_enext_figurename_tl
}
\cs_new_protected_nopar:Nn \enext_setfigurename:n
{
\enext_tikzsetfigurename:n { #1 }
\enext_tikzsetnextfilename:V \g_enext_figurename_tl
}
\cs_generate_variant:Nn \enext_setfigurename:n { x }
\msg_new:nnnn { enext } { append ~ failed }
{
\msg_warning_text:n { enext } ~ :: ~ Append ~ to ~ #1 ~ failed ~ \msg_line_context: !
}
{
This ~ is ~ probably ~ not ~ your ~ fault ~ unless ~ you ~ redefined ~ the ~ modified ~ functions. ~
Either ~ fix ~ the ~ code ~ yourself ~ or ~ ask ~ for ~ help. ~
Apologies ~ for ~ any ~ inconvenience. ~
All ~ code ~ provided ~ as-is ~ for ~ use ~ at ~ your ~ own ~ risk! ~
As ~ a ~ goodwill ~ gesture, ~ a ~ full ~ refund ~ will ~ be ~ provided ~ on ~ request, ~ less ~ a ~ small ~ fee ~ to ~ cover ~ administration.
}
\msg_new:nnn { enext } { append ~ succeeded }
{
\msg_warning_text:n { enext } ~ :: ~ Modified ~ #1 ~ \msg_line_context: !
}
\NewDocumentCommand \extinput { m }
{
\group_begin:
\enext_settofilename:n { #1 }% hopefully allows use of \file_input rather than \input
\file_input:n { #1 }
\group_end:
}
\apptocmd \sa@document
{% ddim yn gywir o gwbl
\tl_if_empty:NTF \g_file_curr_name_str% \l__file_base_name_str
{
\enext_setfigurename:x { \currfilebase- }
}
{
\enext_setfigurename:
}
}{
\msg_warning:nnn { enext } { append ~ succeeded } { document ~ environment }
}{
\msg_warning:nnn { enext } { append ~ failed } { document ~ environment }
}
\apptocmd \tikzsetnextfilename
{
\tl_gset:Nn \g_enext_figurename_tl { #1 }
}{
\msg_warning:nnn { enext } { append ~ succeeded } { \tikzsetnextfilename }
}{
\msg_warning:nnn { enext } { append ~ failed } { \tikzsetnextfilename }
}
\apptocmd \tikzexternal@getnextfilename@resetglobals
{
\tl_gclear:N \g_enext_figurename_tl
}{
\msg_warning:nnn { enext } { append ~ succeeded } { \tikzexternal@getnextfilename@resetglobals }
}{
\msg_warning:nnn { enext } { append ~ failed } { \tikzexternal@getnextfilename@resetglobals }
}
\ExplSyntaxOff
\endinput
加载cfrexternal
并继续执行external
。请注意,虽然这对我来说效果很好,但它远非稳健,并且按原样提供,使用风险自负。它甚至无法避免无人维护的库的问题external
,因为它所做的只是加载它并增加大量额外的脆弱性。
买者自负 ...
答案2
在仔细查看了外部化库的文档之后,确实有一种(手动)方法可以将 tikzpictures 与其外部化输出更紧密地联系起来,即tikzsetnextfilename
如上所述这里。然后改变顺序或删除一个 tikzpicture 对其他(已生成的)tikzpicture 的识别和总编译时间没有影响。据我在手册中所知,没有自动(不依赖于 tikzpictures 的先前顺序)的方法可以做到这一点。
\documentclass{article}
\usepackage{float}
\usepackage{tikz}
\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}
\pgfplotsset{compat=1.18}
\usepgfplotslibrary{external}
\tikzexternalize[prefix=tikzcache/]
\begin{document}
Some text to pose a question.
\begin{figure}[H]
\tikzsetnextfilename{image1} % adding ID myself
\begin{tikzpicture}
\foreach \i in {1,...,1000} {
\draw[thin,rounded corners=8pt] ({\i*0.05},0) -- ({\i*0.05},2) -- ({1+\i*0.05},3.25) -- ({2+\i*0.05},2) -- ({2+\i*0.05},0) -- ({\i*0.05},2) -- ({2+\i*0.05},2) -- ({\i*0.05},0) -- ({2+\i*0.05},0);
}
\end{tikzpicture}
\caption{A time consuming tikzpicture to represent several tikz pictures.}
\end{figure}
The particular question/solution with tikzpicture editing/commenting out/deleting.
\begin{figure}[H]
% \tikzsetnextfilename{image2} % adding ID myself
% \begin{tikzpicture}
% \begin{axis}[
% axis lines = middle,
% axis on top = true,
% grid = both,
% ]
% \addplot[very thick, samples=30, smooth,domain=-5:5]{1-x}; % edit the equation for the function here
% \end{axis}
% \end{tikzpicture}
\end{figure}
Some more text to pose a question.
\begin{figure}[H]
\tikzsetnextfilename{image3} % adding ID myself
\begin{tikzpicture}
\foreach \i in {1,...,1000} {
\draw[thin,rounded corners=8pt] ({\i*0.05},0) -- ({\i*0.05},2) -- ({1+\i*0.05},3.25) -- ({2+\i*0.05},2) -- ({2+\i*0.05},0) -- ({\i*0.05},2) -- ({2+\i*0.05},2) -- ({\i*0.05},0) -- ({2+\i*0.05},0);
}
\end{tikzpicture}
\caption{Another time consuming tikzpicture to represent several tikz pictures.}
\end{figure}
\end{document}