我试图为这里的另一个问题想出一个基于 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