我怎样才能从给定的模式规范中“解复用”几个功能
\foreach
?
我想使用 来\foreach
绘制 TikZ 图片中的多个节点。循环将为每个节点指定一个模式,反过来,该模式将用于设置节点样式和位置的几个特征。由于模式指定了一组特征,我想从模式规范中“分离”这些特征,而不是必须在 中列出每个特征\foreach
。一个最小的不起作用的例子是
\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\begin{document}
\begin{tikzpicture}
\foreach \mode/\loc in {small/{(0,0)}, large/{(2,0)}}
{
\edef\myscale{\ifstrequal{\mode}{large}{1}{0.25}}
\edef\mycolor{\ifstrequal{\mode}{large}{black}{gray}}
\typeout{\meaning\myscale}
\typeout{\meaning\mycolor}
\node [scale=\myscale, color=\mycolor, draw] at \loc {\myscale\mycolor};
}
\end{tikzpicture}
\end{document}
如果我尝试编译它,我会得到错误! Package xcolor Error: Undefined color \ifstrequal{small}{large}{black}{gray}.
似乎在将条件传递给样式之前需要对其进行扩展,但我不知道该怎么做。令人惊讶的是(至少对我来说),如果我scale=\myscale, color=\mycolor
从样式中删除,那么我会得到以下输出。
因此,由于某种原因,节点文本扩展了条件,但样式却没有。
(另外问一下:为什么我帖子里的图片总是变那么小?)
编辑:看起来,\foreach
上面的错误信息有点让人分心。具体来说,以下更简单的代码会产生相同的错误:
\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\begin{document}
\def\mode{small}%
\begin{tikzpicture}
\node [scale=\ifstrequal{\mode}{large}{1}{0.25}, draw]
{\ifstrequal{\mode}{large}{1}{0.25}};
\end{tikzpicture}
\end{document}
尽管@percusse 的答案最适合我的特定用途,但我仍然想知道为什么会出现此错误。此外,是否可以强制扩展\ifstrequal
?
答案1
在 foreach 列表中扩展通常会有问题,需要在正确的位置执行。以下是一些示例
还建议使用样式定义键以避免此类问题。
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\tikzset{l/.style={scale=1,black},s/.style={scale=0.25,gray}}
\foreach \mode/\loc in {s/{(0,0)}, l/{(2,0)}}{
\node [\mode] at \loc {\mode};
}
\end{tikzpicture}
\end{document}
我还会避免使用文字来定义样式和变量,因为任何其他包也可以定义相同的样式和变量,这会导致不必要的调试工作。
答案2
不确定发生了什么\ifstrequal
,但你可以使用\IfStrEq
来自 包裹xstring
\IfStrEq{\mode}{large}{%
\gdef\myscale{1}%
\gdef\mycolor{black}%
}{%
\gdef\myscale{0.25}%
\gdef\mycolor{gray}%
}%
生成结果:
代码:
\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{xstring}
\begin{document}
\begin{tikzpicture}
\foreach \mode/\loc in {small/{(0,0)}, large/{(2,0)}}
{
\IfStrEq{\mode}{large}{%
\gdef\myscale{1}%
\gdef\mycolor{black}%
}{%
\gdef\myscale{0.25}%
\gdef\mycolor{gray}%
}%
\node [scale=\myscale, color=\mycolor, draw] at \loc {\myscale\mycolor};
}
\end{tikzpicture}
\end{document}
我实际上建议您使用\tikzset
来定义样式:
\IfStrEq{\mode}{large}{%
\tikzset{MyStyle/.style={scale=1, color=black}}
}{%
\tikzset{MyStyle/.style={scale=0.25, color=gray}}
}%
产生与上面相同的结果。
代码:
\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{xstring}
\begin{document}
\begin{tikzpicture}
\foreach \mode/\loc in {small/{(0,0)}, large/{(2,0)}}
{
\IfStrEq{\mode}{large}{%
\tikzset{MyStyle/.style={scale=1, color=black}}
}{%
\tikzset{MyStyle/.style={scale=0.25, color=gray}}
}%
\node [MyStyle, draw] at \loc {\myscale\mycolor};
}
\end{tikzpicture}
\end{document}
答案3
或许这在技术上不能回答您的问题\ifstrequal
,但提供了一种解决方法。您可以使用不同的(更原始的)方法进行调节\ifx...\else...\fi
:
\def\mystring{large}%
\ifx\mode\mystring
\def\myscale{1}%
\def\mycolor{black}%
\else% \mode is not large
\def\myscale{0.25}%
\def\mycolor{gray}%
\fi%