如何使用 mpgraph 绘制标准函数图形?

如何使用 mpgraph 绘制标准函数图形?

是否可以使用 mpgraph(可能使用 lua、mplib)绘制标准函数图?例如 gdraw(sin(x)+cos(x))、gdraw(2x+3) 以及一般的 gdraw(f(x)),其中 f(x) 是标准函数的有限组合?

答案1

这个问题似乎是将 Lua 函数与 mplib 和 mpgraph 结合使用

您可以简单地从宏参数构建想要绘制的函数。

\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}

在此处输入图片描述

通过一点点额外的工作,您还可以获得密钥和值来配置情节。

\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}

在此处输入图片描述

相关内容