36

In my thesis that I'm writing on, I'm using a Mandelbrot generator to test an application I've written. To explain a certain problem discussed in the report an actual generated image need to be included.

Since every figure in the report so far has been generated using TikZ, I'm wondering whether I could also generate the Mandelbrot image using TikZ. But would it possible?

2
  • 1
    There's a TikZ library for fractal decorations (30.7 Fractal Decorations) and a Lindenmayer systems library (37 Lindenmayer System Drawing Library) Aug 25, 2012 at 15:44
  • Heiko Oberdiek posted a Mandelbrot generator in LaTeX at the Programming Puzzels & Code Golf stackexchange: codegolf.stackexchange.com/questions/23423/… Mar 25, 2014 at 5:50

6 Answers 6

27

There's a Mandelbrot set shading in the shadings library:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shadings}
\begin{document}
\tikz\shade[shading=Mandelbrot set] (0,0) rectangle (4,4);
\end{document}

Mandelbrot set

Displayed with the Acrobat Reader, as the TeXworks PDF previewer did not show high resolution.

The Mandelbrot set is computed and generated by the PDF renderer. The algorithm is written using PostScript commands, PDF supports a subset of Postscript operators, that's why it should be much faster than computing using higher level pgf or TikZ operators.

4
  • Ha! Well, that was unexpected. ^^ Unfortunately, the image doesn't exactly look like a Mandelbrot set, but cool nonetheless.
    – gablin
    Dec 28, 2011 at 17:05
  • 3
    @gablin This could be caused by a low number of iterations, I would expect that a higher number of iterations would be nearer to the exact Mandelbrot set, which would require an infinite number of iterations.
    – Stefan Kottwitz
    Dec 28, 2011 at 17:10
  • @StefanKottwitz Is there any way to increase the iteration count? That looks like 10 or so iterations . . . you get a much better picture even with just 20. Nov 15, 2013 at 18:53
  • @mrc Yes, it can be seen in the code of that TikZ library, the number of iteration is fixed but can be extended by changing or redefining the code.
    – Stefan Kottwitz
    Nov 15, 2013 at 22:15
23

Here is a rather crude solution using luatex. Note that the calculations are done without any optimization, no use of symmetry or any other properties of the Mandelbrot set. Warning: the code takes a while to process even on a fairly fast computer.

\documentclass{standalone}
\usepackage{tikz}
\usepackage{luacode}

\def\escapetime#1#2{\directlua{tex.print(escape_time(#1,#2))}}
\def\mandcolor#1#2{\directlua{mand_color(#1,#2)}}

\begin{document}
\begin{luacode}
local NUMITER=100

point_iter = function (a,b) 
   local n = 1
   local x = a
   local y = b
   return function ()
      if n > NUMITER then return nil end
      n = n+1
      x,y = x*x - y*y + a, 2*x*y + b
      return n, x*x + y*y
   end
end

escape_time = function (a,b)
   local esc_time
   for n, d in point_iter(a,b) do
      esc_time = n
      if d > 4 then break end
   end
   return esc_time
end

mand_color = function (a,b)
   local etime = escape_time(a,b)
   if etime == NUMITER+1 then tex.print("black") else tex.print("red!"..etime) end
end
\end{luacode}
\begin{tikzpicture}[scale=2]
   \foreach \x in {-2,-1.99,...,.5}{
      \foreach \y in {-1.3,-1.29,...,1.3}{
      \draw[\mandcolor{\x}{\y},fill] (\x,\y) +(-.005,-.005) rectangle +(.005,.005);}}
\end{tikzpicture}
\end{document}

This is the resulting image:

mandelbrot set generated with lualatex

The next step would be to use mplib directly from lua to render the picture.

22

For those who are interested in another approach, i.e., using PSTricks:

\documentclass[border=12pt]{standalone}
\usepackage{pst-fractal}

\begin{document}
\psfractal[type=Mandel,baseColor=red,maxRadius=30,dIter=30,cx=-1.3,xWidth=4cm,yWidth=4cm](-3,-2)(2,2)
\end{document}

enter image description here

Compile the code snippet above with xelatex or latex-dvips-ps2pdf sequence.

3
  • 1
    Very cool! How does the pstricks compare to MATLAB or Python in the terms of speed when it comes to things like plotting strange attractors, KAM islands or fractals? How difficult is to generate movie? In MATLAB is for example trivial to generate movie which shows creation of the Lorenz attractor. It is fairly easy to call such movie from the Powerdot slides (written in PSTricks) but I wonder if I could create animation natively which will not require to launch a video player. Dec 29, 2011 at 2:05
  • 2
    I believe that pstricks does not actually generate the image, it inserts postscript code that does the actual calculation. Which means the speed would depend on your postscript interpreter. When printing such document on a postscript printer, the calculations would be done on the printer. When viewing the resulting dvi or postscript file, the calculations would be done by your dvi or ps viewer at the time of viewing. Perhaps you could first convert from postscript to another format, the calculation would happen then, and view the result later. Dec 29, 2011 at 2:52
  • Of course. I meant PostScript and Ghostscript interpreter vs MATLAB or Python. See my post here for getting row PostScript into TeX with command special tex.stackexchange.com/questions/23987/… Dec 29, 2011 at 4:39
11

I posted a pgfplots solution on TeXwelt.de drawing the Mandelbrot set: Fraktale mit pgfplots. Christian Feuersänger improved it, instead of creating a table (as inspired by Herbert) doing the sampling via \addplot3 and the coloring by surf and shader=interp. Run it with LuaLaTeX.

Mandelbrot set

The complete code:

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{width=7cm,compat=1.8}
\usepackage{luacode}
\begin{luacode}
  function mandelbrot(cx,cy, max_iter, max)
    local x,y,xtemp,ytemp,squaresum,iter
    squaresum = 0
    x = 0
    y = 0
    iter = 0
    while (squaresum <= max) and (iter < max_iter)  do
      xtemp = x * x - y * y + cx
      ytemp = 2 * x * y + cy
      x = xtemp
      y = ytemp
      iter = iter + 1
      squaresum = x * x + y * y
    end
    local result = 0
    if (iter < max_iter) then
        result = iter
    end
    -- result = squaresum
    -- io.write("" .. cx .. ", " .. cy .. " = " .. result .. " (iter " .. iter .. " squaresum " .. squaresum .. ") \string\n")
    tex.print(result);
  end
\end{luacode}
\begin{document}
\begin{tikzpicture}
  \begin{axis}[
    colorbar,
    axis equal,
    point meta max=30,
    tick label style={font=\tiny},
    view={0}{90}]
    \addplot3 [surf,domain=-1.72:0.72,shader=interp,domain y=-1:1,samples=300] {
        \directlua{mandelbrot(\pgfmathfloatvalueof\x,
        \pgfmathfloatvalueof\y,10000,4)}
    };
  \end{axis}
\end{tikzpicture}
\end{document}
5

I couldn't resist to proposing a MetaPost version. After all, MetaPost is embedded in LuaTeX and thanks to the package luamplib we have direct access to it, so it would be a pity not to take advantage of this fact :-)) All credits must go to Stephan Kottwitz though (and to Herbert previously), since the following code is almost entirely an adaptation of his Lua Code to MetaPost. Without it, drawing this would probably not have been possible to me, since I know too little about fractals.

Notice the call to MetaPost's newly implemented floating point number system by the instruction \mplibnumbersystem{double}. I figure it is necessary, due to the heaviness of the computations.

Caution: it may take several minutes for the following code to compile! (10 min for my 5-year old laptop.)

\documentclass[12pt]{article}
\usepackage{luamplib}
  \mplibnumbersystem{double}
  \mplibtextextlabel{enable}
\begin{document}
\begin{center}
  \leavevmode
  \begin{mplibcode} 
    u := 4cm;
    vardef mandelbrot(expr xa, xb, ya, yb, steps, max_iter, maxs) =
      save dx, dy, cx, cy, xtemp, ytemp, squaresum, iter; clearxy;
      dx := (xb-xa)/steps; 
      dy := (yb-ya)/steps; 
      cx := xa;
      forever:
        exitunless cx <= xb;
        cy := ya;
        forever:
          exitunless cy <= yb;
          squaresum := 0;
          x:= 0; y:= 0; iter := 0;
          forever:
            exitunless (squaresum <= maxs) and (iter < max_iter);
            xtemp := x**2 - y**2 + cx;
            ytemp := 2*x*y + cy;
            x := xtemp;
            y := ytemp;
            iter := iter + 1;
            squaresum := x**2 + y**2;
          endfor;
          if iter >= max_iter: draw u*(cx, cy); fi;
          cy := cy + dy;
        endfor;
        cx := cx + dx;
      endfor; 
    enddef;
    beginfig(0);
      % Coordinates and marks
      xmin = -2; xmax = 0.75; ymin = -1.25; ymax = 1.25; len := 6bp;
      draw u*(xmin, ymin) -- u*(xmax, ymin) -- u*(xmax, ymax) -- u*(xmin, ymax) -- cycle; 
      for i = -1.5 step .5 until .5:
        label.bot("$" & decimal i & "$", u*(i, ymin));
        draw u*(i, ymin) -- (i*u, ymin*u+len);
        draw u*(i, ymax) -- (i*u, ymax*u-len);
      endfor;
      for j = -1 step 1 until 1:
        label.lft("$"&decimal j&"$", u*(xmin, j));
        draw u*(xmin, j) -- (xmin*u+len, j*u);
        draw u*(xmax, j) -- (xmax*u-len, j*u);
      endfor;
      % Mandelbrot fractal
      pickup pencircle scaled 1bp;
      mandelbrot(-2, 1, -2, 2, 500, 1000, 4);
    endfig;
  \end{mplibcode}
\end{center}
\end{document}

enter image description here

0

With knitr one can use R to draw the Mandelbrot set (R code from here):

\documentclass[12pt]{scrartcl}
\begin{document}
<<echo=F>>=
    cols <- colorRampPalette(c("blue","yellow","red","black"))(11)
    xmin = -2
    xmax = 1
    nx = 500
    ymin = -1.5
    ymax = 1.5
    ny = 500
    n=200
    
    # variables
    x <- seq(xmin, xmax, length.out=nx)
    y <- seq(ymin, ymax, length.out=ny)
    c <- outer(x,y*1i,FUN="+")
    z <- matrix(0.0, nrow=length(x), ncol=length(y))
    k <- matrix(0.0, nrow=length(x), ncol=length(y))
    
    for (rep in 1:n) {
        index <- which(Mod(z) < 2)
        z[index] <- z[index]^2 + c[index]
        k[index] <- k[index] + 1
    }
    image(x,y,k, col=cols)
@
\end{document}

mandelbrot set

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .