这个问题询问如何在 LaTeX 中生成漂亮的函数图。有几个很好的答案,但是,大多数答案要么依赖外部程序来生成图,要么(如果使用 TeX 来计算图的坐标)仅限于相当简单的函数。
我想用 luatex 来找到答案,用 lua 进行计算,用 mplib 来实际绘制图形。但是,我不知道如何将 lua 和 mplib 一起使用。在 lua 中生成图形并不难,我可以将生成的路径传递给 tikz 进行渲染:
\documentclass{article}
\usepackage{luacode}
\usepackage{tikz}
\begin{luacode}
require("math")
sin=math.sin;cos=math.cos;pi=math.pi
point = function (f,x) return "("..x..","..f(x)..")" end;
path = function (f,a,b,n)
local step = (b-a)/n; local s = "";
for x = a, b - step/2, step do s = s .. point(f,x) .. "--" end;
s = s .. point(f,b);
return s
end;
\end{luacode}
\def\plot#1#2#3#4{%
\directlua{
do local f = function (x) return #1 end;
tex.print(path(f,#2,#3,#4)) end;
}%
}
\begin{document}
\begin{tikzpicture}
\draw[thin,->] (-.2,0)--(6.5,0)node[right]{$x$};
\draw[thin,->] (0,-2.2)--(0,2.2)node[above]{$y$};
\draw[thick] \plot{sin(2*x)+cos(x)}{0}{2*pi}{40}node[above]{$y=\sin(2x)+\cos(x)$};
\end{tikzpicture}
\end{document}
我想知道使用 lua 生成绘图并使用 mplib 渲染它的最佳方法是什么。
答案1
这是我在 ConTeXt 中执行的操作。我不知道 LaTeX 包中是否有类似的功能。基本上,我在 lua 中进行计算,然后将结果写入\startMPcode
..\stopMPcode
环境中。
\启动lua代码 需要(“数学”) 局部正弦 = math.sin 本地 cos = math.cos 本地 pi = math.pi 局部函数 scale(x) 返回 x ..“ * 1cm” 结尾 局部函数对(x,y) 返回“(” .. 比例(x) .. “,” .. 比例(y) .. “)” 结尾 局部函数点(f,x) 返回对(x,f(x)) 结尾 用户数据 = 用户数据或 {} 函数用户数据.draw_function(f,a,b,n) 局部步骤 = (ba)/n 本地路径 = {} 局部 i = 0 对于 x = a, b,步骤执行 路径[i] = 点(f,x) 我=我+ 1 结尾 路径 = 表.concat(路径,“--”) context("绘制" .. 路径 .. " withpen pencircle 缩放 2bp;") 结尾 函数 userdata.draw_x_axis(从,到) 上下文(“绘制箭头” .. 对(从,0) .. “--” .. 对(到,0) .. “;”) 上下文(“标签.rt(btex $x$ etex,“..对(to,0)..“);”) 结尾 函数 userdata.draw_y_axis(从,到) 上下文(“绘制箭头” .. 对(0,从) .. “--” .. 对(0,到) .. “;”) 上下文(“标签.top(btex $y$ etex,“..对(0,to)..“);”) 结尾 函数用户数据.plot() 用户数据.draw_x_axis(-2, 6.5) 用户数据.draw_y_axis(-2.2, 2.2) 局部 f = 函数 (x) 返回 sin(2*x) + cos(x) 结尾 用户数据.draw_function(f, 0, 2*pi, 40) 结尾 \stoplua代码 \开始文本 \ctxlua {上下文.startMPcode(); 用户数据.绘图(); 上下文.stopMPcode() ; } \停止文本
但是,这假设函数中写入的所有内容userdata.plot()
都是 MP 代码。如果您还希望该函数将内容打印到 TeX 流,那么您可以将所有 MP 代码存储在\startMPdrawing
and\stopMPdrawing
环境中并使用 检索它们\getMPdrawing
。
\启动lua代码 需要(“数学”) 局部正弦 = math.sin 本地 cos = math.cos 本地 pi = math.pi 局部函数 scale(x) 返回 x ..“ * 1cm” 结尾 局部函数对(x,y) 返回“(” .. 比例(x) .. “,” .. 比例(y) .. “)” 结尾 局部函数点(f,x) 返回对(x,f(x)) 结尾 用户数据 = 用户数据或 {} 函数用户数据.draw_function(f,a,b,n) 局部步骤 = (ba)/n 本地路径 = {} 局部 i = 0 对于 x = a, b,步骤执行 路径[i] = 点(f,x) 我=我+ 1 结尾 路径 = 表.concat(路径,“--”) context.startMPdrawing() context("绘制" .. 路径 .. " withpen pencircle 缩放 2bp;") context.stopMPdrawing() 结尾 函数 userdata.draw_x_axis(从,到) context.startMPdrawing() 上下文(“绘制箭头” .. 对(从,0) .. “--” .. 对(到,0) .. “;”) 上下文(“标签.rt(btex $x$ etex,“..对(to,0)..“);”) context.stopMPdrawing() 结尾 函数 userdata.draw_y_axis(从,到) context.startMPdrawing() 上下文(“绘制箭头” .. 对(0,从) .. “--” .. 对(0,到) .. “;”) 上下文(“标签.top(btex $y$ etex,“..对(0,to)..“);”) context.stopMPdrawing() 结尾 函数用户数据.plot() 用户数据.draw_x_axis(-2, 6.5) 用户数据.draw_y_axis(-2.2, 2.2) 局部 f = 函数 (x) 返回 sin(2*x) + cos(x) 结尾 用户数据.draw_function(f, 0, 2*pi, 40) 结尾 \stoplua代码 \开始文本 \ctxlua { 上下文.resetMPdrawing() ; 用户数据.绘图(); 上下文.MPdrawingdonetrue(); 上下文.获取MPdrawing();} \停止文本
答案2
我将 Aditya 的 ConTeXt 解决方案与我的原始代码相结合,并针对 LaTeX 进行了修改。它基本可以正常工作,但我似乎在使用btex ... etex
标签时遇到了麻烦。如果我将下面代码中的两行 mpost 标签替换为它们的注释版本,我会得到
! LuaTeX error ...share/texmf-texlive/tex/luatex/luamplib/luamplib.lua:74: invalid option '%C' to 'format'
stack traceback:
[C]: in function 'format'
...share/texmf-texlive/tex/luatex/luamplib/luamplib.lua:74: in function 'log'
...share/texmf-texlive/tex/luatex/luamplib/luamplib.lua:143: in function 'report'
...share/texmf-texlive/tex/luatex/luamplib/luamplib.lua:173: in function 'process'
...share/texmf-texlive/tex/luatex/luamplib/luamplib.lua:101: in function 'processlines'
<\directlua >:1: in main chunk.
\endmplibcode ...adirect {luamplib.processlines()}
l.49 \plot{sin(2*x)+cos(x)}{0}{2*pi}{40}{-2}{2}
以下工作:
\documentclass{article}
\usepackage{luatextra}
\usepackage{luamplib}
\begin{luacode}
scale = function (x) return x .. " * 1cm" end;
pair = function (x,y) return "("..scale(x)..","..scale(y)..")" end;
point = function (f,x) return pair (x,f(x)) end;
path = function (f,a,b,n)
local step = (b-a)/n; local s = "";
for x = a, b - step/2, step do s = s .. point(f,x) .. "--" end;
s = s .. point(f,b);
return s
end;
draw_x_axis = function (from, to)
tex.print(" drawarrow " .. pair(from,0) .. " -- " .. pair(to,0) .. "; ")
tex.print([[ label.rt ( "x" , ]] .. pair(to,0) .. ") ;")
% The following does not work, though:
%tex.print(" label.rt ( btex $x$ etex, " .. pair(to,0) .. ") ;")
end
draw_y_axis = function (from, to)
tex.print(" drawarrow " .. pair(0, from) .. " -- " .. pair(0,to) .. "; ")
tex.print([[ label.top ( "y" , ]] .. pair (0,to) .. ") ;")
% The following does not work, though:
%tex.print(" label.top ( btex $y$ etex , " .. pair (0,to) .. ") ;")
end
beginMPcode = function ()
tex.print("\string\\begin{mplibcode}")
tex.print("beginfig(0)")
end;
endMPcode = function ()
tex.print("endfig;")
tex.print("\string\\end{mplibcode}")
end;
\end{luacode}
\def\plot#1#2#3#4#5#6{%
\directlua{
require("math")
local sin=math.sin;local cos=math.cos;local pi=math.pi % ... and so on
local f = function (x) return #1 end;
beginMPcode()
draw_x_axis(#2-.2,#3+.2)
draw_y_axis(#5-.2,#6+.2)
tex.print("draw " .. path(f,#2,#3,#4) .. " withpen pencircle scaled 2pt;" )
endMPcode()
}%
}
\begin{document}
\plot{sin(2*x)+cos(x)}{0}{2*pi}{40}{-2}{2}
\end{document}
关于如何改善这一点以及如何解决标签问题,您有什么想法吗?