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?
1 Answer
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()}}
\newcommand\addplot[2][]{%
\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]
\addplot[color="red", samples=50]{sin(2*pi*x) * exp(-x/2)}
\addplot[color="blue", style="dashed evenly"]{exp(-x/2)}
\addplot[color="(0,.8,.1)", style="scaled 2pt dashed withdots"]{sin(2*pi*x)}
\addplot[range={exp(-2),exp(2)}]{log(x)}
\end{luamplibplots}
\end{document}
-
-
How can the option for ymin, ymax and color of graphs can be added? Also is it possible to draw graphs of multiple functions in single figure? Feb 13, 2020 at 7:04
-
1@user61681 Nice challange. I updated my answer but without further explanation. Feb 13, 2020 at 9:47
-
Thank you for the wonderful solution. Sorry, but I didn't mean to challenge anything. Thanks again. Feb 13, 2020 at 13:23
-