实际上是我之前提出的一个问题,我有了一些新的想法,但还是不能解决。
首先我的目的是输出以下这样分布的 node:
我的代码是
\begin{tikzpicture}
\foreach \x/\y/\z in{
0/0/A,
2/0/B,
0/-1/C,
2/-1/D
}
{\node at(\x,\y){\z};}
\end{tikzpicture}
这样是可以实现的,但我想简化输入,于是想这样操作:
\begin{tikzpicture}
\foreach \x in{0,2}
\foreach \y in{0,-1}
\foreach \z in{A,B,C,D}
\foreach \m/\n/\l in{\x/\y/\z}
{\node[draw] at(\m,\n){\l};}
\end{tikzpicture}
但结果是这样
可以看到,每个 node 上并不是只有一个字母,而应该是16个,也就是说最后的标签变量把所有的循环都走了一遍,但现在我只想输出一个字母,也就是让\foreach \m/\n/\l in{\x/\y/\z}
中的\x/\y/\z
展开,请问有什么方法可以实现这样的效果?谢谢。
仔细整理一下你的代码,其实你在嵌套循环
\begin{tikzpicture}
\foreach \x in{0,2} %2
{
\foreach \y in{0,-1} %2
{
\foreach \z in{A,B,C,D} %4
{
\foreach \m/\n/\l in{\x/\y/\z}
{
\node[draw] at(\m,\n){\l}; % 2 x 2 x 4 = 16
}
}
}
}
\end{tikzpicture}
循环次数分别是 2,2,4,1
. 所以一共是 2x2x4x1=16
次,你的这种想法我大概明白了,但是目前我并没有好的办法.
或许可以使用计数器来代替第三层循环,如下
\begin{tikzpicture}
\newcounter{node}
\setcounter{node}{1}
\foreach \x in{0,2} %2
{
\foreach \y in{0,-1} %2
{
\node[draw] at (\x,\y){\Alph{node}\stepcounter{node}};
}
}
\end{tikzpicture}
给另外一个例子,或许可以给你提供一点思路,如下:
我想构造两个循环,但是他们不嵌套,而是一一对应,第一层为1,2,3,4,...,10
, 第二层为2,4,6,8,...,20
,当然你可以使用:
\foreach \x/\y in {1/2,2/4,3/6,4/8,5/10,6/12,7/14,8/16,9/18,10/20}
{
...
}
这样固然是可行的, 但是难免有些繁琐, 毕竟两个循环的值是有函数关系的,那么可以:
方法一
\foreach \x in {1,2,...,10}
{
\pgfmathsetmacro{\y}{2*\x} % \y = 2*\x
\node[] at (\x,0) {\y};
}
方法二
\foreach \x [count=\xc] in {1,2,...,10}
{
\foreach \y [count=\yc] in {2,4,...,20}
{
\ifnum\xc=\yc
\node[] at (\x,0) {\y};
\fi
}
}
希望能够帮助到你!
关于二维数组,可以使用 LaTeX3
实现一个阉割版的 二维数组,
\documentclass{article}
\usepackage{tikz}
\begin{document}
\ExplSyntaxOn
\seq_new:N \l_node_row_seq
\seq_new:N \l_node_tmp_seq
\cs_set:Npn \GetArray #1 {
\seq_set_split:Nnn \l_node_row_seq {;} {#1}
\int_step_inline:nn{\seq_count:N \l_node_row_seq}
{
\seq_if_exist:cF {l_node_row_##1_seq}
{
\seq_new:c {l_node_row_##1_seq}
}
\exp_args:Ncx\seq_set_from_clist:Nn {l_node_row_##1_seq} {\seq_item:Nn \l_node_row_seq{##1}}
}
}
\cs_set:Npn \PrintArray [#1][#2] {
\tl_if_empty:nTF { #1 }
{
\tl_if_empty:nTF { #2 }
{
\seq_use:Nn \l_node_row_seq {,}
}
{
\int_step_inline:nn{\seq_count:N \l_node_row_seq}
{
\seq_put_right:Nn \l_node_tmp_seq {\seq_item:cn {l_node_row_##1_seq}{#2}}
}
\seq_use:Nn \l_node_tmp_seq {,}
}
}
{
\tl_if_empty:nTF {#2}
{
\seq_use:cn {l_node_row_#1_seq}{,}
}
{
\seq_item:cn {l_node_row_#1_seq}{#2}
}
}
}
\ExplSyntaxOff
\GetArray
{
A,B,C;
D,E,F;
G,H,I
}
\PrintArray[][]\par
\PrintArray[1][]\par
\PrintArray[][2]\par
\PrintArray[1][2]
\vspace*{1cm}
\begin{tikzpicture}
\GetArray
{
A,B,C;
D,E,F;
G,H,I
}
\foreach \x in {1,2,3}
{
\foreach \y in {1,2,3}
{
\node[draw] at (\x,\y) {\PrintArray[\x][\y]};
}
}
\end{tikzpicture}
\end{document}
其实需要的就是一个多维数组而已。简单描述一下就是:
a[M][N] = {...} % 以 1 起始
for (i=1; i<=M; i++)
for (j=1; j<=N; i++)
node(a[i][j]);
只是在 LaTeX 中(包括 LaTeX3)并没有这样的数据结构。LuaTeX 倒是可以用 table 实现。
要使用宏来实现,简单的就是使用多个 seq 或 clist 或 prop。这样实现的话效率很低。
或者也可以直接用宏保存:
% \@namedef := \expandafter \def \csname #1\endcsname
\@namedef{data@1@1}{A}
\@namedef{data@1@2}{B}
\@namedef{data@2@1}{C}
\@namedef{data@2@2}{D}
然后直接用
% \UseName := \csname #1\endcsname
\foreach \i .....
\foreach \j .....
{\node {\UseName{data@\i @\j}};}
谢谢您,不过我感觉还是离最终答案有点远,也许是我要求太苛刻,计数器似乎只能输出固定样式的标签,但实际情况中标签要复杂很多,没有规律。
我的目的其实就是把两个坐标和标签这三个东西分开输出,然后再整合到一块并且有正确的对应,现在核心问题是标签没有办法和前两个坐标匹配。不过这种方法对有规律的标签是可行的。
@u26254
从实际作图来看,如果 node 比较少,手工设计 node 坐标,标签的代码并不多。如果 node 数量很多,最好使用能够自动排布 node 的库。
@u817 是的,不过这种情况面向的 node 一般都比较多,几十个甚至上百个,这样的话实际上用矩阵模块输入也不是很方便,除此之外我不知道其他的自动排布的方式,请问还有别的吗?
@u26254
手册的 19,27 等章节,
usetikzlibrary{graphs}
usetikzlibrary {graphs,graphdrawing}
usegdlibrary{force}
之类
@u817 谢谢您,我现在才注意到
请问这个数组中的取值只能说整数1,2,3...吗就是
\foreach \x in {1,2,3}
中的取值,可以上小数或负数吗