为什么在删除/注释掉一张 tikzpicture 后,Tikzexternalize 需要这么长时间?我该如何解决?

为什么在删除/注释掉一张 tikzpicture 后,Tikzexternalize 需要这么长时间?我该如何解决?

我正在使用 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

正如其他人所指出的,没有内置方法可以自动执行此操作。如果将每张图片放入单独的文件中,则可以在此基础上自动为外部化的图片分配名称。或者,您可以尝试两个支持外部化的新软件包之一:memoizerobust-externalize。两者都使用哈希而不是连续 ID,因此插入或删除图片不会导致重新编译所有后续图片。此外,两者都旨在将除tikzpictures 之外的其他内容外部化。

下面是一个示例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}

相关内容