编辑2:
所以问题在于,tikzpicture
在生成哈希之前,环境中的代码没有被扩展.md5
。因此,内容不会随着不同的输入而改变。
现在,我有一个想法,.md5
为我的命令的输入创建一个自己的哈希值,然后将其存储在单独的文件中。
\newwrite\tempfile%
\immediate\openout\tempfile=./\csvPlotOutputDir/\csvPlotLabel._md5%
\immediate\write\tempfile{\pdfmdfivesum{#1}}%
\immediate\closeout\tempfile%
这似乎很有效。当选项被修改时,它会改变哈希值。现在我正在寻找一种方法来评估该文件中的更改。
编辑1:
运行时latexmk
,.md5
会为每个外部化图生成一个文件。但是,在我更改\csvplot[]{}
命令和编译的某些选项后,它不会重新创建。
因此,如果我更改选项列表中的某些内容,文件的内容.md5
实际上不会改变。为什么会这样?当我清理辅助文件并使用更改重新编译时,编译文档中的输出是不同的。
我编写了自己的软件包,用于使用不同的设置绘制 .csv 文件。例如,我可以选择使用简单的列名列表绘制 .csv 的某些列,并将其作为参数传递给我的命令。
但是,我也想使用 Tikz externalize,并且我通常使用 latexmk 进行编译。因为我想使用尽可能多的 CPU 核心,所以我使用 externalization 选项[mode=list and make]
。
因此,编译流程如下:
latexmk -pdf file.tex
make -j 4 -f file.makefile
latexmk -g -pdf file.tex
我没有遇到任何问题,一次最多可以外部化四幅图像。我也可以毫无问题地获得 .pdf 输出。
使用我自己编写的绘制 .csv 文件的函数,我无法让 tikzexternalize 更新图形。它检测不到任何变化。如果您不使用该mode=list and make
选项,情况也是如此。因此,下面的 MWE 不包括它,以便于访问。
下面你会看到一个 MWE,它并不是真正最小的,因为包已经变大了。原则上,我在一个groupplot
环境中绘图,其中有两个循环迭代 .csv 文件的不同列。第一个循环用于作为 x 轴的列,第二个循环用于作为 y 轴的列。这些循环是嵌套的。
最后,完整代码如下:
不带选项的要编译的主要 .tex 文件 (csvtest.txt) mode=list and make
。其中包含一个绘图的手动声明,如果我更改某些内容(例如,它应该从中提取数据的列),该声明会更新。
\documentclass{article}
\usepackage[default]{csvtoolbox}
\usetikzlibrary{external}%
\tikzexternalize%[mode=list and make]%
\begin{document}
\csvplot[%
%output dir = fig, % this allows you to choose the output folder for the .pdf
label = f1, % this also defines the name of the externalized figure file name -> f1.pdf
x columns = {x},%
y columns = {a, b},%
] {data.csv}
\begin{figure}
\begin{tikzpicture}
\begin{groupplot}
\nextgroupplot
\addplot table[x=x, y=x, col sep=comma]{data.csv};
\end{groupplot}
\end{tikzpicture}
\end{figure}
\end{document}
以下是我编写的用于绘制.csv 文件的包。
\NeedsTeXFormat{LaTeX2e}%
\ProvidesPackage{csvtoolbox}[2017/05/17 CSV Plot]%
\RequirePackage{etoolbox}%
\RequirePackage{pgfplots}%
\RequirePackage{tikz}%
\RequirePackage{pgfkeys}%
\RequirePackage{float}%
\RequirePackage{hyperref}%
\RequirePackage{tikzscale}%
\pgfplotsset{compat=newest}%
\usepgfplotslibrary{groupplots}%
\DeclareOption{default}{%
\pgfplotsset{csvPlotStyle/.style=%
{%
cycle list name=black white,%
grid=both,%
grid style={dashed, gray},%
}%
}%
\pgfkeys{
% Switch to /csvplot key subset
/csvplot/.is family, /csvplot,%
% User options
def/.style = {%
axis rows = 1,%
axis columns = 1,%,
legend pos = north east,%
height = \textwidth,%
width = \textwidth,%
x columns = x,%
y columns = y,%
style = csvPlotStyle,%
caption = ,%
label = ,%
align = top,%
output dir =.%
}%
}%
}%
%
\ExecuteOptions{default}%
\ProcessOptions\relax%
%
% Set up the keys
\pgfkeys{
% Switch to /csvplot key subset
/csvplot,%
%% definitions
axis rows/.estore in = \csvPlotAxisRows,%
axis columns/.estore in = \csvPlotAxisCols,%
output dir/.estore in = \csvPlotOutputDir,%
legend pos/.estore in = \csvLegPos,%
height/.estore in = \csvPlotHeight,%
width/.estore in = \csvPlotTotalWidth,%
x columns/.estore in = \csvPlotXCol,%
y columns/.estore in = \csvPlotYCol,%
style/.estore in = \csvPlotStyle,%
caption/.estore in = \csvPlotCaption,%
label/.estore in = \csvPlotLabel,%
align/.style = {alignments/#1/.get = \csvPlotAlignment},%
% dictionary for alignment of figure
alignments/.cd,%
top/.initial = t,%
here/.initial = h,%
bottom/.initial = b,%
force/.initial = H,%
page/.initial = p,%
}
%
\newcommand{\csvplot}[2][]{%
\pgfkeys{/csvplot, def, #1}%
\tikzsetnextfilename{./\csvPlotOutputDir/\csvPlotLabel}%
% Expand figure options
\def\efigure{\begin{figure}}\expandafter\efigure\expandafter[\csvPlotAlignment]%
\centering%
\begin{tikzpicture}%
\begin{groupplot} [%
\csvPlotStyle,%
height=1/\csvPlotAxisRows*\csvPlotHeight,%
width=1/\csvPlotAxisCols*\csvPlotTotalWidth,%
legend pos=\csvLegPos,%
group style = {group size = \csvPlotAxisCols\space by \csvPlotAxisRows},%
]%
% Plot loop: All x/y columns for multiple plots in one axis
\edef\XIterate{%
\noexpand\pgfplotsforeachungrouped \noexpand\x in {\csvPlotXCol}%
}
\edef\YIterate{%
\noexpand\pgfplotsforeachungrouped \noexpand\y in {\csvPlotYCol}%
}
\XIterate {%
\YIterate {%
\eappto\PlotList{%
\noexpand\nextgroupplot%
\noexpand\addplot table[x=\x, y=\y, col sep=comma] {#2};%
\noexpand\addlegendentry{\y}%
}%
}%
}%
\PlotList%
\end{groupplot}%
\end{tikzpicture}%
\caption{\csvPlotCaption}%
\label{\csvPlotLabel}%
\end{figure}
}%
最后,绘制一些数据(data.csv)
a,b,x,y
1,2,3,4
5,6,8,1
9,2,4,5
5,5,1,9
谢谢您的意见!
答案1
我终于找到了解决方案。我.md5
根据传递给命令的选项生成一个单独的哈希文件。在命令中,哈希文件生成如下:
\newwrite\tempfile%
\immediate\openout\tempfile=./\csvPlotOutputDir/\csvPlotLabel.md5_%
\immediate\write\tempfile{\pdfmdfivesum{#1}}%
\immediate\closeout\tempfile%
然后,我tikzexternalize
通过添加以下内容来依赖此文件的内容
\tikzpicturedependsonfile{./\csvPlotOutputDir/\csvPlotLabel.md5_}%
以下是供参考的完整csvtoolbok.sty
文件:
\NeedsTeXFormat{LaTeX2e}%
\ProvidesPackage{csvtoolbox}[2017/05/17 CSV Plot]%
\RequirePackage{etoolbox}%
\RequirePackage{pgfplots}%
\RequirePackage{tikz}%
\RequirePackage{pgfkeys}%
\RequirePackage{float}%
\RequirePackage{hyperref}%
\RequirePackage{tikzscale}%
\pgfplotsset{compat=newest}%
\usepgfplotslibrary{groupplots}%
\DeclareOption{default}{%
\pgfplotsset{csvPlotStyle/.style=%
{%
cycle list name=color,%
grid=both,%
grid style={dashed, gray},%
}%
}%
\pgfkeys{
% Switch to /csvplot key subset
/csvplot/.is family, /csvplot,%
% User options
def/.style = {%
axis rows = 1,%
axis columns = 1,%,
output dir =.,%
legend pos = outer south,%
height = \textwidth,%
width = \textwidth,%
plot data x/y = x/y,%
common style = csvPlotStyle,%
caption = ,%
label = ,%
align = top,%
}%
}%
}%
%
\ExecuteOptions{default}%
\ProcessOptions\relax%
% Define outer south legend style
\pgfplotsset{
every axis x label/.append style={
alias=current axis xlabel
},
legend pos/outer south/.style={
/pgfplots/legend style={
at={%
(%
\@ifundefined{pgf@sh@ns@current axis xlabel}%
{xticklabel cs:0.5}%
{current axis xlabel.south}%
)%
},
anchor=north
}
}
}
%
% Set up the keys
\pgfkeys{
% Switch to /csvplot key subset
/csvplot,%
%% definitions
axis rows/.estore in = \csvPlotAxisRows,%
axis columns/.estore in = \csvPlotAxisCols,%
output dir/.estore in = \csvPlotOutputDir,%
legend pos/.estore in = \csvLegPos,%
height/.estore in = \csvPlotHeight,%
width/.estore in = \csvPlotTotalWidth,%
plot data x/y/.estore in = \csvPlotXYCol,%
common style/.estore in = \csvPlotStyle,%
caption/.estore in = \csvPlotCaption,%
label/.estore in = \csvPlotLabel,%
align/.style = {alignments/#1/.get = \csvPlotAlignment},%
% dictionary for alignment of figure
alignments/.cd,%
top/.initial = t,%
here/.initial = h,%
bottom/.initial = b,%
force/.initial = H,%
page/.initial = p,%
}
%
\newcommand{\csvplot}[2][]{%
\pgfkeys{/csvplot, def, #1}%
%
\newwrite\tempfile%
\immediate\openout\tempfile=./\csvPlotOutputDir/\csvPlotLabel.md5_%
\immediate\write\tempfile{\pdfmdfivesum{#1}}%
\immediate\closeout\tempfile%
%
\tikzsetnextfilename{./\csvPlotOutputDir/\csvPlotLabel}%
\tikzpicturedependsonfile{./\csvPlotOutputDir/\csvPlotLabel.md5_}%
% Expand figure options
\def\efigure{\begin{figure}}\expandafter\efigure\expandafter[\csvPlotAlignment]%
\centering%
\begin{tikzpicture}%
\begin{groupplot} [%
\csvPlotStyle,%
height=1/\csvPlotAxisRows*\csvPlotHeight,%
width=1/\csvPlotAxisCols*\csvPlotTotalWidth,%
legend pos=\csvLegPos,%
group style = {group size = \csvPlotAxisCols\space by \csvPlotAxisRows},%
]%
% Plot loop: All x/y columns for multiple plots in one axis
\edef\XYIterate{%
\noexpand\pgfplotsforeachungrouped \noexpand\x/\noexpand\y in {\csvPlotXYCol}%
}%
\XYIterate {%
\eappto\PlotList{%
\noexpand\nextgroupplot%
\noexpand\addplot table[x=\x, y=\y, col sep=comma] {#2};%
\noexpand\addlegendentry{\y}%
}%
}%
\PlotList%
\end{groupplot}%
\end{tikzpicture}%
\caption{\csvPlotCaption}%
\label{\csvPlotLabel}%
\end{figure}%
%
}%