26

how to plot the function $f:x\mapsto \int_x^{2x}\frac{4}{\sqrt{1+t^4}}\, \textrm{d}t$ with TikZ?

enter image description here

g.kov
  • 21,864
  • 1
  • 58
  • 95
Vibrer
  • 261
  • 3
  • 3
  • 7
    you could try using pgfplots. would be nice though, if you could provide a MWE of what you've already got. – Rico Aug 23 '13 at 11:58
  • 3
    Welcome to TeX.SX! You can have a look at our starter guide to familiarize yourself further with our format. – Heiko Oberdiek Aug 23 '13 at 12:07
  • 2
    I don't think is possible to use durectly TikZ or pgfplots to plot such a function. I suggest to use another program (like Matlab or Mathematica) to generate a data file for this function and then to plot the file using pgfplots. – Red Aug 23 '13 at 13:02
  • matlab2tikz would be a useful tool if you follow Red's suggestion. – Herr K. Aug 23 '13 at 13:26
  • 1
    Integration is exclusive to PSTricks and Asymptote (leave Metapost aside). People have been doing amazing stuff with them. example, http://pstricks.blogspot.de/2012/06/lattracteur-de-lorenz-avec-pstricks.html You can make a table of small increments though with pgfplots – percusse Aug 23 '13 at 13:28
  • 1
    As for compilation times, it would be far faster to \includegraphics a generated pdf (made with Mathematica/etc.) and then superimpose ticks and labels. Doing things like this with TeX-based tools, while certainly possible, isn't practical in the end. – Sean Allred Aug 23 '13 at 13:46
  • 1
    If you want to use TikZ then, you could use gnuplot. It doesn't support integration natively, but you can find examples easily googling them. Another alternative would be using LuaTeX and doing the integration in Lua. – Toscho Aug 23 '13 at 15:02

4 Answers4

38

enter image description here

MWE using adaptive Simpson integration (Asymptote):

% s.tex:
\documentclass{article}
\usepackage[inline]{asymptote}
\usepackage{lmodern}
\begin{document}
\begin{asy}
size(300,200,IgnoreAspect);
import graph;
real F(real t){return 4/sqrt(1+t^4);}
real f(real x){return simpson(F,x,2x);}
pen axPen=darkblue;
pen fPen=red+1bp;
draw(graph(f,-7,7,n=200),fPen);
string noZero(real x) {return (x==0)?"":string(x);}
defaultpen(fontsize(10pt));
xaxis(axPen,LeftTicks(noZero,Step=2));
yaxis(axPen,RightTicks(noZero,Step=0.5));

label("$f:x\mapsto \displaystyle\int_x^{2x}"
     +"\frac{4}{\sqrt{1+t^4}}\, \textrm{d}t$"
  ,(1.7,f(1.7)),NE);
\end{asy}
\end{document}    

% To process it with `latexmk`, create file `latexmkrc`:
% 
%     sub asy {return system("asy '$_[0]'");}
%     add_cus_dep("asy","eps",0,"asy");
%     add_cus_dep("asy","pdf",0,"asy");
%     add_cus_dep("asy","tex",0,"asy");
% 
% and run `latexmk -pdf s.tex`.
g.kov
  • 21,864
  • 1
  • 58
  • 95
  • 2
    That's great, I've to investigate Asymptote someday. – juliohm Aug 23 '13 at 15:06
  • @PSTikZ: see Asymptote answer added. – g.kov Aug 23 '13 at 18:23
  • I attempted to compile your code as discussed here but I did not get the asymptote output. The only output I got is the graphics caption. – kiss my armpit Sep 03 '13 at 22:07
  • @PSTikZ: the answer is pretty simple: latexmk script expects latexmkrc, not the latexmkrc.pl. Something like \immediate\write18{mv latexmkrc.pl latexmkrc} \immediate\write18{latexmk -pdf integral.tex} works (just checked). – g.kov Sep 03 '13 at 22:48
  • mv is not recognized.... – kiss my armpit Sep 03 '13 at 22:57
  • What is the correct extension for latexmkrc file? If I ignore the extension, filecontents will use .tex by default. – kiss my armpit Sep 03 '13 at 23:52
  • @PSTikZ: The correct extension for latexmkrc is empty. It seems that TeX has problems with creation files with empty extension, at least on some file systems. On windows file systems latexmkrc. might work. – g.kov Sep 04 '13 at 10:11
26

Here is the PSTricks answer. I slightly changed the \psCumIntegral macro from pst-func to account for the different integration limits:

\documentclass[preview, varwidth, border=5pt]{standalone}
\usepackage{pst-func}

\makeatletter
\def\psMyIntegral{\pst@object{psMyIntegral}}
\def\psMyIntegral@i#1#2#3{%
  \begin@OpenObj%
  \addto@pscode{
    /xStart #1  def
    /dx #2 #1 sub \psk@plotpoints\space div def
    /a #1 def
    /b a 2 mul def
    /scx { \pst@number\psxunit mul } def
    /scy { \pst@number\psyunit mul } def
    tx@FuncDict begin /SFunc { #3 } def end
    \psk@plotpoints 1 add {
      a b \psk@Simpson
      tx@FuncDict begin Simpson I end
      scy a scx exch a xStart eq {moveto}{lineto}ifelse
      /a a dx add def
      /b a 2 mul def
    } repeat
  }%
  \end@OpenObj%
}
\makeatother

\begin{document}

\psset{xunit=0.8,yunit=1.5}
\begin{pspicture}(-7,-2)(7,2)
  \psMyIntegral[plotpoints=500, linecolor=red]{-7}{7}{4 exp 1 add sqrt 4 exch div}
  \psaxes[Dy=0.5, arrows=->](0,0)(-7,-2)(7,2)
  \rput[rt](7,2){$f:x\mapsto \displaystyle\int_x^{2x} \frac{4}{\sqrt{1+t^4}}\, \textrm{d}t$}
\end{pspicture}
\end{document}

That gives:

enter image description here

EDIT: Here comes a more general macro \psVarIntegral, which allows to specify both limits a(x) and b(x) in terms of functions operating on the x-value on the stack.

\documentclass[pstricks, border=5pt]{standalone}
\usepackage{pst-func}

\makeatletter
\def\psVarIntegral{\pst@object{psVarIntegral}}
\def\psVarIntegral@i#1#2#3#4#5{%
  \begin@OpenObj%
  \addto@pscode{
    /xStart #1 def
    /xCurr #1 def
    /dx #2 #1 sub \psk@plotpoints\space div def
    /a #1 #3 def
    /b #1 #4 def
    /scx { \pst@number\psxunit mul } def
    /scy { \pst@number\psyunit mul } def
    tx@FuncDict begin /SFunc { #5 } def end
    \psk@plotpoints 1 add {
      a b \psk@Simpson
      tx@FuncDict begin Simpson I end
      scy xCurr scx exch xCurr xStart eq {moveto}{lineto}ifelse
      /xCurr xCurr dx add def
      /a xCurr #3 def
      /b xCurr #4 def
    } repeat
  }%
  \end@OpenObj%
}
\makeatother

\begin{document}

\psset{xunit=0.8,yunit=1.5}
\begin{pspicture}(-7,-2)(7,2)
  \psVarIntegral[plotpoints=500, linecolor=red]{-7}{7}{}{2 mul}{4 exp 1 add sqrt 4 exch div}
  \psaxes[Dy=0.5, arrows=->](0,0)(-7,-2)(7,2)
  \rput[rt](7,2){$f:x\mapsto \displaystyle\int_x^{2x} \frac{4}{\sqrt{1+t^4}}\, \textrm{d}t$}
\end{pspicture}
\end{document}
Christoph
  • 16,593
  • 1
  • 23
  • 47
15

Here is another, quite compact, PSTricks solution.

The TikZ solution using the same numerical approach is given below to satisfy the OP.

\pstODEsolve (RKF45 method) from the pst-ode package is used to solve the definite integral between x and 2 x at each of the 501 plot points in the interval [-7,7]. The initial value for each \pstODEsolve invocation is set to zero to immediately get the definite integral at 2 x.

\documentclass[pstricks,border=5pt]{standalone}
\usepackage{pst-ode,pst-plot}

\begin{document}
\pstVerb{/result {} def} %initialise empty result list
\multido{\nX=-7.00+0.028}{501}{% 501 plotpoints
  %integral = [x 0 2x F(2x)] (two output points)-------------v   v----initial value
  \pstODEsolve[algebraicAll]{integral}{t | y[0]}{\nX}{2*\nX}{2}{0.0}{4/sqrt(1+t^4)}
  %append [x F(2x)] to results list
  \pstVerb{/result [result integral exch pop exch pop] cvx def}
}
%plot result
\psset{xunit=0.8,yunit=1.5}
\begin{pspicture}(-7,-2)(7,2)
  \psaxes[Dy=0.5, arrows=->](0,0)(-7,-2)(7,2)
  \listplot[linecolor=red]{result}
  \rput[rt](7,2){$f:x\mapsto \displaystyle\int_x^{2x} \frac{4}{\sqrt{1+t^4}}\, \textrm{d}t$}
\end{pspicture}
\end{document}

enter image description here


TikZ/PGFPlots solution, requires pdflatex --shell-escape:

enter image description here

\documentclass[tikz,border=5pt]{standalone}
\usepackage{pgfplots} \pgfplotsset{width=\linewidth,compat=1.9}
\usepackage{filecontents}

\begin{filecontents}{xyz.tex}
  \input pst-ode \input multido
  \pstVerb{/statefile (result.dat) (w) file def}
  \multido{\nX=-7.00+0.028}{501}{% 501 plotpoints
    \pstODEsolve[algebraicAll]{integral}{t | y[0]}{\nX}{2*\nX}{2}{0}{4/sqrt(1+t^4)}
    \pstVerb{[integral exch pop exch pop] tx@odeDict begin writeresult end}
  }
  \pstVerb{statefile closefile} \bye
\end{filecontents}
\immediate\write18{tex xyz}\immediate\write18{dvips xyz}
\immediate\write18{ps2pdf -dNOSAFER xyz.ps}

\begin{document}
\begin{tikzpicture}
  \begin{axis}[
      axis x line=center, axis y line=center, unit vector ratio=0.8 1.5,
      ymin=-2, ymax=2, xtick={-7,...,6}, ytick={-2,-1.5,...,1.5},
      y tick label style={/pgf/number format/.cd, fixed, fixed zerofill, precision=1},
    ]
    \addplot[red] table {result.dat};
    \node [anchor=north east] at (axis cs:7,2)
      {$f:x\mapsto \displaystyle\int_x^{2x} \frac{4}{\sqrt{1+t^4}}\, \textrm{d}t$};
  \end{axis}
\end{tikzpicture}
\end{document}
AlexG
  • 54,894
  • \immediate\write18{tex xyz && dvips xyz && ps2pdf -dNOSAFER xyz.ps} does work as well and simpler. – kiss my armpit Jul 26 '14 at 14:29
  • @Pleasedon'ttouch Yes I know. But it is Bash syntax and hence not portable, say, to a Windows box. Therefore I used two separate \write18's. – AlexG Aug 02 '14 at 20:26
  • Nice! I'm trying to adapt the code to the function \int_{-\infty}^{x}exp(-1/(t*(2-t)))dt but after latex and dvips the ps file loads forever and does not show anything. Your code works right for the example, but not with my function. Any idea? – Sigur Oct 01 '16 at 14:31
  • The integral doesn't seem to be defined around x =0? The following works : x =[-10,-9.975,-9.950,...,-0.05] (399 steps) : \multido{\nX=-10+0.025}{399}{...} and using -1e6 for -\infty \pstODEsolve[algebraicAll]{integral}{t | y[0]}{-1000000}{\nX}{2}{0.0}{Euler^(-1/(t*(2-t)))} – AlexG Oct 01 '16 at 16:33
  • @AlexG I try to compile your PSTricks code but I get error as the following: https://i.imgur.com/9rnt4YE.png . My pst-ode ver. is 0.12 –  Mar 23 '19 at 04:42
  • @chishi I'll have a look at it asap. – AlexG Mar 23 '19 at 08:17
  • 1
    @TrongVuong : Thank you for reporting. Indeed, this is a bug, introduced in v0.11, file pst-ode.pro, which occurs when stepping in negative direction (d t <0). Fixed in v0.14 which is on the way to CTAN. Or: https://gitlab.com/agrahn/pst-ode . – AlexG Mar 25 '19 at 14:14
2

You can use the GNU Scientific Library (GSL) via the FFI of LuaJITTeX (and LuaTeX ≥ 1.0.3). Needs --shell-escape.

\documentclass{article}

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

\usepackage{luacode}
\begin{luacode*}
local ffi = require("ffi")

ffi.cdef[[
typedef double (*gsl_callback) (double x, void * params);

typedef struct {
  gsl_callback F;
  void * params;
} gsl_function;

typedef void gsl_integration_workspace;

gsl_integration_workspace * gsl_integration_workspace_alloc (size_t n);

void gsl_integration_workspace_free (gsl_integration_workspace * w);

int gsl_integration_qags(gsl_function * f, double a, double b, double epsabs, double epsrel, size_t limit,
                         gsl_integration_workspace * workspace, double * result, double * abserr);
]]

local gsl = ffi.load("gsl")

function gsl_qags(f, a, b, epsabs, epsrel, limit)
   local limit = limit or 50
   local epsabs = epsabs or 1e-8
   local epsrel = epsabs or 1e-8

   local gsl_function = ffi.new("gsl_function")
   gsl_function.F = ffi.cast("gsl_callback", function(x, params) return f(x) end)
   gsl_function.params = nil

   local result = ffi.new('double[1]')
   local abserr = ffi.new('double[1]')

   local workspace = gsl.gsl_integration_workspace_alloc(limit)
   gsl.gsl_integration_qags(gsl_function, a, b, epsabs, epsrel, limit, workspace, result, abserr)
   gsl.gsl_integration_workspace_free(workspace)

   gsl_function.F:free()

   return result[0]
end

function f(x)
    tex.sprint(gsl_qags(function(t) return 4/math.sqrt(1+t^4) end, x, 2*x))
end
\end{luacode*}

\begin{document}

\begin{tikzpicture}[
  declare function={f(\x) = \directlua{f(\x)};}
  ]
  \begin{axis}[
    use fpu=false, % very important!
    no marks, samples=101,
    ]
    \addplot {f(x)};
  \end{axis}
\end{tikzpicture}

\end{document}

enter image description here

Henri Menke
  • 109,596