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. 🙂