11

I am trying to generate this particular fractal image of a flower, but don't even know where or how to start. Can TikZ be used to generate a "Phylotactic spiral"?

I saw it here: https://www.reddit.com/r/FractalPorn/comments/xr17t1/fractal_rose/

and the image looks as given below: Fractal Image

It seems like loads of dots, so I began trying with a scatterplot on pgfplots, but failed completely. No code worth showing here.

EDIT: How do I put a green-tick to more than one answer? The results you folks have given are astounding!

7
  • I can't see where there's any fractal in that design. It's at most a scaled repetition of the same eight leaves flower. Shouldn't involve any fractal definition.
    – SebGlav
    Oct 11, 2022 at 18:55
  • 4
    Fractal := scaled repetition Oct 11, 2022 at 19:00
  • To me it looks like you want what once was called dithering. Here are a few tikz-solutions: tex.stackexchange.com/questions/266881/… . // Se also: bartwronski.com/2016/10/30/… + elopezr.com/dithering-algorithm + tannerhelland.com/2012/12/28/… and many other.
    – MS-SPO
    Oct 11, 2022 at 19:31
  • 1
    Hi! An approach for your image might be the following: 1) Draw the basic quadrilateral (plain color first). 2) Transform it into a pic element. 3) Learn how to use the command ($(p)! c! angle: (p)$) which produces the image of the point q through a direct similarity of center p, ratio c, and angle angle. 4) Do some mathematics for one of the spirals and create it with the pic and the above similarity. 5) Use a \foreach loop to have your eight leaves. 6) Modify the filling of the elementary quadrilateral (in the initial pic) to have the desired effect.
    – Daniel N
    Oct 11, 2022 at 19:33
  • 1
    @hpekristiansen Many definitions of a fractal are a bit more strict than that. Otherwise, a line segment would be a fractal, as you can make it by putting together infinitely many line segments end to end, each half the size of the one before.
    – Hearth
    Oct 12, 2022 at 4:30

3 Answers 3

27

I'm using Sandy G's formula here, basically the .707^<level> part.

Two approaches:

  1. PGF and LuaLaTeX that uses JLDiaz' great poisson lua script.
  2. TikZ and PGFmath that just uses the rnd function.

The macro \pgfpointspiralifdefined makes sure that coordinates that have been calculated already don't need to have be recalculated.

Instead of the coordinate a, b, c and d, you can also use the vertex anchors of the kite shape that Sandy G's answer uses (you need to name the nodes of course, e.g. spiral-\l-\n).

In both solutions I'm cubing one of the random values so that the points get bunched to one side of the kites.

PGF + LuaLaTeX

\documentclass{standalone}
\usepackage{pgf,pgffor}
\usepackage{jldiaz-poisson}% https://tex.stackexchange.com/a/185423/16595
\usepackage{xcolor} % colorwheel
\definecolor{cw0}{HTML}{9AFF00}\definecolor{cw1}{HTML}{FFA500}
\definecolor{cw2}{HTML}{FF001A}\definecolor{cw3}{HTML}{FF00D9}
\definecolor{cw4}{HTML}{6500FF}\definecolor{cw5}{HTML}{005AFF}
\definecolor{cw6}{HTML}{00FFE5}\definecolor{cw7}{HTML}{00FF25}
\pgfset{
  declare function={
    spiralAngle(\level,\spiral) = \directlua{tex.print(
      180/(\pgfkeysvalueof{/pgf/spiral\space N})*\level
     +360/(\pgfkeysvalueof{/pgf/spiral\space N})*\spiral)};
    spiralRadius(\level)        = \directlua{tex.print(
      .707^\level*(\pgfkeysvalueof{/pgf/spiral\space radius}))};
    xSpread(\n)=\n^3*.8+.1; ySpread(\n)=\n*.8+.1;},
  spiral radius/.initial=5, spiral N/.initial=8}
\newcommand*\pgfpointspiral[2]{% #1 = level, #2 = spiral
  \pgfpointpolarxy{spiralAngle(#1,#2)}{spiralRadius(#1)}}
\makeatletter
\newcommand*\pgfpointspiralifdefined[3]{%
  % if spiral-#2-#3 doesn't exist, define it
  % if it does do nothing
  \pgfutil@ifundefined{pgf@sh@ns@spiral-#2-#3}{%
    \pgfcoordinate{spiral-#2-#3}{\pgfpointspiral{#2}{#3}}%
  }{}% and make it an alias for #1
  \pgfnodealias{#1}{spiral-#2-#3}}
\makeatother
\begin{document}
\begin{pgfpicture}
\pgfsetxvec{\pgfqpoint{5mm}{0mm}}
\pgfsetyvec{\pgfqpoint{0mm}{5mm}}
\foreach \l in {0,...,6}{
  \foreach \n in {0,...,7}{
    \pgfpointspiralifdefined{a}{\l}            {\n}
    \pgfpointspiralifdefined{b}{\inteval{\l+1}}{\n}
    \pgfpointspiralifdefined{c}{\l}            {\inteval{\n+1}}
    \pgfpointspiralifdefined{d}{\inteval{\l-1}}{\inteval{\n+1}}
    \pgfsetfillcolor{cw\n}
    \foreach[expand list, evaluate={\xSpread=xSpread(\x);}]
      \x/\y in {\poissonpointslist{1}{1}{.02+.0\l}{10}} {
      \pgfpathcircle{
        \pgfpointlineattime{ySpread(\y)}
          {\pgfpointlineattime{\xSpread}
            {\pgfpointanchor{a}{center}}{\pgfpointanchor{b}{center}}}
          {\pgfpointlineattime{\xSpread}
            {\pgfpointanchor{d}{center}}{\pgfpointanchor{c}{center}}}
      }{+.25pt}
      \pgfusepath{fill}
    }
  }
}
\end{pgfpicture}
\end{document}

TikZ + PGFmath

The \pgfpointspiralifdefined could have also been implemented by a custom TikZ coordinate system but why bother …

\documentclass[tikz]{standalone}
\usetikzlibrary{calc}
\pgfset{
  declare function={
    xSpread(\n)=\n^3*.8+.1; ySpread(\n)=\n*.8+.1;},
  spiral radius/.initial=5,
  spiral N/.initial=8}
\newcommand*\pgfpointspiral[2]{% #1 = level, #2 = spiral
  \pgfpointpolarxy{180/(\pgfkeysvalueof{/pgf/spiral N})*(#1)
                  +360/(\pgfkeysvalueof{/pgf/spiral N})*(#2)}
                  {.707^(#1)*(\pgfkeysvalueof{/pgf/spiral radius})}}
\makeatletter
\newcommand*\pgfpointspiralifdefined[3]{%
  \pgfutil@ifundefined{pgf@sh@ns@spiral-#2-#3}{%
    \pgfcoordinate{spiral-#2-#3}{\pgfpointspiral{#2}{#3}}%
  }{}%
  \pgfnodealias{#1}{spiral-#2-#3}}
\makeatother
\begin{document}
\begin{tikzpicture}[x=+5mm, y=+5mm]
\foreach \l[evaluate={\Dots=250*.7^\l}] in {0,...,6} {
  \foreach \n in {0,...,7} {
    \pgfpointspiralifdefined{a}{\l}            {\n}
    \pgfpointspiralifdefined{b}{\inteval{\l+1}}{\n}
    \pgfpointspiralifdefined{c}{\l}            {\inteval{\n+1}}
    \pgfpointspiralifdefined{d}{\inteval{\l-1}}{\inteval{\n+1}}
    \fill[radius=+.4pt] foreach[
      evaluate={\xSpread=xSpread rnd; \ySpread=ySpread rnd;}]
      \dot in {0,...,\Dots} {
        ($($(a)!\ySpread!(d)$)!\xSpread!($(b)!\ySpread!(c)$)$)
        circle[radius=+.4pt]};
  }
}
\end{tikzpicture}
\end{document}

Output

enter image description here enter image description here

3
25

Here is the rose, which uses the kite node shape from the tikz library shapes.geometric. I leave it to others to fill the nodes with dots.

enter image description here

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{shapes.geometric}

\tikzset{mykite/.style={inner sep=.1pt, kite, fill=red!30, kite vertex angles=120 and 75}}

\begin{document}

\begin{tikzpicture}
\foreach \l in {1,...,12}{
\foreach \n[evaluate=\n as \t using \l*22.5+\n*45, % \t is the angle for node placement
    evaluate=\n as \s using .703^(\l-1), % \s is the scaling factor for the distance from 0 for each level
    evaluate=\n as \c using \s-.01] in {1,...,8} % \c is used to shrink each node just a bit.
    {\node[mykite, rotate=\t, minimum size=\c cm] at (\t-90:{\s*1.38}){};}
}
\end{tikzpicture}

\end{document}

To get an 8-vertex rose, the kite vertex angles must differ by 45 (120 and 75 in the code above). You can change .703 to (sin((\aaa-45)/2)/sin(\aaa/2)), where \aaa is the larger angle to get variations in the shape. The 1.38 factor needs adjusting as well.

enter image description here

6

enter image description hereTest

I tried to make the construction using a pic and a helix like curve. All the computations are hidden in the definition of the petalPiece (the pic element) which creates a quadrangle; each petal will consist of \nbQuad pieces.

There are two global variables: the number of petals and the number of pieces for each petal. For example, with 9 petals, we get the drawing below. enter image description here

The code

\documentclass[11pt, margin=1cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{math, calc}
\begin{document}

\tikzmath{
  integer \nbPetals, \nbQuad;
  \nbPetals = 8;
  \nbQuad = 7;
  real \a, \base, \r;
  \a = 360/\nbPetals;  % petal's angle
  \base = 2;  % base of the exponential definig the helix
  \r = .35;  % scaling constant
  function tmpR(\i) {% integer giving a point along the helix
    return {\r*pow(\base, 3.145*\i/\nbQuad)};
  };
}
\tikzset{%
  pics/petalPiece/.style 2 args={% branch number, base point number
    code={%
      \tikzmath{integer \b, \p; \b = #1; \p = #2;}
      \path
      (\p/\nbQuad*180 +\b*\a: {tmpR(\p)}) coordinate (NW)
      ({(\p +1)/\nbQuad*180 +\b*\a}: {tmpR(\p +1)}) coordinate (NE)
      ({(\p +2)/\nbQuad*180 +(\b -1)*\a}: {tmpR(\p +2)}) coordinate (SE)
      ({(\p +1)/\nbQuad*180 +(\b -1)*\a}: {tmpR(\p +1)}) coordinate (SW);
      \foreach \i in {0, .05, ..., .9}{%
        \draw[white, thick, fill=magenta!90, opacity=.05]
        ($(NW)!\i!(SW)$) -- ($(NE)!\i/2!(SE)$) -- (SE) -- (SW) -- cycle;
      }
    }
  }
}
\begin{tikzpicture}
  \foreach \l in {1, 2, ..., \nbPetals}{
    \foreach \i in {-1, 0, 1, 2, ..., \nbQuad}{%
      \path (0, 0) pic {petalPiece={\l}{\i}};
    }
  }
\end{tikzpicture}

You must log in to answer this question.

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