How to plot a complicated multi-variable function in a tex document automatically, not just importing an image

Here is a solution by means of pgfplots + lualatex (i.e. it has to be compiled with lualatex P.tex:

\documentclass{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=1.9}

\begin{document}
\begin{tikzpicture}
    \directlua{
        Y = function(x,m,n)
            return math.abs(1-(1-((x+1)/2)^2)^m)^n
        end
        N1 = function(x,m,n)
            return (-Y(0,m,n) + (Y(0,m,n)-1)*x + Y(x,m,n))/ (1-2*Y(0,m,n))
        end
    }
    \pgfmathdeclarefunction{N1}{3}{%
        \edef\pgfmathresult{\directlua{tex.print(N1(\pgfmathfloatvalueof{#1},\pgfmathfloatvalueof{#2},\pgfmathfloatvalueof{#3}))}}%
    }%
    \begin{axis}[
        axis lines=center,
        enlargelimits,
        tick align=inside,
        no markers,
        legend entries={$N1(x,0.2,0.5)$\\$N1(x,1,5)$\\$N1(x,1,10)$\\},
        domain=-1:0.99999,
        samples=150,
        minor tick num=4,
    ]
    \addplot {N1(x,0.2,0.5)};
    \addplot {N1(x,1,5)};
    \addplot {N1(x,1,10)};
    \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

some remarks:

  • I have used Lua in order to benefit from its higher accuracy - the current formulation of N1 suffers from numerical instability near x=-1 (i.e. small errors in the input add up to huge errors in the output). This requires higher precision than TeX offers by means of its builtin methods.
  • I ignored the possibility to reuse the value for y(0,m,n). It does not hurt to compute it twice.
  • Add cycle list={dashed,black,black} to the option list of the axis to get your plot styles - I prefered the defaylt cycle list (with no markers) such that you can identify each in a legend (which I added as well).
  • Note that I chose to define a PGF math function N1 by means of \pgfmathdeclarefunction. This allows us to use N1(x,m,n) inside of a PGF math expression (in particular: in \addplot {<expression>}). The argument {3} means that the new function takes three arguments, available as #1, #2, and #3 as in a macro. Currently, these arguments are in some internal format generated by the floating point library (in TeX), so we need to convert them back to something understood by Lua (by means of \pgfmathfloatvalueof.
  • since I never plotted Y directly, I did not generate a \pgfmathdeclarefunction for Y -- after all, the Lua code can compute this in a self-contained fashion.
  • Note that \pgfmathdeclarefunction is supposed to assign results to the macro \pgfmathresult, which is the purpose of \edef\pgfmathresult. The tex.print is Lua's way to report results back to TeX.

In general, it would be safe to formulate the function by means of PGF's math engine which results in

\documentclass{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=1.9}

\begin{document}
\begin{tikzpicture}
    \pgfmathdeclarefunction{Y}{3}{%
        \pgfmathparse{abs(1-(1-((#1+1)/2)^2)^(#2))^(#3)}%
    }%
    \pgfmathdeclarefunction{N1}{3}{%
        \pgfmathparse{(-Y(0,#2,#3) + (Y(0,#2,#3)-1)*(#1) + Y(#1,#2,#3))/ (1-2*Y(0,#2,#3)}%
    }%
    \begin{axis}[
        axis lines=center,
        enlargelimits,
        tick align=inside,
        no markers,
        legend entries={$N1(x,0.2,0.5)$\\$N1(x,1,5)$\\$N1(x,1,10)$\\},
        domain=-1:0.99999,
        samples=150,
        minor tick num=4,
    ]
    \addplot {N1(x,0.2,0.5)};
    \addplot {N1(x,1,5)};
    \addplot {N1(x,1,10)};
    \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

Note the visible artifact near x=-1; it originates in the numerically instable function formulation near x=-1 combined with TeX's limited precision (unless I am mistaken).


You can use gnuplot to plot these. For instance, you can use the following code:

\documentclass{standalone}
\makeatletter\newwrite\verbatim@out\makeatother
\usepackage{gnuplottex}
\usepackage{epstopdf}

\begin{document}
\begin{gnuplot}[terminal=epslatex]
    set samples 2000 # Set to get more accurate, but slower
    set parametric
    set xtics -1,.5,1
    set ytics -1,.5,1

    set trange [-1:1] # Parametric plot range
    set xrange [-1.1:1.1] # Axis range

    set zeroaxis
    set border 0
    set xtics axis
    set ytics axis

    y(x,m,n) = (abs(1-(1-((x+1)/2)**2)**m))**n
    N(x,m,n) = (-y(0,m,n) + (y(0,m,n) - 1)*x + y(x,m,n))/(1 - 2*y(0,m,n))

    plot t,N(t,0.2,0.5) title "", t,N(t,1,5) title "", t,N(t,1,10) title ""
\end{gnuplot}
\end{document}

You need to compile it with the --shell-escape option, and have gnuplot installed.

As you can see in the code, it is easy to define and use functions in gnuplot, even with multiple parameters.

Rendering: rendering of the code


* Edit * Added dashed patterns, legend and a couple of labels; also an array mn[] of (m,n) pairs is used to create a function N1(m,n)(x) instead of the array of functions. enter image description here

% f.tex:
%
\documentclass{article}
\usepackage[inline]{asymptote}
\usepackage{lmodern}
\begin{document}
\begin{figure}
\centering
\begin{asy}[width=8cm]
size(9cm);
import graph;
import fontsize;
defaultpen(fontsize(9pt));

pen dashed=linetype(new real[] {4,4});
pen longdashed=linetype(new real[] {12,4});
pen dotted=linetype(new real[] {0,3});

pen[] fpen={
  gray+longdashed,
  black+dotted,
  black+dashed
};

real y(real x,real m,real n){
  return abs(1-(1-((x+1)/2)^2)^m)^n;
}

typedef real Func(real);

Func N1(real m,real n){
  return 
    new real(real x){
      return (-y(0,m,n)+(y(0,m,n)-1)*x+y(x,m,n))/(1-2y(0,m,n));
    };
}

pair[] mn={(0.2,0.5),(1,5), (1,10)}; 

real xmin=-1, xmax=1;

xaxis(xmin,xmax,LeftTicks(Label(LeftSide),Step=0.5,step=0.1,OmitTick(0)));
yaxis(RightTicks(Step=0.5,step=0.1,OmitTick(0)));

real penwidth=1bp; 
real m,n;
for(int i=0;i<mn.length;++i){
  m=mn[i].x; n=mn[i].y;
  draw(graph(N1(m,n),xmin,xmax,n=400),fpen[i]+penwidth
    ,legend="$N_1("+string(m)+","+string(n)+")$"
  );
}

label("$x$",1.1*(xmax,0),S); // 1.1*(xmax,0) is a location,
                         // alignment S == (0,-1)  means "South"
m=mn[2].x; n=mn[2].y;

label("$("+string(m)+","+string(n)+")$",
  (0.6,N1(m,n)(0.6))
  ,SW
);

add(
  legend(linelength=0.5legendlinelength,nullpen) // here nullpen means no frame 
  ,point(NE),SW,UnFill
);
\end{asy}
\caption{Family of functions $N_1(x,m,n)$}
\end{figure}
\end{document}

Process it as follows:

pdflatex f.tex
asy f-*.asy
pdflatex f.tex

* ======== first version ======== *

enter image description here

Plotting of such families of functions is straightforward with the Asymptote (which is part of the TeXLive distribution for quite a while). Inside the asy environment, the function N1(m,n) uses parameters m and 'n' to create a new real-valued function which takes one real argument. All functions that have to be plotted are collected in array f[] and then plotted inside a loop, using a prepared array of pens fpen[].

% f.tex:
%
\documentclass{article}
\usepackage[inline]{asymptote}
\usepackage{lmodern}
\begin{document}
\begin{figure}
\centering
\begin{asy}[width=7cm]
import graph;
import fontsize;
defaultpen(fontsize(9pt));
pen dashed=linetype(new real[] {4,4});

pen[] fpen={
  deepblue+dashed,
  black,
  orange
};

real y(real x,real m,real n){
  return abs(1-(1-((x+1)/2)^2)^m)^n;
}

typedef real Func(real);

Func N1(real m,real n){
  return 
    new real(real x){
      return (-y(0,m,n)+(y(0,m,n)-1)*x+y(x,m,n))/(1-2y(0,m,n));
    };
}

Func[] f={ N1(0.2,0.5), N1(1,5), N1(1,10) };

real xmin=-1, xmax=1;

xaxis(xmin,xmax,LeftTicks(Label(LeftSide),Step=0.5,step=0.1,OmitTick(0)));
yaxis(RightTicks(Step=0.5,step=0.1,OmitTick(0)));

real penwidth=1bp; 
for(int i=0;i<f.length;++i){
  draw(graph(f[i],xmin,xmax),fpen[i]+penwidth);
}
\end{asy}
\caption{Family of functions $N_1(x,m,n)$}
\end{figure}
\end{document}

Process it as follows:

pdflatex f.tex
asy f-*.asy
pdflatex f.tex

P.S. I hope you don't count the step asy f-*.asy as too much of extra work.