# How to draw graphs of standard functions using mpgraph?

Is it possible to draw graph of standard functions using mpgraph (probably using lua, mplib)? For example something like gdraw(sin(x)+cos(x)), gdraw(2x+3) and in general gdraw(f(x)) where f(x) is finite combination of standard functions?

• You should check out the Metafun XL format (from ConTeXt). It has graph drawing functions. Commented Jan 15, 2020 at 17:09

This questions seems to be a follow-up of Using Lua functions with mplib and mpgraph

You can simply construct the function that you want to plot from the macro parameter.

\documentclass{article}
\usepackage{luamplib}
\directlua{userdata = userdata or {}}
\begin{document}
\def\plot#1{%
\directlua{
function userdata.f(x)
local _ENV = math
return (#1)
end
luamplib.process_mplibcode([[
vardef f primary x =
runscript("mp.print(userdata.f(" & decimal x & "))")
enddef ;
input graph ;
beginfig(0)
draw begingraph(5cm,3cm)
gdraw (0,f(0)) for x = 1 upto 1000: .. (x/100, f(x/100)) endfor ;
endgraph ;
endfig ;
]])}%
}

\plot{sin(x) + cos(x)}

\plot{sin(2*pi*x) * exp(-x/2)}

\end{document}


With a tiny bit of extra work you can also get keys and value to configure the plot.

\documentclass{article}
\usepackage{luamplib}
\usepackage{luacode}
\begin{luacode*}

userdata = userdata or {}

userdata.mplibcode = [[
vardef f primary x =
runscript("mp.print(userdata.f(" & decimal x & "))")
enddef ;
numeric xmin, xmax, samples, width ,height ;
xmin := runscript("mp.print(userdata.xmin)");
xmax := runscript("mp.print(userdata.xmax)");
samples := runscript("mp.print(userdata.samples)");
width := runscript("mp.print(userdata.width)");
height := runscript("mp.print(userdata.height)");
input graph ;
beginfig(0)
draw begingraph(width,height)
gdraw (xmin,f(xmin)) for i = 1 upto samples:
-- ((xmax - xmin) / samples * i + xmin, f((xmax - xmin) / samples * i + xmin))
endfor ;
endgraph ;
endfig ;
]]

function userdata.graph(settings)
settings = settings or {}
userdata.xmin = tostring(settings.xmin or "0")
userdata.xmax = tostring(settings.xmax or "1")
userdata.samples = tostring(settings.samples or "100")
userdata.width = tostring(settings.width or "5cm")
userdata.height = tostring(settings.height or "3cm")
luamplib.process_mplibcode(userdata.mplibcode)
end

\end{luacode*}

\newcommand\plot[2][]{%
\directlua{
local userdata = userdata
local _ENV = math
function userdata.f(x)
return (#2)
end
userdata.graph({#1})
}%
}

\begin{document}

\plot[xmin=-pi,xmax=pi,width="7cm"]{sin(x) + cos(x)}
%                            ^^^^^
%          need to be quoted because this is parsed by Lua

\plot[xmin=0,xmax=10,samples=1000]{sin(2*pi*x) * exp(-x/2)}

\end{document}


\documentclass{article}
\usepackage{pgffor}
\usepackage{luamplib}
\usepackage{luacode}
\begin{luacode*}

userdata = userdata or {}

userdata.mplibcode = [[
color clr ;
numeric Nf, rmin, rmax, xmin, xmax, ymin, ymax, samples, width ,height ;
Nf := runscript("mp.print(#userdata.f)");
rmin := runscript("mp.print(userdata.range[1])");
rmax := runscript("mp.print(userdata.range[2])");
xmin := runscript("mp.print(userdata.xmin)");
xmax := runscript("mp.print(userdata.xmax)");
ymin := runscript("mp.print(userdata.ymin)");
ymax := runscript("mp.print(userdata.ymax)");
samples := runscript("mp.print(userdata.samples)");
width := runscript("mp.print(userdata.width)");
height := runscript("mp.print(userdata.height)");

input graph ;

beginfig(0)
draw begingraph(width,height)
setrange(xmin, ymin, xmax, ymax) ;
for n = 1 upto Nf:
vardef f primary x =
runscript("mp.print(userdata.f[" & decimal n & "](" & decimal x & "))")
enddef ;

clr := runscript("mp.print(userdata.color[" & decimal n & "] or 'black')") ;

drawoptions(runscript("mp.print(userdata.style[" & decimal n & "] or '')")) ;
gdraw (rmin,f(rmin)) for i = 1 upto samples:
-- ((rmax - rmin) / samples * i + rmin, f((rmax - rmin) / samples * i + rmin))
endfor withcolor clr ;
drawoptions() ;
endfor ;
endgraph ;
endfig ;
]]

function userdata.graph(settings)
settings = settings or {}
settings.range = settings.range or {}
userdata.range = {
tostring(settings.range[1] or "0"),
tostring(settings.range[2] or "1")
}
userdata.xmin = tostring(settings.xmin or "0")
userdata.xmax = tostring(settings.xmax or "1")
userdata.ymin = tostring(settings.ymin or "whatever")
userdata.ymax = tostring(settings.ymax or "whatever")
userdata.samples = tostring(settings.samples or "100")
userdata.width = tostring(settings.width or "5cm")
userdata.height = tostring(settings.height or "3cm")
userdata.color = settings.color or {}
userdata.style = settings.style or {}
luamplib.process_mplibcode(userdata.mplibcode)
end

\end{luacode*}

\newcommand\plot[2][]{%
\directlua{userdata.f = {}}%
\foreach \f [count=\i] in {#2} {%
\directlua{
local userdata = userdata
local _ENV = math
userdata.f[\i] = function(x)
return (\f)
end
}%
}%
\directlua{
local userdata = userdata
local _ENV = math
userdata.graph({#1})
}%
}

\begin{document}

\plot[
range={ 0, 10 },
xmin=-1, xmax=11,
ymin=-sqrt(2), ymax=sqrt(2),
samples=1000,
color={ "red", "blue", "(0,.8,.1)" },
style={ "", "dashed evenly", "dashed withdots" }
]{sin(2*pi*x) * exp(-x/2), exp(-x/2), sin(2*pi*x)}

\end{document}


\documentclass{article}
\usepackage{luamplib}
\usepackage{luacode}
\begin{luacode*}

userdata = userdata or {}

userdata.mplibcode = [[
numeric Nf, xmin, xmax, ymin, ymax, width ,height ;
Nf := runscript("mp.print(#userdata.functions)");
xmin := runscript("mp.print(userdata.axis.xmin)");
xmax := runscript("mp.print(userdata.axis.xmax)");
ymin := runscript("mp.print(userdata.axis.ymin)");
ymax := runscript("mp.print(userdata.axis.ymax)");
width := runscript("mp.print(userdata.axis.width)");
height := runscript("mp.print(userdata.axis.height)");

input graph ;

beginfig(0)
draw begingraph(width,height)
setrange(xmin, ymin, xmax, ymax) ;
for n = 1 upto Nf:
vardef f primary x =
runscript("mp.print(userdata.functions[" & decimal n & "].f(" & decimal x & "))")
enddef ;
numeric rmin, rmax, samples ;
rmin := runscript("mp.print(userdata.functions[" & decimal n & "].range[1] or userdata.axis.range[1])");
rmax := runscript("mp.print(userdata.functions[" & decimal n & "].range[2] or userdata.axis.range[2])");
samples := runscript("mp.print(userdata.functions[" & decimal n & "].samples or userdata.axis.samples)");
color clr ;
clr := runscript("mp.print(userdata.functions[" & decimal n & "].color or userdata.axis.color)") ;

drawoptions(runscript("mp.print(userdata.functions[" & decimal n & "].style or userdata.axis.style)")) ;
gdraw (rmin,f(rmin)) for i = 1 upto samples:
-- ((rmax - rmin) / samples * i + rmin, f((rmax - rmin) / samples * i + rmin))
endfor withcolor clr ;
drawoptions() ;
endfor ;
endgraph ;
endfig ;
]]

function userdata.draw_graph()
local axis = userdata.axis
axis.range = {
tostring(axis.range[1] or "0"),
tostring(axis.range[2] or "1")
}
axis.xmin = tostring(axis.xmin or "whatever")
axis.xmax = tostring(axis.xmax or "whatever")
axis.ymin = tostring(axis.ymin or "whatever")
axis.ymax = tostring(axis.ymax or "whatever")
axis.samples = tostring(axis.samples or "100")
axis.width = tostring(axis.width or "5cm")
axis.height = tostring(axis.height or "3cm")
axis.color = tostring(axis.color or "black")
axis.style = tostring(axis.style or "")
luamplib.process_mplibcode(userdata.mplibcode)
end

\end{luacode*}

\newenvironment{luamplibplots}[1][]%
{\directlua{
local userdata = userdata
local _ENV = math
userdata.functions = {}
userdata.axis = {#1}
}}%
{\directlua{userdata.draw_graph()}}

\directlua{
local userdata = userdata
local tableinsert = table.insert
local _ENV = math
tableinsert(userdata.functions, {
f = function(x) return (#2) end,
range = {},
#1
})
}%
}

\begin{document}

\begin{luamplibplots}
[range={0,10},
xmin=-1,
xmax=11,
ymin=-sqrt(2),
ymax=sqrt(2),
samples=1000]