44

If we look down upon the Solar System in a geocentric model, the Sun and all the planets will be orbiting the Earth. In this model, the Earth is at the center of the universe. Let us focus on two celestial bodies other than Earth: Sun and Venus. If we assume the Earth is fixed, as the Sun orbits the Earth 8 times, Venus will do so 13 times. This will create a beautiful diagram known as the Pentagram of Venus (in reality, the ratio is 8:13.004 and the non-integer coefficient will create a wobble). Matthew Henderson posted this simplified image of the cosmic dance of Venus and Earth on his Tumblr webpage:

enter image description here

EDIT. The image above shows the dance of Venus from a heliocentric perspective, not a geocentric one as I explained. I missed it because I had several images of both heliocentric and geocentric Venus Pentagram open in my browser and I apparently copied the wrong one. Thanks to Keks Dose for mentioning that. Here is the link to an awesome video that shows the dance of Venus with Earth fixed at the center.

I was wondering if I can draw this diagram using TikZ/PGF. I have seen a similar topic on Mathematica Stack Exchange but I want to use LaTeX. I recently found the packages pst-solarsystem and tikz-planets and it would be cool to use their features if possible. I do not need the animation, any help to create the final static image would be appreciated.

  • Nice. It's such a shame you don't ask for a non-TikZ solution :( –  Dec 22 '20 at 13:58
  • 5
    Isn't this picuture highly misleading, because the earth in the center is painted yellow? The rose of vensys is a picture from a geocentric model, not a heliocentric. – Keks Dose Dec 22 '20 at 15:43
  • @KeksDose If you look at the original Tumblr post, the image indeed depicts the sun as the centre, despite what the OP describes here – gen-ℤ ready to perish Dec 22 '20 at 19:01
  • I put both views in my MP version below... – Thruston Dec 22 '20 at 19:35
  • @JairoA.delRio What other options do I have? I only know about TikZ, PGF, and Asymptote for drawing diagrams in LaTeX and I would be extremely happy to find more tools! – Amir Parvardi Dec 22 '20 at 21:22
  • @KeksDose You are absolutely right, thank you. I edited my question to provide a YouTube link that shows the dance of Venus in a geocentric model. – Amir Parvardi Dec 22 '20 at 21:23
  • 1
    Keep your eyes on the central yellow circle, and then enjoy the optical illusion when it disappears! – Gimelist Dec 23 '20 at 00:36

2 Answers2

81

Fascinating and lots of fun. This essentially one-liner:

\documentclass{article}

\usepackage[halfletter,margin=0.6in]{geometry}

\usepackage{tikz}

\begin{document}

\begin{tikzpicture} \foreach \x in {0,5,...,2880}{ \draw[help lines] (\x:5) -- ({(\x/8)*13}:4);%% <<<--- avoids arithmetic overflow } \end{tikzpicture}

\end{document}

yields this beautiful graphic:

enter image description here

Update

Well, it had to happen. Here is a macro that will do the drawing, along with the ability to play with the parameters:

\documentclass[tikz,border=20pt]{standalone}

\usepackage{keyval}

\newlength{\outerlength} \setlength{\outerlength}{4in} \newlength{\innerlength} \setlength{\innerlength}{3in} \def\outerrate{8} \def\innerrate{13} \def\maxtimes{2880} \def\increment{2}

\makeatletter \define@key{venus}{outerlength}{\setlength{\outerlength}{#1}} \define@key{venus}{innerlength}{\setlength{\innerlength}{#1}} \define@key{venus}{outerrate}{\def\outerrate{#1}} \define@key{venus}{innerrate}{\def\innerrate{#1}} \define@key{venus}{maxtimes}{\def\maxtimes{#1}} \define@key{venus}{increment}{\def\increment{#1}}

\newcommand{\makevenus}[1][]{% \setkeys{venus}{#1} \begin{tikzpicture} \foreach \x in {0,\increment,...,\maxtimes}{% \draw[help lines] (\x:\outerlength) -- ({(\x/\outerrate)*\innerrate}:\innerlength);%% <<<--- avoids arithmetic overflow }% \end{tikzpicture}% }

\begin{document}

\makevenus[innerrate=7,innerlength=2.25in,increment=3]

\end{document}

which produces:

enter image description here

while \makevenus[outerrate=5,innerrate=13,innerlength=3.75in,increment=1] produces (I love my new toy!):

enter image description here

Update 2

I was curious about what would happen if the centerpoint of each line drawn was shown. Interestingly, as the macro \newmakevenus shows, it traces the shapes formed by the intersections of the lines.

\RequirePackage[rgb]{xcolor}
\documentclass[tikz,border=20pt]{standalone}

\usepackage{xparse} \usepackage{keyval} \usepackage{fp}

\newlength{\outerlength} \setlength{\outerlength}{4in} \newlength{\innerlength} \setlength{\innerlength}{2.8933in} \def\outerrate{8} \def\innerrate{13} \def\maxtimes{2880} \def\increment{2} \colorlet{mycolor}{black}

\makeatletter \define@key{venus}{outerlength}{\setlength{\outerlength}{#1}} \define@key{venus}{innerlength}{\setlength{\innerlength}{#1}} \define@key{venus}{outerrate}{\def\outerrate{#1}} \define@key{venus}{innerrate}{\def\innerrate{#1}} \define@key{venus}{maxtimes}{\def\maxtimes{#1}} \define@key{venus}{increment}{\def\increment{#1}} \define@key{venus}{venuscolor}{\colorlet{mycolor}{#1}} \makeatother

\NewDocumentCommand{\makevenus}{sO{}}{% \setkeys{venus}{#2} \begin{tikzpicture} \foreach \x in {0,\increment,...,\maxtimes}{% \IfBooleanT{#1}{% \pgfmathsetmacro{\huenum}{\x/\maxtimes} \definecolor{mycolor}{hsb}{\huenum,0.5,1} }% \draw[help lines,mycolor] (\x:\outerlength) -- ({(\x/\outerrate)*\innerrate}:\innerlength);%% <<<--- avoids arithmetic overflow }% \end{tikzpicture}% }

\NewDocumentCommand{\newmakevenus}{sO{}}{% \setkeys{venus}{#2} \begin{tikzpicture} \foreach \x in {0,\increment,...,\maxtimes}{% \IfBooleanT{#1}{% \pgfmathsetmacro{\huenum}{\x/\maxtimes} \definecolor{mycolor}{hsb}{\huenum,0.5,1} }% \draw(\x:\outerlength) --node[circle,fill=orange,pos=.5]{} ({(\x/\outerrate)*\innerrate}:\innerlength);%% <<<--- avoids arithmetic overflow }% \end{tikzpicture}% }

\begin{document}

%%\makevenus*[outerrate=8,innerrate=13,increment=2,maxtimes=2880,innerlength=2.9in]

\newmakevenus[outerrate=8,innerrate=13,increment=3,innerlength=2.9in,maxtimes=2880]

\end{document}

enter image description here

An optional * will colorize the graphic so that \makevenus*[outerrate=8,innerrate=13,increment=2,maxtimes=2880,innerlength=2.9in] will produce:

enter image description here

2880 is simply 8*360.

A festive holiday update

Colorizing the graphic is simple: using the hsb colorspace and changing the hue of each line as it is drawn (requires \RequirePackage[rgb]{xcolor} before \documentclass command). While interesting, I wondered what would happen if the number of color cycles (red-yellow->green->blue->purple->red) were to cycle as many times as the lobes of the pattern generated -- turns out this is simply abs(\innerrate-\outerrate) -- this works best if either/both \innerrate or \outerrate are prime numbers. I was stunned by just how effective this is:

\RequirePackage[rgb]{xcolor}
\documentclass[tikz,border=20pt]{standalone}

\usepackage{xparse} \usepackage{keyval}

\newlength{\outerlength} \setlength{\outerlength}{4in} \newlength{\innerlength} \setlength{\innerlength}{2.8933in} \def\outerrate{8} \def\innerrate{13} \def\maxtimes{2880} \def\increment{2} \def\changephase{0} \colorlet{mycolor}{black}

\makeatletter \define@key{venus}{outerlength}{\setlength{\outerlength}{#1}} \define@key{venus}{innerlength}{\setlength{\innerlength}{#1}} \define@key{venus}{outerrate}{\def\outerrate{#1}} \define@key{venus}{innerrate}{\def\innerrate{#1}} \define@key{venus}{increment}{\def\increment{#1}} \define@key{venus}{changephase}{\def\changephase{#1}} \define@key{venus}{venuscolor}{\colorlet{mycolor}{#1}} \makeatother

\NewDocumentCommand{\makevenus}{sO{}}{% \setkeys{venus}{#2} \begin{tikzpicture} \pgfmathsetmacro{\nmaxtimes}{360\outerrate} \foreach \x in {0,\increment,...,\nmaxtimes}{% \IfBooleanT{#1}{% \pgfmathsetmacro{\huenum}{% abs(sin((360/\nmaxtimes)\xabs(\innerrate-\outerrate)+\changephase)) }% \definecolor{mycolor}{hsb}{\huenum,1,1} }% \draw[help lines,mycolor] (\x:\outerlength) -- ({(\x/\outerrate)\innerrate}:\innerlength);%% <<<--- avoids arithmetic overflow }% \end{tikzpicture}% }

\begin{document}

\makevenus*[outerrate=8,innerrate=17,increment=2,innerlength=3.5in,changephase=60]

\end{document}

enter image description here

It is also possible to change the phase of the color cycling using changephase so that \makevenus*[outerrate=8,innerrate=13,increment=2,innerlength=3.5in,changephase=60] produces:

enter image description here

Hope you have fun with this -- I know I did.

A Festive New Year's Fireworks Update

Most importantly, a terrific vote of thanks to @Thruston on two counts: first for the elegant one-liner that does the drawing and, second, for the wonderful MP code that translates HSL to RGB.

The following code outputs three styles of graphics: 1: a monochrome version; 2: Thruston's original version of coloring; 3: phased coloring that repeats the spectrum (inner rate - outer rate) times. Note that I am not a MP expert by any manner of means, so that, no doubt, all sorts of improvements could be made to this code.

\documentclass[border=10pt]{standalone}
\usepackage{luamplib}
\usepackage{xparse}
\usepackage{graphicx}
\mplibnumbersystem{double}

%% TO DO: use keyval.sty %% [#1 step delta]; #2 inner r; #3 outer r; %% #4 [cycle offset] %% #5 inner rate; #6 outer rate; %% #7[pen scale]; #8=color (& #9 phased color) %% #3 (outer r) is the radius of the finished graphic, assuming that it is %% greater than #2 (inner r). \NewDocumentCommand{\makevenusL}{O{1} m m O{0} m m O{.125} s s}{% \begin{mplibcode} vardef hsv_color_cyc(expr h,s,v) = % HSB->rgb following wikipedia article on "HSL and HSV" save chroma, hh, x, m; chroma = vs; %% The following cycles through color spectrum (\innerrate-\outerrate) times %% a constant can be added to shift the cycle. hh = (((#6-#5)h + #4) mod 360)/60; x = chroma * (1-abs(hh mod 2 - 1)); m = v - chroma; if hh < 1: (chroma,x,0)+(m,m,m) elseif hh < 2: (x,chroma,0)+(m,m,m) elseif hh < 3: (0,chroma,x)+(m,m,m) elseif hh < 4: (0,x,chroma)+(m,m,m) elseif hh < 5: (x,0,chroma)+(m,m,m) else: (chroma,0,x)+(m,m,m) fi enddef; vardef hsv_color(expr h,s,v) = % HSB->rgb following wikipedia article on "HSL and HSV" save chroma, hh, x, m; chroma = vs; %% The following cycles through color range once hh = h/60; x = chroma (1-abs(hh mod 2 - 1)); m = v - chroma; if hh < 1: (chroma,x,0)+(m,m,m) elseif hh < 2: (x,chroma,0)+(m,m,m) elseif hh < 3: (0,chroma,x)+(m,m,m) elseif hh < 4: (0,x,chroma)+(m,m,m) elseif hh < 5: (x,0,chroma)+(m,m,m) else: (chroma,0,x)+(m,m,m) fi enddef; \IfBooleanTF{#8} {% \IfBooleanTF{#9} {% cycle through spectrum multiple times beginfig(1); for t=0 step #1 until 360: draw #2 dir #5t -- #3 dir #6t withpen pencircle scaled #7 withcolor hsv_color_cyc(t, 1, 1); endfor; draw (288,0) .. (0,288) .. (-288,0) .. (0,-288) .. cycle; endfig; }% {% cycle through spectrum once beginfig(1); for t=0 step #1 until 360: draw #2 dir #5t -- #3 dir #6t withpen pencircle scaled #7 withcolor hsv_color(t, 1, 1); endfor; draw (288,0) .. (0,288) .. (-288,0) .. (0,-288) .. cycle; endfig; }% }% {% one color beginfig(1); for t=0 step #1 until 360: draw #2 dir #5t -- #3 dir #6t %% << change (r,g,b) spec to suit withpen pencircle scaled #7 withcolor (0.2,0.5,0.5); %% (0,0,0) for black endfor; draw (288,0) .. (0,288) .. (-288,0) .. (0,-288) .. cycle; endfig; }% \end{mplibcode} }

\begin{document}

\makevenusL[.2]{260}{288}{8}{13}[0.125] \makevenusL[.2]{260}{288}{8}{13}[0.125]* \makevenusL[.2]{260}{288}[225]{8}{13}[0.125]**

\end{document}

%%% Local Variables: %%% coding: utf-8 %%% mode: latex %%% TeX-engine: luatex %%% End:

enter image description here

sgmoye
  • 8,586
  • 5
    Spectacular...I have upvoted before. – Sebastiano Dec 22 '20 at 12:54
  • 4
    Wow, this is incredible! – fractal Dec 22 '20 at 14:35
  • very nicely done :) – cmhughes Dec 22 '20 at 14:49
  • 4
    Woohoo! This is exactly what I was looking for. I'm going to make all kinds of variations for this beautiful \makevenus macro. I was just curious why you chose 2880 for \maxtimes; is there a reason for that? – Amir Parvardi Dec 22 '20 at 21:40
  • 4
    @AmirHossein Thanks. 2880 was a rough guess for what would display the symmetries. – sgmoye Dec 22 '20 at 21:44
  • 2
    @sgmoye Makes sense. I just checked it and 2700 is enough to make the symmetry. Here is the step-by-step construction: https://docdro.id/syvxJNf – Amir Parvardi Dec 22 '20 at 22:50
  • 1
    @AmirParvardi Impressive! – sgmoye Dec 22 '20 at 23:59
  • 1
    @AmirParvardi Having thought this through, \maxtimes has to be 360*\outerrate. My bad for taking so long to realize that... – sgmoye Dec 23 '20 at 17:55
  • @sgmoye I have been messing around with your \makevenus macro to create the planetary dance of any pair of two planets. Venus and Earth are very special in the sense that their orbital period is actually very close to 13:8. I need my calculation to be more precise, so I used 200:123 instead. If I use \maxtimes=360*200 the compiler will crash, giving me a big red dimensions too large error... For Venus and Earth I can solve the problem by changing back to 13:8 but the numbers in the ratio for other planets are much larger and cause the crashing if I use \maxtimes=360*\outerrate. – Amir Parvardi Dec 23 '20 at 18:08
  • Incredible, imo, this deserves its answer in there too : https://tex.stackexchange.com/questions/1319/showcase-of-beautiful-typography-done-in-tex-friends/184885#184885 – Bromind Dec 25 '20 at 14:05
  • @Bromind Thank you for the suggestion! – sgmoye Dec 25 '20 at 14:10
  • @AmirParvardi In the last block of code (metapost), a rather extraordinary thing happens if the step (first optional argument to \makevenusL) is (outer rate)/(n*inner rate), n=1,2,3,... – sgmoye Dec 28 '20 at 13:03
  • @sgmoye the pattern indeed looks amazing. My new favourite one is Venus-Jupiter: https://docdro.id/6bbW8hq – Amir Parvardi Dec 28 '20 at 15:08
32

Here is a Metapost "one-liner" that draws the geocentric view of the orbit. Compile with lualatex:

enter image description here

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
beginfig(1);
    draw for t=0 upto 359: 108 dir 13t - 147 dir 8t .. endfor cycle;
endfig;
\end{mplibcode}
\end{document}

So what is going on here? First note that the Earth is 147 million km from the sun, and Venus is 108 million km. So I have used these distances as my radius (scaled down so that 1 pt = 1 million km). And then that Venus does 13 orbits to Earth's 8 orbits.

Now note, that in MP you can write polar coordinates as r * dir theta. So for a given angle t, Venus will be at 108 * dir 13t when Earth is at 147 * dir 8t. (And because MP allows implied multiplication between a known constant and a function we can actually write 108 dir 13t and 147 dir 8t directly.)

To get the geocentric view we want to know where Venus is from Earth, so the simplest way to get a point representing that is to subtract the pair representing the position of Earth from the pair representing the position of Venus. So at a given angle t, one way to represent the position of Venus from Earth is

108 dir 13t - 147 dir 8t

The rest of the one liner just wraps this up into an inline for loop.

for t=0 upto 359: 108 dir 13t - 147 dir 8t .. endfor cycle

using .. to connect each point to the previous, and cycle to close the path at the end. This could be saved as a path variable. Or as I have shown, you can pass it straight to draw. The path comes back on itself at t=360,

Heliocentric

And another that does the corresponding heliocentric view (where each line connects Earth to Venus...)

enter image description here

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibnumbersystem{double}
\begin{mplibcode}
beginfig(1);
    for t=0 step 1/4 until 359: draw 108 dir 13t -- 147 dir 8t withpen pencircle scaled 1/8; endfor;
endfig;
\end{mplibcode}
\end{document}

Note the need for the enhanced number system here... again compile with lualatex. This one is similar to the first, except that I have moved the draw statement inside the loop, and instead of subtracting the Earth point from the Venus point, I am drawing a line segment between them, as in the OP animation at the top.

Some HSV colours help a bit here. In particular the five cardoids appear more clearly like this:

enter image description here

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibnumbersystem{double}
\begin{mplibcode}
vardef hsv_color(expr h,s,v) =
    % following wikipedia article on "HSL and HSV"
    save chroma, hh, x, m;
    chroma = v*s;
    hh = h/60;
    x  = chroma * (1-abs(hh mod 2 - 1));
    m  = v - chroma;
    if     hh < 1: (chroma,x,0)+(m,m,m)
    elseif hh < 2: (x,chroma,0)+(m,m,m)
    elseif hh < 3: (0,chroma,x)+(m,m,m)
    elseif hh < 4: (0,x,chroma)+(m,m,m)
    elseif hh < 5: (x,0,chroma)+(m,m,m)
    else:          (chroma,0,x)+(m,m,m)
    fi
enddef;
beginfig(1);
    for t=0 step 1/4 until 360-1/4: 
        draw 108 dir 13t -- 147 dir 8t
        withpen pencircle scaled 1/8 withcolor hsv_color(t, .4, .8); endfor;
endfig;
\end{mplibcode}
\end{document}

Almost good enough for a bank note now....

Thruston
  • 42,268
  • Wow, this is very cool and convenient. Thank you! I didn't know about Metapost... I just changed Venus' relative angular position from 13t to 13.004t to make it closer to reality and it works like a charm. I will be having so much fun with MP to generate similar diagrams in the following days. – Amir Parvardi Dec 22 '20 at 21:31
  • I'm loving the coloured version of your design. Is it possible to make a macro using Metapost (similar to \makevenus command in sgmoye's answer). I tried to make one but failed miserably... – Amir Parvardi Dec 23 '20 at 20:50
  • Sure, it is, but the documentation is a bit spare. Try texdoc luamplib or look for luamplib on CTAN. When I get a few mins spare I’ll update this with an example. – Thruston Dec 23 '20 at 22:40
  • Thank you very much, I'll look it up. It would be great to see an example. – Amir Parvardi Dec 24 '20 at 00:41
  • The number of petals is the difference between the two numbers defining the harmonic: 5 = 13 - 8. – Cicada Dec 24 '20 at 07:20
  • Cycloids in general might be of interest: https://tex.stackexchange.com/questions/521684/drawing-spirograph-patterns – Cicada Dec 24 '20 at 07:54