# Parabolic Moebius map on sphere using tikz

There is a discussion here about coding the elliptic Moebius map. I however am interested in how I might do the parabolic one. case [d] The arrow heads are not an issue, but how do I get the lines on the surface of the sphere? Most (all?) tutorials only focus on lines of latitude and longitude)

• parametrization :) Sep 2, 2014 at 18:15
• @cmhughes in general it is the TeX code I have problems with, not the maths. Can you elaborate just a little what you mean? Is there an easy way to plot parametrised curves on a 2 sphere and have it look similar to texample.net/tikz/examples/map-projections Sep 3, 2014 at 18:44

# How to Draw Parametrized Curves on a Sphere in TikZ

The technique shown here parametrizes azimuth and elevation in order to draw things in a spherical coordinate system. These are then converted to the cartesian XYZ coordinate system for plotting.

Using the technique shown below, the requested parabolic Moebius map can be drawn using the following command (the formula was provided by the OP):

\def\theX{0.5*(1-cos(deg(x)))} % 0 to 1 to 0
\def\theY{0.5*(sin(deg(x))} % 0 to 0.5 to 0 to -0.5 to 0
(
{sin(\i)*\theX},       % X coordinate
{2*sin(0.5*\i)*\theY}, % Y coordinate
{1-((1-cos(\i)))*\theX} % Z coordinate
);


And the result, when rendered from different angles: ## Using TikZ + PGFPlots

By combining TikZ and PGFPlots you can have a nice looking sphere and automatically hidden lines. If you are drawing on the surface of a sphere, the sign of the z-depth directly shows whether that point is in front of or behind the sphere. The z-depth is obtained by multiplying the point in question with the view direction vector of the camera. Using the coordinate filtering mechanism of PGFPlots, you can exploit this to only draw parts of a path that are not hidden behind the sphere. This is what the sytles only background and only foreground do. Note that there is a slight overlap from depth -0.05 to depth 0.05 to avoid gaps between foreground and background parts.

Additionally, you can use TikZ to draw a nice looking sphere instead of the grid sphere shown at the bottom of this post. However, this requires aligning the PGFPlots coordinate system with the TikZ coordinate system, which is not trivial for 3D plots with variable view angles.

First you have to adjust TikZ's XYZ coordinate system to show the perspective you like. Since I haven't found anything similar to PGFPlots' view option in TikZ, I have simply implemented a viewport style that sets the x, y and z keys and accepts the same arguments as view. Using this style on an axis environment aligns the PGFPlots coordinate system with the TikZ one. But it is still necessary to assign the same parameters to the view style because otherwise PGFPlots hides parts of the plot when looking from some angles.

Then you can then use \addplot3 ({x-expr}, {y-expr}, {z-expr}); to draw your parametrized plot. In the example I defined helper macros \azimuth and \elevation to separate the definition of the curve from the coordinate transformation, such that the \draw command contain only the transformation.

Using the styles for z-depth filtering, you can then choose to draw only the visible or only the hidden parts of the plot. The macro \addFGBGplot automates this process for you by first drawing the hidden parts transparently and then drawing the visible parts using opaque lines.

\documentclass[margin=5pt, tikz]{standalone}
\usepackage{pgfplots}
\usepackage{xxcolor}
\pgfplotsset{compat=1.10}

% Declare nice sphere shading: http://tex.stackexchange.com/a/54239/12440
color(0bp)=(tikz@ball!0!white);
color(7bp)=(tikz@ball!0!white);
color(15bp)=(tikz@ball!70!black);
color(20bp)=(black!70);
color(30bp)=(black!70)}
\makeatother

% Style to set TikZ camera angle, like PGFPlots view
\tikzset{viewport/.style 2 args={
x={({cos(-#1)*1cm},{sin(-#1)*sin(#2)*1cm})},
y={({-sin(-#1)*1cm},{cos(-#1)*sin(#2)*1cm})},
z={(0,{cos(#2)*1cm})}
}}

% Styles to plot only points that are before or behind the sphere.
\pgfplotsset{only foreground/.style={
restrict expr to domain={rawx*\CameraX + rawy*\CameraY + rawz*\CameraZ}{-0.05:100},
}}
\pgfplotsset{only background/.style={
restrict expr to domain={rawx*\CameraX + rawy*\CameraY + rawz*\CameraZ}{-100:0.05}
}}

% Automatically plot transparent lines in background and solid lines in foreground
}

\newcommand{\ViewAzimuth}{-30}
\newcommand{\ViewElevation}{30}

\begin{document}
\begin{tikzpicture}
% Compute camera unit vector for calculating depth
\pgfmathsetmacro{\CameraX}{sin(\ViewAzimuth)*cos(\ViewElevation)}
\pgfmathsetmacro{\CameraY}{-cos(\ViewAzimuth)*cos(\ViewElevation)}
\pgfmathsetmacro{\CameraZ}{sin(\ViewElevation)}
\path[use as bounding box] (-1,-1) rectangle (1,1); % Avoid jittering animation
% Draw a nice looking sphere
\begin{scope}
\clip (0,0) circle (1);
\begin{scope}[transform canvas={rotate=-20}]
\shade [ball color=white] (0,0.5) ellipse (1.8 and 1.5);
\end{scope}
\end{scope}
\begin{axis}[
hide axis,
view={\ViewAzimuth}{\ViewElevation},     % Set view angle
every axis plot/.style={very thin},
disabledatascaling,                      % Align PGFPlots coordinates with TikZ
anchor=origin,                           % Align PGFPlots coordinates with TikZ
viewport={\ViewAzimuth}{\ViewElevation}, % Align PGFPlots coordinates with TikZ
]
% Plot equator and two longitude lines with occlusion
\addFGBGplot[domain=0:2*pi, samples=100, samples y=1] ({cos(deg(x))}, {sin(deg(x))}, 0);
\addFGBGplot[domain=0:2*pi, samples=100, samples y=1] (0, {sin(deg(x))}, {cos(deg(x))});
\addFGBGplot[domain=0:2*pi, samples=100, samples y=1] ({sin(deg(x))}, 0, {cos(deg(x))});
% Draw heart shape with occlusion
\def\azimuth{deg(0.7*sin(x)+pi)}
\def\elevation{deg(1.1*abs(sin(0.67*x))-0.4)}
(
{sin(\azimuth)*cos(\elevation)}, % X coordinate
{cos(\azimuth)*cos(\elevation)}, % Y coordinate
{sin(\elevation)}                % Z (vertical) coordinate
);
\end{axis}
\end{tikzpicture}
\end{document}


## Using only TikZ

Using only TikZ, you can draw plots on the surface of a sphere, but there is no automatic way to hide parts which are behind the sphere. If you don't want to use PGFPlots for whatever reason, you can also plot parametrized functions with the TikZ \draw plot command. However, the lack of a coordinate filtering mechanism means that the curve is always drawn regardless of whether it is on the visible or on the hidden side of the sphere, as you can see in the animated image above. For simple shapes on a sphere you can fix this by adjusting the domain option such that only the visible parts of the curve are actually drawn, like the equator in the example code. Of course, you have to do that every time you change the viewport.

\documentclass[tikz,margin=5pt]{standalone}
\usepackage{tikz}

% Declare nice sphere shading: http://tex.stackexchange.com/a/54239/12440
color(0bp)=(tikz@ball!0!white);
color(7bp)=(tikz@ball!0!white);
color(15bp)=(tikz@ball!70!black);
color(20bp)=(black!70);
color(30bp)=(black!70)}
\makeatother

% Style to set camera angle, like PGFPlots view style
\tikzset{viewport/.style 2 args={
x={({cos(-#1)*1cm},{sin(-#1)*sin(#2)*1cm})},
y={({-sin(-#1)*1cm},{cos(-#1)*sin(#2)*1cm})},
z={(0,{cos(#2)*1cm})}
}}

% Convert from spherical to cartesian coordinates
\newcommand{\ToXYZ}{
{sin(#1)*cos(#2)}, % X coordinate
{cos(#1)*cos(#2)}, % Y coordinate
{sin(#2)}          % Z (vertical) coordinate
}

\begin{document}
\def\Rotation{-10}
\begin{tikzpicture}
% Draw shaded circle that looks like a sphere
\begin{scope}
\clip (0,0) circle (1);
\begin{scope}[transform canvas={rotate=-20}]
\shade [ball color=white] (0,0.5) ellipse (1.8 and 1.5);
\end{scope}
\end{scope}
% Draw things in actual 3D coordinates.
\begin{scope}[viewport={\Rotation}{30}, very thin]
% Draw equator (manually hidden behind sphere)
\draw[domain=90-\Rotation:270-\Rotation, variable=\azimuth, smooth] plot (\ToXYZ{\azimuth}{0});
\draw[domain=-90-\Rotation:90-\Rotation, variable=\azimuth, smooth, densely dotted] plot (\ToXYZ{\azimuth}{0});
% Draw "poles"
\draw[domain=0:360, variable=\azimuth, smooth] plot (\ToXYZ{\azimuth}{80});
\draw[domain=0:360, variable=\azimuth, smooth, densely dotted] plot (\ToXYZ{\azimuth}{-80});
% Draw two longitude lines for orientation
\foreach \azimuth in {0,90} {
\draw[domain=0:360, variable=\elevation, smooth] plot (\ToXYZ{\azimuth}{\elevation});
}
% Draw parametrized plot in spherical coordinates
\def\azimuth{deg(0.7*sin(\t)+pi)}
\def\elevation{deg(1.1*abs(sin(0.67*\t))-0.4)}
\draw[red, domain=-180:180, variable=\t, samples=101] plot (\ToXYZ{\azimuth}{\elevation});
\end{scope}
\end{tikzpicture}
\end{document}


## Using only PGFPlots

See the updated answer above. This is left here only for reference.

The pgfplots package allows you to draw parametrized 3d plots rather easily. It can also handle occlusion with z buffer=sort, but only inside a single \addplot command; later plots are simply drawn on top of earlier plots. For example, the averse side of the sphere is not drawn because there are other faces in front of it, but the equator that is added later is simply drawn on top of the sphere. \documentclass[margin=5pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.8}
\begin{document}
\begin{tikzpicture}
\begin{axis}[view={60}{30}, width=15cm, axis equal image]
% Draw sphere (example from the pgfplots manual)
surf, z buffer=sort, colormap/cool, point meta=-z,
samples=20, domain=-1:1, y domain=0:2*pi
]
(
{sqrt(1-x^2) * cos(deg(y))}, % X coordinate
{sqrt(1-x^2) * sin(deg(y))}, % Y coordinate
x                            % Z (vertical) coordinate
);

% Black twiddly line-thing that I just made up (parametrized)
\def\azimuth{(sin(deg(2*x)))}
\def\elevation{(0.5*cos(deg(x))+1)}
(
{cos(deg(\azimuth))*cos(deg(\elevation))}, % X coordinate
{sin(deg(\azimuth))*cos(deg(\elevation))}, % Y coordinate
{sin(deg(\elevation))}                     % Z (vertical) coordinate
);

% Draw equator to show missing occlusion
({cos(deg(x))}, {sin(deg(x))}, 0);
\end{axis}
\end{tikzpicture}
\end{document}

• May be using gnuplot as a backend would speed up the compilation time. Sep 5, 2014 at 23:09
• Ewwwww gnuplot. Maybe it would, but I don't like it. Sep 5, 2014 at 23:49
• I mean passing the calculations to gnuplot, which is doable with TikZ. Sep 6, 2014 at 0:09
• Ah okay. Yes, that might be possible if you have gnuplot installed. Note however, that the TikZ version is already really fast, only the PGFPlots version is obscenely slow (specifically, when drawing the black path which has only 50 samples). So the gain from using gnuplot is probably minimal and must be weighed against the overhead of starting the gnuplot processes. Sep 6, 2014 at 0:27
• Your pgfplots example suffers from a little unexpected gotcha: your two line plots are actually surface plots. The first is a matrix of 50x50, the second a matrix of 20x20 samples. Adding samples y=1 solves the issue. Sep 6, 2014 at 7:33

I am still stunned by Fritz's great answer, and even more by what one can do with pgfplots. Here is a small addendum: it is possible to automatically discriminate between visible and hidden points with TikZ "only". One "only" has to modify the plot handler a bit. (This has severe side-effects: the paths get cut to tiny pieces and one can no longer be used for intersections and so on. Of course, one could just redraw the paths with a \path command, but this will certainly not win a prize for elegance.) Anyway, here is the code.

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot}
\makeatletter

% from https://tex.stackexchange.com/a/375604/121799
%along x axis
\define@key{x sphericalkeys}{theta}{\def\mytheta{#1}}
\define@key{x sphericalkeys}{phi}{\def\myphi{#1}}
\tikzdeclarecoordinatesystem{x spherical}{%
\setkeys{x sphericalkeys}{#1}%

%along y axis
\define@key{y sphericalkeys}{theta}{\def\mytheta{#1}}
\define@key{y sphericalkeys}{phi}{\def\myphi{#1}}
\tikzdeclarecoordinatesystem{y spherical}{%
\setkeys{y sphericalkeys}{#1}%

%along z axis
\define@key{z sphericalkeys}{theta}{\def\mytheta{#1}}
\define@key{z sphericalkeys}{phi}{\def\myphi{#1}}
\tikzdeclarecoordinatesystem{z spherical}{%
\setkeys{z sphericalkeys}{#1}%
\pgfmathsetmacro{\Xtest}{sin(\tdplotmaintheta)*cos(\tdplotmainphi-90)*sin(\mytheta)*cos(\myphi)
+sin(\tdplotmaintheta)*sin(\tdplotmainphi-90)*sin(\mytheta)*sin(\myphi)
+cos(\tdplotmaintheta)*cos(\mytheta)}
% \Xtest is the projection of the coordinate on the normal vector of the visible plane
\pgfmathsetmacro{\ntest}{ifthenelse(\Xtest<0,0,1)}
\ifnum\ntest=0
\xdef\MCheatOpa{0.3}
\else
\xdef\MCheatOpa{1}
\fi
%\typeout{\mytheta,\tdplotmaintheta;\myphi,\tdplotmainphi:\ntest}

%%%%%%%%%%%%%%%%%

\tikzoption{spherical smooth}[]{\let\tikz@plot@handler=\pgfplothandlersphericalcurveto}

\pgfdeclareplothandler{\pgfplothandlersphericalcurveto}{}{%
point macro=\pgf@plot@curveto@handler@spherical@initial,
jump macro=\pgf@plot@smooth@next@spherical@moveto,
end macro=\pgf@plot@curveto@handler@spherical@finish
}

\def\pgf@plot@smooth@next@spherical@moveto{%
\pgf@plot@curveto@handler@spherical@finish%
\global\pgf@plot@startedfalse%
\global\let\pgf@plotstreampoint\pgf@plot@curveto@handler@spherical@initial%
}

\def\pgf@plot@curveto@handler@spherical@initial#1{%
\pgf@process{#1}%
\ifx\tikz@textcolor\pgfutil@empty%
\else
\pgfsetstrokecolor{\tikz@textcolor}
\fi
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@plot@first@action{\pgfqpoint{\pgf@xa}{\pgf@ya}}%
\xdef\pgf@plot@curveto@first{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%
\global\let\pgf@plot@curveto@first@support=\pgf@plot@curveto@first%
\global\let\pgf@plotstreampoint=\pgf@plot@curveto@handler@spherical@second%
}

\def\pgf@plot@curveto@handler@spherical@second#1{%
\pgf@process{#1}%
\xdef\pgf@plot@curveto@second{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
\global\let\pgf@plotstreampoint=\pgf@plot@curveto@handler@spherical@third%
\global\pgf@plot@startedtrue%
}

\def\pgf@plot@curveto@handler@spherical@third#1{%
\pgf@process{#1}%
\xdef\pgf@plot@curveto@current{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
% compute difference vector:
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\pgf@plot@curveto@first}
% compute support directions:
\pgf@xa=\pgf@plottension\pgf@xa%
\pgf@ya=\pgf@plottension\pgf@ya%
% first marshal:
\pgf@process{\pgf@plot@curveto@second}%
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\pgf@xc=\pgf@x%
\pgf@yc=\pgf@y%
\@ifundefined{MCheatOpa}{}{%
\pgf@plotstreamspecial{\pgfsetstrokeopacity{\MCheatOpa}}}
\edef\pgf@marshal{\noexpand\pgfsetstrokeopacity{\noexpand\MCheatOpa}
\noexpand\pgfpathcurveto{\noexpand\pgf@plot@curveto@first@support}%
{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgf@plot@curveto@second}
\noexpand\pgfusepathqstroke
\noexpand\pgfpathmoveto{\noexpand\pgf@plot@curveto@second}}%
{\pgf@marshal}%
%\pgfusepathqstroke%
% Prepare next:
\global\let\pgf@plot@curveto@first=\pgf@plot@curveto@second%
\global\let\pgf@plot@curveto@second=\pgf@plot@curveto@current%
\xdef\pgf@plot@curveto@first@support{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}%
}

\def\pgf@plot@curveto@handler@spherical@finish{%
\ifpgf@plot@started%
\pgfpathcurveto{\pgf@plot@curveto@first@support}{\pgf@plot@curveto@second}{\pgf@plot@curveto@second}%
\fi%
}

\makeatother
\begin{document}

\begin{tikzpicture}

\tdplotsetmaincoords{72}{100}

\begin{scope}[tdplot_main_coords]
% \draw[-latex] (0,0,0) -- (\RadiusSphere,0,0) node[below]{$x$};
% \draw[-latex] (0,0,0) -- (0,\RadiusSphere,0) node[left]{$y$};
% \draw[-latex] (0,0,0) -- (0,0,\RadiusSphere) node[left]{$z$};

\begin{scope}
\foreach \X in {0,20,...,180}
\draw[blue] plot[spherical smooth,variable=\x,domain=-180:180,samples=60]
\foreach \X in {0,20,...,180}
\draw[gray] plot[spherical smooth,variable=\x,domain=-180:180,samples=60]
\end{scope}

\begin{scope}[xshift=8cm]
\foreach \X in {0,20,...,180}
\draw[gray] plot[spherical smooth,variable=\x,domain=-180:180,samples=60]
\foreach \X in {0,20,...,180}
\draw[blue] plot[spherical smooth,variable=\x,domain=-180:180,samples=60]
\end{scope}

\begin{scope}[yshift=-8cm]
\draw[blue] plot[spherical smooth,variable=\x,domain=0:180,samples=360]
\end{scope}

\begin{scope}[xshift=8cm,yshift=-8cm]
\foreach \X in {1,...,10}
{\draw[blue] plot[spherical smooth,variable=\x,domain=0:180,samples=360]
theta= {10*\X*sin(\x)});
\draw[blue] plot[spherical smooth,variable=\x,domain=0:180,samples=360]
theta= {10*\X*sin(\x)});}
\end{scope}

\end{scope}

\end{tikzpicture}
\end{document} Ah, important. I was using essentially the same trick here and here. If anyone reading this feels that posting a very similar answer over and over is not a good idea, I will be happy to remove this post. (Perhaps also important, the spurious almost horizontal and vertical lines are not in the PDF, they come only after the conversion to PNG, and I dunno why. They seem to be related to the shade sphere directive.)

• I like this approach! How does one change the line styles (e.g. dashed, thickness)? Apr 10, 2020 at 5:26

If the idea is to simply visualize the parabolic Moebius map, you can exploit how the \tdplotsphericalsurfaceplot command in tikz-3dplot works. Here is an example:

\documentclass[tikz,border=10pt]{standalone}
\usepackage{tikz,tikz-3dplot}

\begin{document}

\tdplotsetmaincoords{135}{350}

\begin{tikzpicture}[tdplot_main_coords,fill opacity=.7,]

\tdplotsetpolarplotrange{0}{180}{0}{180}
\tdplotsphericalsurfaceplot{36}{36}{6*sin(\tdplotphi)*sin(\tdplottheta)}{black!70!red}{red}{}{}{}

\end{tikzpicture}

\end{document} Of course, this is a rather crude solution. However, if you don't need anything fancier, this is an example with minimal code. The details about the \tdplotsphericalsurfaceplot command can be found in the tikz-3dplot manual.

Based on Fritz's answer above, here is how I did it:

\documentclass[margin=5pt, tikz]{standalone}
\usepackage{pgfplots}
\usepackage{xxcolor}
\pgfplotsset{compat=1.10}

% Declare nice sphere shading: http://tex.stackexchange.com/a/54239/12440
color(0bp)=(tikz@ball!0!white);
color(7bp)=(tikz@ball!0!white);
color(15bp)=(tikz@ball!70!black);
color(20bp)=(black!70);
color(30bp)=(black!70)}
\makeatother

% Style to set TikZ camera angle, like PGFPlots view
\tikzset{viewport/.style 2 args={
x={({cos(-#1)*1cm},{sin(-#1)*sin(#2)*1cm})},
y={({-sin(-#1)*1cm},{cos(-#1)*sin(#2)*1cm})},
z={(0,{cos(#2)*1cm})}
}}

% Styles to plot only points that are before or behind the sphere.
\pgfplotsset{only foreground/.style={
restrict expr to domain={rawx*\CameraX + rawy*\CameraY + rawz*\CameraZ}{-0.05:100},
}}
\pgfplotsset{only background/.style={
restrict expr to domain={rawx*\CameraX + rawy*\CameraY + rawz*\CameraZ}{-100:0.05}
}}

% Automatically plot transparent lines in background and solid lines in foreground
}

\newcommand{\ViewAzimuth}{20}
\newcommand{\ViewElevation}{30}

\begin{document}
\begin{tikzpicture}
% Compute camera unit vector for calculating depth
\pgfmathsetmacro{\CameraX}{sin(\ViewAzimuth)*cos(\ViewElevation)}
\pgfmathsetmacro{\CameraY}{-cos(\ViewAzimuth)*cos(\ViewElevation)}
\pgfmathsetmacro{\CameraZ}{sin(\ViewElevation)}
\path[use as bounding box] (-1,-1) rectangle (1,1); % Avoid jittering animation
% Draw a nice looking sphere
\begin{scope}
\clip (0,0) circle (1);
\begin{scope}[transform canvas={rotate=-20}]
\shade [ball color=white] (0,0.5) ellipse (1.8 and 1.5);
\end{scope}
\end{scope}
\begin{axis}[
hide axis,
view={\ViewAzimuth}{\ViewElevation},     % Set view angle
every axis plot/.style={very thin},
disabledatascaling,                      % Align PGFPlots coordinates with TikZ
anchor=origin,                           % Align PGFPlots coordinates with TikZ
viewport={\ViewAzimuth}{\ViewElevation}, % Align PGFPlots coordinates with TikZ
]
\foreach \i in {10,30,...,350} {
\def\theX{0.5*(1-cos(deg(x)))} % 0 to 1 to 0
\def\theY{0.5*(sin(deg(x))} % 0 to 0.5 to 0 to -0.5 to 0
(
{sin(\i)*\theX}, % X coordinate
{2*sin(0.5*\i)*\theY}, % Y coordinate
{1-((1-cos(\i)))*\theX} %
); %
}
\end{axis}
\end{tikzpicture}
\end{document}


Updated. ^^This is the final version. Thanks @Fritz and everyone for helping :)

• Why not save it as a pdf? Nov 13, 2014 at 23:12
• png, pdf ... all good :) Nov 13, 2014 at 23:33
• No, I mean, not as a raster image. Nov 13, 2014 at 23:45
• oh. that's just due to my cluelessness Nov 13, 2014 at 23:48
• Surely you should have given the tick to Fritz since your answer is based on this -- and especially given all of the effort that he put into his great answer.
– user30471
Nov 4, 2015 at 2:25