Tikzmath:使用数组

Tikzmath:使用数组

我想在中使用数组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。这似乎是图形程序和编程语言之间的区别。

我读过某人的一篇帖子(忘记了链接),他说他/她喜欢mathTikZ 库,因为它增强了 TikZ 的编程能力。但是,math由于它的语法不自然,我尝试了几次后就停止使用这个库了。出于同样的原因(语法干净),我对arrayAsymptote 中的操作感到很满意。

我认为下面的 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));

相关内容