今天,在全国隔离期间(我无法再使用办公室的非 LaTeX 图形创建软件),我花了一些时间尝试实际学习一些知识tikz
并根据我经常使用的可视化格式自动执行图形创建过程,该格式由单个方形图上的一个或多个 xy 图组成,其中的图是数据点的集合(线和/或散点图)。
我已经制定了一个用于绘图例程的数据文件\input
。总而言之,我对结果很满意,但有一个问题无法解决……那就是如何自动输入以完成对每个绘图的标记。
这是我目前的情况。我的输入文件目前如下:
% The data files, written on the first run.
\begin{filecontents*}{PlotA.data}
1.33E-02 10.403432
1.33E-01 12.53108
2.66E-01 14.90265
3.99E-01 17.22483
5.31E-01 19.58292
6.64E-01 21.89876
9.20E-01 24.44624
1.20E+00 26.6708
\end{filecontents*}
\def\PlotAfile{PlotA.data}
\def\PlotAdrawoptions{red}
\def\PlotAoptions{only marks, mark=*, mark options={fill=white}}
\def\PlotAlegend{Plot A data}
\begin{filecontents*}{PlotB.data}
# COMMENT IN THIS FILE
4.35E-02 9.562436
4.35E-01 10.845494
8.69E-01 12.24356
1.30E+00 13.66974
1.74E+00 15.13008
2.17E+00 16.57845
2.61E+00 17.97894
3.04E+00 19.41534
\end{filecontents*}
\def\PlotBfile{PlotB.data}
\def\PlotBdrawoptions{densely dashed}
\def\PlotBoptions{mark options={fill=white}}
\def\PlotBlegend{Plot B data}
\begin{filecontents*}{PlotC.data}
8.57E-01 11.255013
9.99E-01 11.4804
1.14E+00 11.718
1.29E+00 11.9916
1.64E+00 12.65854
2.00E+00 13.308
2.64E+00 14.484
3.85E+00 16.8
\end{filecontents*}
\def\PlotCfile{PlotC.data}
\def\PlotCdrawoptions{blue}
\def\PlotCoptions{mark=triangle*, mark options={}}
\def\PlotClegend{Plot C data}
\begin{filecontents*}{PlotD.data}
4.28E+00 17.56312023
5.71E+00 20.21127914
7.14E+00 22.85943805
8.57E+00 25.50759696
9.99E+00 28.15575587
\end{filecontents*}
\def\PlotDfile{PlotD.data}
\def\PlotDdrawoptions{thick}
\def\PlotDoptions{mark=square*, mark options={fill=yellow}}
\def\PlotDlegend{Plot D data}
\def\legendcoords{(6,10)}
\def\nplots{4}
\def\showlegend{T}% ANYTHING BUT T TURNS OFF LEGEND
\graphdim=8cm
%
\def\xaxislen{10.4}
\def\xaxisstart{-.2}
\def\xaxisinc{2}
\def\xaxismode{int}% {} OR {int}
\def\xlabeloffset{0.6cm}
\def\xlabeltext{$\hat f$}
\def\xlabeloptions{%
% fixed,
% use comma,
% fixed zerofill,
precision=1,
1000 sep={,},
}
%
\def\yaxislen{30}
\def\yaxisstart{0}
\def\yaxisinc{5}
\def\yaxismode{}% {} OR {int}
\def\ylabeloffset{0.8cm}
\def\ylabeltext{$F(\hat f)$}
\def\ylabeloptions{%
fixed,
% use comma,
% fixed zerofill,
precision=0,
1000 sep={,},
}
%
绘图文件会创建独立的图像文件,稍后我可以将其插入到我的文档中,如下所示:
\documentclass[12pt, border=1pt]{standalone}
%\usepackage[iso-8859-7]{inputenc}
%\usepackage{epigrafica}
%\usepackage[italic]{mathastext}
\usepackage{tikz}
\usetikzlibrary{plotmarks}
\newcounter{plotnumber}
\newlength\graphdim
\input mytikzinput
\newcommand\answer[1]{$\mathrm{\expandafter\pgfmathprintnumber\expandafter
[\labelopts, assume math mode]{#1}}$}
\begin{document}
\begin{tikzpicture}[y={\graphdim/\yaxislen},
x={\graphdim/\xaxislen}]
%axis
\draw (\xaxisstart,{\yaxisstart+\yaxislen}) --
({\xaxisstart+\xaxislen},{\yaxisstart+\yaxislen});
\draw ({\xaxisstart+\xaxislen},\yaxisstart) --
({\xaxisstart+\xaxislen},{\yaxisstart+\yaxislen});
\draw (\xaxisstart,\yaxisstart) -- coordinate (x axis mid)
({\xaxisstart+\xaxislen},\yaxisstart);
\draw (\xaxisstart,\yaxisstart) -- coordinate (y axis mid)
(\xaxisstart,{\yaxisstart+\yaxislen});
%xticks
\let\labelopts\xlabeloptions
\pgfmathparse{\xaxismode(\xaxisstart}
\let\thexllim\pgfmathresult
\pgfmathparse{\xaxismode(\thexllim+\xaxisinc)}
\let\thexlnext\pgfmathresult
\pgfmathparse{\xaxismode(\xaxisstart+\xaxislen)}
\let\thexulim\pgfmathresult
\foreach \x in {\thexllim,\thexlnext,...,\thexulim}
\draw (\x,{\yaxisstart*\graphdim/\yaxislen+1pt}) --
(\x,{\yaxisstart*\graphdim/\yaxislen-3pt})
node[anchor=north] {\answer{\x}};
%yticks
\let\labelopts\ylabeloptions
\pgfmathparse{\yaxismode(\yaxisstart}
\let\theyllim\pgfmathresult
\pgfmathparse{\yaxismode(\theyllim+\yaxisinc)}
\let\theylnext\pgfmathresult
\pgfmathparse{\yaxismode(\yaxisstart+\yaxislen)}
\let\theyulim\pgfmathresult
\foreach \y in {\theyllim,\theylnext,...,\theyulim}
\draw ({\xaxisstart*\graphdim/\xaxislen+1pt},\y) --
({\xaxisstart*\graphdim/\xaxislen-3pt},\y)
node[anchor=east] {\answer{\y}};
%labels
\node[below=\xlabeloffset] at (x axis mid) {\xlabeltext};
\node[rotate=90, above=\ylabeloffset] at (y axis mid) {\ylabeltext};
%plots
\foreach\z in {1,...,\nplots}{
\stepcounter{plotnumber}
\edef\tmp{\noexpand\draw
[\csname Plot\Alph{plotnumber}drawoptions\endcsname]
plot[\csname Plot\Alph{plotnumber}options\endcsname]
file {\csname Plot\Alph{plotnumber}file\endcsname}}
\tmp node [below left] {blah};% GOES TO LAST POINT
% attempts to use [midway, pos=...] do not avail
}
%legend
\if T\showlegend\relax
\begin{scope}[shift={\legendcoords}]
\setcounter{plotnumber}{0}
\foreach\z in {1,...,\nplots}{
\stepcounter{plotnumber}
\edef\tmp{\noexpand\draw
[\csname Plot\Alph{plotnumber}drawoptions\endcsname,
text = black, yshift=\numexpr1-\z\relax\baselineskip]
plot [\csname Plot\Alph{plotnumber}options\endcsname]
(0.3,0) -- (0.0,0) -- (0.6,0)
node[right]{\csname Plot\Alph{plotnumber}legend\endcsname}}
\tmp;
}
\end{scope}
\fi
\end{tikzpicture}%
\end{document}
目前结果是这样的:
虽然我可以使用诸如 之类的限定符below left
,但您可以看到的问题(在标有 的代码部分中找到%plots
)是,我正在尝试弄清楚如何将图的标签放置在图上的任意长度上。我目前的做法是始终将标签放置在相对于数据集中最后一个点的位置。我尝试过使用诸如midway
和之类的pos=
限定符,但它们只会将标签移回原点。
因此,问题显然是如何解决绘图标签的位置问题。我想,在最坏的情况下,我总是可以让用户指定标签应该放在的图形坐标,但我认为可能有一种更自动化的方法。
注意:为了便于代码开发,我以相同的方式标记了所有图。在我弄清楚如何解决这个问题之后,我将修改代码以区分每个图的标签。
答案1
我会这样做。pgfplots
我认为这样整个企业就会变得简单得多。(我可能忽略了一些细节,如果是这样,请告诉我。)
\documentclass[12pt, border=1pt,tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16} % my MacTeX 2020 is still downloading
\newlength\graphdim
\input{mytikzinput}
\begin{document}
\begin{tikzpicture}
\begin{axis}[width=\graphdim,
legend style={at={(0.98,0.02)},anchor=south east},
xlabel=\xlabeltext,
ylabel=\ylabeltext,
xmin=\xaxisstart,
xmax=\xaxislen,
ymin=\yaxisstart,
ymax=\yaxislen]
% this can be done in a loop but I'd really use pgf keys in the
% input file. if that's not acceptable I will be happy to build
% a loop with these macros
\tikzset{locA/.style/.expanded={\PlotAdrawoptions,\PlotAoptions}}
\addplot[locA] table {\PlotAfile}
node[midway,above,sloped]{blah};
\tikzset{locB/.style/.expanded={\PlotBdrawoptions,\PlotBoptions}}
\addplot[locB]
table {\PlotBfile}
node[midway,above,sloped]{blah};
\tikzset{locC/.style/.expanded={\PlotCdrawoptions,\PlotCoptions}}
\addplot[locC]
table {\PlotCfile}
node[midway,above,sloped]{blah};
\tikzset{locD/.style/.expanded={\PlotDdrawoptions,\PlotDoptions}}
\addplot[locD]
table {\PlotDfile}
node[midway,above,sloped]{blah};
\legend{\PlotAlegend,\PlotBlegend,\PlotClegend,\PlotDlegend}
\end{axis}
\end{tikzpicture}
\end{document}
这使用您的数据文件。显然您不需要倾斜节点,这只是为了表明这是可能的。
您可以将其变成一个循环。(如果参数存储在 pgf 键中,循环会更漂亮,但当然宏也可以工作。显然blah
可以用依赖于情节的宏替换。您可以使用找出循环的上限,\ifcsname
但您比我更了解这些事情。)
\documentclass[12pt, border=1pt,tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16} % my MacTeX 2020 is still downloading
\newlength\graphdim
\input{mytikzinput}
\begin{document}
\begin{tikzpicture}
\begin{axis}[width=\graphdim+1.5cm,% <- +1.5cm is an estimate of the space taken by the y labesl
legend style={at={(0.98,0.02)},anchor=south east},
xlabel=\xlabeltext,
ylabel=\ylabeltext,
xmin=\xaxisstart,
xmax=\xaxislen,
ymin=\yaxisstart,
ymax=\yaxislen]
\pgfplotsinvokeforeach{A,B,C,D}{
\tikzset{loc#1/.style/.expanded={\csname Plot#1drawoptions\endcsname,
\csname Plot#1options\endcsname}}
\edef\temp{\noexpand\addplot[loc#1] table {\csname Plot#1file\endcsname}
node[midway,above,sloped]{blah};
\noexpand\addlegendentry{\csname Plot#1legend\endcsname}}
\temp}
\end{axis}
\end{tikzpicture}
\end{document}