我想在中使用数组tikzmath
。我希望能够手动定义一个数组,相当于python代码myarray = [1,0,0,1,1]
,我还希望能够在tikzmath中访问它,使用类似的东西myarray[3]
以及修改它,使用类似的东西myarray[4] = 42
。我发现了两种处理数组的方法,但每种方法都有一个问题。
第一个(参见我的 MWE)很有趣,因为它允许我动态定义数组,但我不知道如何使用一行手动初始化这个数组,而不使用循环来计算值。
我发现的第二种解决方案存在相反的问题:我可以以单行方式定义一个数组,但随后访问它tikzmath
很困难,我需要使用如下疯狂的结构:
\pgfmathparse{\myarray[\s]}
\edef\val{\pgfmathresult}
虽然我想直接\myarray[\s]
在tikzmath
代码中使用。
您知道创建一个可以轻松访问和修改的数组的最佳方法是什么吗?tikzmath
如果需要,我可以在单行命令中指定初始值?
谢谢!
梅威瑟:
\documentclass{report}
\usepackage{tikz}
\usetikzlibrary{math}
\begin{document}
%%% FIRST METHOD
\begin{tikzpicture}
\tikzmath{
\n = 5;
% Works, but one problem: how to manually choose the values
% without using a loop?
int \i;
for \i in {1,...,\n}{
\myarray{\i} = mod(\i,2);
};
% Display
for \i in {1,...,\n}{
if \myarray{\i} == 1 then { \ccolor = "green!30";}
else { \ccolor = "blue!30"; };
{\node[draw,circle,fill=\ccolor] at ({90+360/\n * (\i-1)}:2cm) {$\i$};};
};
}
\end{tikzpicture}
%%% SECOND METHOD
\begin{tikzpicture}
\def\n{5}
\def\myarray{{42,1,0,1,1,0}}
\foreach \s in {1,...,\n}
{
%%% Works but not really easy to read/write, and is not inside the
%%% tikzmath code.
% \pgfmathparse{\myarray[\s]}
% \edef\val{\pgfmathresult}
% \tikzmath{ if \val == 1 then { \ccolor = "green!30"; }
%%% Does not work, no idea why
\tikzmath{ if \myarray[\s] == 1 then { \ccolor = "green!30"; }
else { \ccolor = "blue!30";};
}
\node[draw,circle,fill=\ccolor] at ({90+360/\n * (\s-1)}:2cm) {$\s$};
}
\end{tikzpicture}
\end{document}
答案1
listofitems
使用 的简单语法,操作起来很简单。例如,readlist\myarray{1,0,1,1,0}
这允许通过完全可扩展的 逐个单元进行访问。可以访问完全可扩展的数组长度来设置循环限制,就像我使用(或者,通过)所做的那样。\myarray[5]
\edef\n{\listlen\myarray[]}
\edef\n{\myarraylen}
我已经提供了\reassignitem
带有语法的宏\reassignitem\myarray[5]{42}
来重新分配数组值。
在 MWE 中,图形结果上放置了下标,仅仅是为了表明宏\reassignitem
实际上可以重新分配列表项的值。
\documentclass{report}
\usepackage{tikz}
\usetikzlibrary{math}
\usepackage{listofitems}
\catcode`\_11
\def\reassignitem#1[#2]#3{\loi_argcsname\loi_def{\loi_macroname#1[#2]}{#3}}
\loi_restorecatcode
\begin{document}
\readlist\myarray{1,0,1,1,0}
\reassignitem\myarray[5]{42}
\begin{tikzpicture}
% HERE CAN DEFINE \n IN TERMS OF ARRAY LENGTH, FOR EXAMPLE
\edef\n{\listlen\myarray[]}
\foreach \s in {1,...,\n}
{
\tikzmath{ if \myarray[\s] == 1 then { \ccolor = "green!30"; }
else { \ccolor = "blue!30";};
}
\node[draw,circle,fill=\ccolor] at ({90+360/\n * (\s-1)}:2cm) {$\s_{\myarray[\s]}$};
}
\end{tikzpicture}
\end{document}
代码\reassignitem
\catcode`\_11
\def\reassignitem#1[#2]#3{\loi_argcsname\loi_def{\loi_macroname#1[#2]}{#3}}
\loi_restorecatcode
本质上等同于以下内容,但带有listofitems
错误检查。
\makeatletter
\def\reassignitem#1[#2]#3{%
\expandafter\def\csname\expandafter\@gobble\string#1[#2]\endcsname{#3}}
\makeatother
免责声明:如果我没有提供\reassignitem
不适用于嵌套项目列表(父/子列表中的数据将不同步)的免责声明,并且listofitems
如果重新分配分隔符(这里是逗号,
)作为重新分配替换文本的一部分,那将破坏逻辑,那我就是失职了。
答案2
\pgfmathsetmacro
从或内部访问数组\pgfmathparse
似乎可以实现您想要的操作:
\documentclass{report}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\def\n{5}
\def\myarray{{42,1,0,1,1,0}}
\foreach \s in {1,...,\n}
{
\pgfmathsetmacro\ccolor{ifthenelse(\myarray[\s]==1, "green!30", "blue!30")}
\node[draw,circle,fill=\ccolor] at ({90+360/\n * (\s-1)}:2cm) {$\s$};
}
\end{tikzpicture}
\end{document}
请注意,您不需要\usetikzlibrary{math}
。
输出与 marmot 的答案相同:
答案3
在里面\tikzmath
你不能进行除了允许的类型之外的赋值(即对局部变量)。
这是一个解决方案,重新实现了数组并添加了一个新关键字 for \tikzmath
,允许在同一级别(而不是在组中)执行代码。注意不要执行改变状态的赋值\tikzmath
;此外,其中没有可用的“tikzmath”,因此必须存在如图所示的间接寻址。
\documentclass{report}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{math}
% define a new keyword
\makeatletter
\def\tikz@math@process@keyword@assign{%
\tikz@math@collecttosemicolon{\tikz@math@process@keyword@@assign}%
}
\def\tikz@math@process@keyword@@assign{%
\tikz@math@collected\tikz@math@parse
}
\makeatother
%% Let's reimplement TikZ arrays
\ExplSyntaxOn
\cs_new:Npn \shp #1 { \prop_show:c { l_tobias_array_#1_prop } }
\NewDocumentCommand{\definearray}{mO{}}
{% #1 = array name, #2 = items
\prop_clear_new:c { l_tobias_array_#1_prop }
\int_step_inline:nnnn { 0 } { 1 } { \clist_count:n { #2 } - 1 }
{
\prop_put:cnx { l_tobias_array_#1_prop } { ##1 } { \clist_item:nn { #2 } { ##1 + 1 } }
}
}
\NewDocumentCommand{\setarrayitem}{mmm}
{% #1 = array name, #2 = index, #3 = value
\prop_put:cff { l_tobias_array_#1_prop } { #2 } { #3 }
}
\NewExpandableDocumentCommand{\arrayitem}{mm}
{
\prop_item:cf { l_tobias_array_#1_prop } { #2 }
}
\cs_generate_variant:Nn \prop_put:Nnn { cff }
\cs_generate_variant:Nn \prop_item:Nn { cf }
\ExplSyntaxOff
\begin{document}
%%% FIRST METHOD
\begin{tikzpicture}
\definearray{myarray}
\tikzmath{
\n = 5;
% Works, but one problem: how to manually choose the values
% without using a loop?
int \i;
for \i in {1,...,\n}{
\tmp = mod(\i,2);
assign \setarrayitem{myarray}{\i}{\tmp};
};
% Display
for \i in {1,...,\n}{
if \arrayitem{myarray}{\i} == 1 then { \ccolor = "green!30";}
else { \ccolor = "blue!30"; };
{\node[draw,circle,fill=\ccolor] at ({90+360/\n * (\i-1)}:2cm) {$\i$};};
};
}
\end{tikzpicture}
%%% SECOND METHOD
\begin{tikzpicture}
\def\n{5}
\definearray{myarray}[42,1,0,1,1,0]
\foreach \s in {1,...,\n}
{
\tikzmath{ if \arrayitem{myarray}{\s} == 1 then { \ccolor = "green!30"; }
else { \ccolor = "blue!30";};
}
\node[draw,circle,fill=\ccolor] at ({90+360/\n * (\s-1)}:2cm) {$\s$};
}
\end{tikzpicture}
\end{document}
答案4
这是一条很长的评论。这是我对使用库和另一种名为 Asymptote 的编程语言array
进行绘图的(偏见)看法math
。这似乎是图形程序和编程语言之间的区别。
我读过某人的一篇帖子(忘记了链接),他说他/她喜欢math
TikZ 库,因为它增强了 TikZ 的编程能力。但是,math
由于它的语法不自然,我尝试了几次后就停止使用这个库了。出于同样的原因(语法干净),我对array
Asymptote 中的操作感到很满意。
我认为下面的 Asymptote 代码是不言自明的,并且很清晰。
unitsize(1cm);
real r=2.5; // radius of pentagon
// array of vertexes of the pentagon
pair[] V;
for(int i=0; i<5; ++i)
V.push(r*dir(90+72i));
// array of filling colors
pen[] p={blue,red,purple,yellow,cyan};
// array of labels
string[] s={"$1_1$","$2_0$","$3_1$","$4_1$","$5_{42}$"};
for(int i=0; i<5; ++i) {
filldraw(circle(V[i],.5),p[i]+opacity(.5),black);
label(s[i],V[i]);
}
shipout(bbox(5mm,invisible));