Lua 函数将值列表返回给 TikZ foreach 循环

Lua 函数将值列表返回给 TikZ foreach 循环

我试图为这里的另一个问题想出一个基于 Lua 的解决方案,但失败了。我对 LuaLaTeX 有些地方确实不太了解。这里有一个演示该问题的玩具代码。

Lua 函数接收一个整数,该整数必须为 1 或 2,并且根据该值,将返回(通过tex.print)区间 [0,3] 的不同细分。返回的字符串由foreach循环接收,希望将其用作图形的横坐标列表。

\documentclass{article}
\usepackage{luacode}
\usepackage{tikz}

\LuaCodeDebugOn
\begin{luacode}
function listx(n)
    local values = ""
    if n == 1 then
        for i=1, 3 do
            values = values .. i .. ","
        end
    elseif n == 2 then
        for i=1, 6 do
            values = values .. i/2 .. ","
        end
    end
    values = values:sub(1, -2)
    tex.print(values)
end
\end{luacode}

\begin{document}
\directlua{listx(2)}  % displays 0.5,1.0,1.5,2.0,2.5,3.0

\begin{tikzpicture}
\foreach \x in {\directlua{listx(2)}} { 
    \fill (\x,0.5) circle (0.02);
};
\end{tikzpicture}
\end{document}

之后的第一行\begin{document}显示该函数打印预期的值列表,只是作为测试。

但是 TikZ 图片在坐标 (0,0) 处显示单个点,而不是均匀分布的 3 个或 6 个点。我猜是因为某种原因,它tex.print没有以正确的格式发送数据foreach,或者某些 LaTeX 处理发生得太早或太晚了……

我感到很惊讶,因为我经常使用 Lua 代码来计算数值,然后传递给它siunitx以获得良好的渲染效果。我猜问题出在我试图传递一个列表值从 Lua 到 LaTeX,这是我以前从未尝试过的事情。

无论如何,我有点超出了我的能力范围,而且我似乎无法显示\LuaCodeDebugOn任何代码来帮助我了解正在发生的事情。

我必须如何调用 Lua 函数,它必须如何将其结果发回,以便将foreach其理解为要循环的数字列表?

(请不要太关注 Lua 代码本身,它只是我为这篇文章编写的一个愚蠢的玩具程序)

答案1

较新版本tikz支持expand list以下选项\foreach

\foreach[expand list] \x in {\directlua{listx(2)}} {  % <--- changed
    \fill (\x,0.5) circle (0.02);
};

梅威瑟:

\documentclass{article}
\usepackage{luacode}
\usepackage{tikz}

\LuaCodeDebugOn
\begin{luacode}
function listx(n)
    local values = ""
    if n == 1 then
        for i=1, 3 do
            values = values .. i .. ","
        end
    elseif n == 2 then
        for i=1, 6 do
            values = values .. i/2 .. ","
        end
    end
    values = values:sub(1, -2)
    tex.print(values)
end
\end{luacode}

\begin{document}
\directlua{listx(2)}  % displays 0.5,1.0,1.5,2.0,2.5,3.0

\begin{tikzpicture}
\foreach[expand list] \x in {\directlua{listx(2)}} {  % <--- changed
    \fill (\x,0.5) circle (0.02);
};
\end{tikzpicture}
\end{document}

在此处输入图片描述

答案2

我并不认为使用起来特别“糟糕” edef,但这是一个“纯 Lua”解决方案:

然而,并不是所有的事情都可以用纯 Lua 来完成,如果你想要进行一些 TeX 编程,有时你需要切换到 TeX,请参阅在 LuaTeX 中并发交叉执行 Lua 和 TeX

%! TEX program = lualatex
\documentclass{article}
\usepackage{luacode}
\usepackage{tikz}

\LuaCodeDebugOn
\begin{luacode*}
function foreachlistx(n)
    local values = ""
    if n == 1 then
        for i=1, 3 do
            values = values .. i .. ","
        end
    elseif n == 2 then
        for i=1, 6 do
            values = values .. i/2 .. ","
        end
    end
    values = values:sub(1, -2)
    tex.print([[\foreach \x in {]] .. values .. "}")
end
\end{luacode*}

\begin{document}

\begin{tikzpicture}
\directlua{foreachlistx(2)} {
    \fill (\x,0.5) circle (0.02);
};
\end{tikzpicture}
\end{document}

当然,解决方案可以稍微改进一下,例如将值列表计算拆分为可以独立调用的单独 Lua 函数,但正如我之前提到的,\foreach没有在括号中展开它的参数,实际上没有更干净的方法。它的作用应该相对容易理解(\directlua{...}“扩展” (*)\foreach \x in {...},后面跟着要执行的代码,正如您所见,它会执行您想要的操作)

(*): 来自 LuaTeX 手册

请注意,\directlua 的扩展是字符序列,而不是标记序列,这与所有 TEX 命令相反。因此,从形式上讲,它的扩展为空,但它将材料放在伪文件中,以便 TEX 立即读取,如下所示

答案3

你可以说:

\edef\mylist{\directlua{listx(2)}}

\begin{tikzpicture}
\foreach \x  in \mylist { 
    \fill (\x,0.5) circle (0.1);
}
\end{tikzpicture}

或者

\ExplSyntaxOn
\begin{tikzpicture}
\exp_args:Nx\clist_map_inline:nn{\directlua{listx(2)}}
{
  \fill (#1,0.5) circle(0.1);
}
\end{tikzpicture}
\ExplSyntaxOn

相关内容