Parametric Rose Plot

I saw a beautiful parametric plot on X (Twitter) by Juan Carlos, that looks like a rose, done in Desmos.

I thought it would be great to understand the math and to plot it in LaTeX. Hard without seeing the math though. As Valentine’s day was approaching, I was motivated and did some research. I found such a plot done in Mathematica by Paul Nylander. He showed this Mathematica code:

Rose[x_, theta_] := Module[{phi = (Pi/2)Exp[-theta/(8 Pi)], X = 1 - (1/2)((5/4)(1 -
  Mod[3.6 theta, 2 Pi]/Pi)^2 - 1/4)^2}, y = 1.95653 x^2 (1.27689 x - 1)^2 Sin[phi];
  r = X(x Sin[phi] + y Cos[phi]); {r Sin[theta], r Cos[theta], X(x Cos[phi] - y Sin[phi]), EdgeForm[]}];

ParametricPlot3D[Rose[x, theta], {x, 0, 1}, {theta, -2 Pi, 15 Pi}, PlotPoints -> {25, 576},
  LightSources -> {{{0, 0, 1}, RGBColor[1, 0, 0]}}, Compiled -> False]

That’s something I can work with!

I wrote a function in Lua for this calculation, embedded it in a LuaLaTeX document, and used pgfplots to do the x and y sampling to generate a parametric plot.

As a small addition, I added some background and a small stalk using axis cs coordinates.

Have fun, and Happy Valentine’s Day 2025!

% !TEX=lualatex
\documentclass{standalone}
\usepackage{pgfplots}
\usetikzlibrary{backgrounds}
\pgfplotsset{width=7cm, compat=1.18}
\usepackage{luacode}
\begin{luacode*}
  function Calculate(axis, x, theta)
    local phi = (math.pi / 2)
      * math.exp(-theta / (8 * math.pi))
    local X = 1 - 0.5 * ((5/4) * (1-((3.6 * theta)
      % (2 * math.pi) ) / math.pi)^2 - 1/4)^2
    local y = 1.95653 * x^2
      * (1.27689 * x - 1)^2 * math.sin(phi)
    local r = X * (x * math.sin(phi)
      + y * math.cos(phi))
    if (axis == "x") then
      tex.print(r * math.sin(theta));
    elseif (axis == "y") then
      tex.print(r * math.cos(theta));
    else
      tex.print(X * (x * math.cos(phi)
        - y * math.sin(phi)));
    end
  end
\end{luacode*}
\newcommand*{\Rose}[1]{\directlua{Calculate("#1",
  \pgfmathfloatvalueof\x,\pgfmathfloatvalueof\y)}}
\begin{document}
\begin{tikzpicture}
  \begin{axis}[view={60}{30}, axis equal, hide axis,
      colormap={red}{rgb255(0cm) = (139,0,0),
                     rgb255(1cm) = (255,127,127)},
      z buffer = sort, shader = interp,
      domain = 0:1, y domain = -2*pi:15*pi,
      /tikz/background rectangle/.style = {
      left color = red!50!black, right color = red!10,
      shading angle = 135}, show background rectangle]
  \fill[left color = green!30!black, right color=green!80!black]
    (axis cs:-0.02, -0.02,-2)
    rectangle (axis cs:0.02, 0.02, -0.5);
  % For the original picture, use samples y = 800
  % Here is a lower value to not get an online compiler timeout
  \addplot3 [surf, samples = 50, samples y = 100]
    (\Rose{x},\Rose{y},\Rose{z});
  \end{axis}
\end{tikzpicture}
\end{document}

PS: I did more plots recently, that you can find on x.com/TeXgallery. I’ll upload them here soon. On X / Twitter, plotting is pretty spontanuous, uploading and explaining here requires some more time. Just follow me on X for more for now. 🙂