# How to Draw Gabriel's Horn

Consider Gabriel's Horn:

which, mathematically speaking, is the curve y=1/x over the interval [1,∞] revolved about the x-axis. It is interesting because though it contains a finite volume, its surface area is infinite.

In an effort to draw it, I imported the image into Inkscape, traced a bitmap, and exported it to a tikzpath, which I incorporated into LaTeX as follows:

\documentclass[12pt]{book}
\usepackage{tikz}

\begin{document}
\thispagestyle{empty}
\begin{tikzpicture}
\path[fill=black] (6.8, 14.1).. controls (6.7, 14.1) and (6.7, 14.3) .. (6.6,
14.4).. controls (6.5, 14.6) and (6.5, 15.2) .. (6.5, 15.1).. controls (6.5,
15.1) and (6.7, 15.1) .. (6.9, 15.1) -- (7.3, 15.1) -- (7.3, 14.9).. controls
(7.3, 14.7) and (7.2, 14.5) .. (7.0, 14.4).. controls (6.9, 14.4) and (6.8,
14.3) .. (6.8, 14.3).. controls (6.7, 14.2) and (6.7, 14.2) .. (6.8, 14.1)..
controls (6.9, 14.0) and (6.9, 14.0) .. (6.8, 14.1) -- cycle(7.2, 14.9)..
controls (7.3, 15.0) and (7.2, 15.1) .. (7.0, 15.0).. controls (6.9, 15.0) and
(6.8, 14.9) .. (6.9, 14.8).. controls (6.9, 14.8) and (7.1, 14.8) .. (7.2,
14.9) -- cycle(7.0, 14.1).. controls (7.0, 14.1) and (7.1, 14.1) .. (7.2,
14.2).. controls (7.3, 14.2) and (7.3, 14.3) .. (7.2, 14.2).. controls (7.2,
14.2) and (7.1, 14.2) .. (7.1, 14.3).. controls (7.1, 14.3) and (7.2, 14.3) ..
(7.3, 14.3).. controls (7.4, 14.3) and (7.4, 14.3) .. (7.4, 14.3).. controls
(7.4, 14.4) and (7.4, 14.4) .. (7.4, 14.4).. controls (7.5, 14.4) and (7.5,
14.4) .. (7.5, 14.4).. controls (7.5, 14.4) and (7.5, 14.4) .. (7.5, 14.4)..
controls (7.6, 14.4) and (7.6, 14.4) .. (7.5, 14.4).. controls (7.5, 14.5) and
(7.5, 14.5) .. (7.5, 14.5).. controls (7.6, 14.4) and (7.6, 14.4) .. (7.3,
14.2).. controls (7.0, 14.0) and (7.0, 14.0) .. (7.0, 14.1) -- cycle(7.6,
14.5).. controls (7.6, 14.5) and (7.6, 14.5) .. (7.7, 14.5).. controls (7.7,
14.5) and (7.7, 14.5) .. (7.7, 14.5).. controls (7.7, 14.5) and (7.7, 14.5) ..
(7.7, 14.5).. controls (7.8, 14.5) and (7.8, 14.5) .. (7.8, 14.5).. controls
(7.7, 14.6) and (7.8, 14.6) .. (7.8, 14.6).. controls (7.8, 14.5) and (7.8,
14.5) .. (7.8, 14.5).. controls (7.7, 14.4) and (7.6, 14.4) .. (7.6, 14.5) --
cycle(7.8, 14.6).. controls (7.8, 14.6) and (7.8, 14.6) .. (7.9, 14.6)..
controls (7.9, 14.6) and (8.0, 14.6) .. (7.9, 14.6).. controls (7.9, 14.6) and
(7.9, 14.6) .. (8.0, 14.6).. controls (8.0, 14.6) and (8.1, 14.6) .. (8.0,
14.6).. controls (8.0, 14.7) and (8.0, 14.7) .. (8.1, 14.7).. controls (8.2,
14.6) and (8.2, 14.6) .. (8.1, 14.7).. controls (8.1, 14.7) and (8.2, 14.7) ..
(8.2, 14.7).. controls (8.3, 14.7) and (8.2, 14.6) .. (8.1, 14.6).. controls
(8.0, 14.6) and (8.0, 14.6) .. (7.9, 14.6).. controls (7.9, 14.5) and (7.9,
14.6) .. (7.8, 14.6) -- cycle(7.3, 14.7).. controls (7.3, 14.8) and (7.3,
14.8) .. (7.3, 14.8).. controls (7.3, 14.7) and (7.3, 14.7) .. (7.3, 14.7)..
controls (7.3, 14.7) and (7.3, 14.7) .. (7.3, 14.7) -- cycle(8.3, 14.7)..
controls (8.2, 14.8) and (8.3, 14.8) .. (8.4, 14.7).. controls (8.4, 14.7) and
(8.4, 14.7) .. (8.4, 14.7).. controls (8.3, 14.7) and (8.3, 14.7) .. (8.3,
14.7) -- cycle(8.4, 14.8).. controls (8.4, 14.8) and (8.4, 14.8) .. (8.5,
14.8).. controls (8.6, 14.8) and (8.6, 14.8) .. (8.6, 14.8).. controls (8.5,
14.8) and (8.5, 14.8) .. (8.6, 14.8).. controls (8.6, 14.8) and (8.7, 14.8) ..
(8.7, 14.8).. controls (8.7, 14.8) and (8.7, 14.8) .. (8.7, 14.8).. controls
(8.5, 14.7) and (8.5, 14.7) .. (8.4, 14.8) -- cycle(8.7, 14.8).. controls
(8.7, 14.8) and (8.7, 14.9) .. (8.8, 14.8).. controls (8.9, 14.8) and (8.9,
14.8) .. (8.9, 14.8).. controls (9.0, 14.8) and (8.8, 14.8) .. (8.7, 14.8) --
cycle(9.0, 14.8).. controls (9.1, 14.9) and (9.1, 14.9) .. (9.1, 14.8)..
controls (9.1, 14.8) and (9.1, 14.8) .. (9.1, 14.8).. controls (9.0, 14.8) and
(9.0, 14.8) .. (9.0, 14.8) -- cycle(7.3, 15.0).. controls (7.3, 15.4) and
(7.3, 15.4) .. (7.0, 15.5) -- (6.7, 15.7) -- (6.7, 15.9).. controls (6.7,
16.0) and (6.7, 16.1) .. (6.7, 16.1).. controls (6.7, 16.1) and (6.6, 16.0) ..
(6.6, 15.9).. controls (6.6, 15.9) and (6.6, 15.9) .. (6.6, 15.9).. controls
(6.6, 15.9) and (6.6, 16.0) .. (6.6, 16.1).. controls (6.7, 16.2) and (6.7,
16.2) .. (6.7, 16.2).. controls (6.7, 16.1) and (6.7, 16.1) .. (6.8, 16.1)..
controls (6.8, 16.2) and (6.8, 16.2) .. (6.8, 16.1).. controls (6.7, 15.9) and
(6.7, 15.9) .. (7.0, 15.7).. controls (7.2, 15.6) and (7.3, 15.5) .. (7.3,
15.5).. controls (7.3, 15.4) and (7.3, 15.3) .. (7.3, 15.1).. controls (7.3,
14.9) and (7.3, 14.9) .. (7.3, 15.0) -- cycle(8.9, 14.9).. controls (8.9,
14.9) and (8.9, 14.9) .. (8.9, 14.9).. controls (8.9, 14.9) and (8.9, 14.9) ..
(8.9, 14.9).. controls (8.8, 14.9) and (8.8, 14.9) .. (8.9, 14.9) --
cycle(9.2, 14.9).. controls (9.3, 14.9) and (9.3, 14.9) .. (9.4, 14.9)..
controls (9.4, 14.9) and (9.4, 14.9) .. (9.3, 14.9).. controls (9.2, 14.9) and
(9.2, 14.9) .. (9.2, 14.9) -- cycle(9.1, 14.9).. controls (9.1, 14.9) and
(9.1, 14.9) .. (9.1, 14.9).. controls (9.2, 14.9) and (9.1, 14.9) .. (9.1,
14.9).. controls (9.1, 14.9) and (9.0, 14.9) .. (9.1, 14.9) -- cycle(9.5,
14.9).. controls (9.5, 14.9) and (9.6, 14.9) .. (9.6, 14.9).. controls (9.7,
14.9) and (9.6, 14.9) .. (9.6, 14.9).. controls (9.5, 14.9) and (9.5, 14.9) ..
(9.5, 14.9) -- cycle(9.3, 15.0).. controls (9.3, 15.0) and (9.3, 15.0) ..
(9.4, 15.0).. controls (9.4, 14.9) and (9.4, 14.9) .. (9.3, 14.9).. controls
(9.3, 14.9) and (9.3, 14.9) .. (9.3, 15.0) -- cycle(9.8, 15.0).. controls
(9.8, 15.0) and (9.9, 15.0) .. (10.0, 15.0).. controls (10.0, 14.9) and (10.0,
14.9) .. (9.9, 14.9).. controls (9.8, 14.9) and (9.7, 14.9) .. (9.8, 15.0) --
cycle(7.9, 15.0).. controls (7.6, 15.1) and (7.4, 15.3) .. (7.4, 15.7)..
controls (7.3, 15.8) and (7.3, 15.9) .. (7.2, 16.1).. controls (7.1, 16.2) and
(7.0, 16.3) .. (7.0, 16.3).. controls (7.0, 16.3) and (7.0, 16.3) .. (7.1,
16.2).. controls (7.1, 16.2) and (7.1, 16.2) .. (7.1, 16.2).. controls (7.1,
16.2) and (7.2, 16.1) .. (7.3, 16.1).. controls (7.9, 15.6) and (9.3, 15.3) ..
(11.4, 15.2).. controls (11.8, 15.2) and (12.2, 15.2) .. (12.3, 15.2)..
controls (12.4, 15.2) and (12.6, 15.2) .. (12.8, 15.2).. controls (12.9, 15.2)
and (13.0, 15.2) .. (13.0, 15.1).. controls (13.0, 15.1) and (12.8, 15.1) ..
(11.5, 15.0).. controls (11.1, 15.0) and (10.6, 15.0) .. (10.4, 15.0)..
controls (10.2, 15.0) and (10.1, 15.0) .. (10.1, 15.0).. controls (10.1, 15.0)
and (10.4, 15.0) .. (10.7, 15.0).. controls (11.9, 15.1) and (12.0, 15.1) ..
(11.9, 15.1).. controls (11.9, 15.2) and (11.7, 15.2) .. (11.5, 15.2)..
controls (9.7, 15.2) and (8.0, 15.5) .. (7.4, 15.9).. controls (7.4, 16.0) and
(7.3, 16.0) .. (7.3, 16.0).. controls (7.3, 16.0) and (7.4, 15.9) .. (7.5,
15.8).. controls (7.6, 15.7) and (7.6, 15.7) .. (7.6, 15.6).. controls (7.6,
15.4) and (7.9, 15.2) .. (8.1, 15.2).. controls (8.2, 15.2) and (8.3, 15.2) ..
(8.3, 15.1).. controls (8.3, 15.1) and (8.7, 15.1) .. (9.4, 15.1).. controls
(10.1, 15.1) and (10.6, 15.1) .. (10.6, 15.1).. controls (10.6, 15.1) and
(10.3, 15.0) .. (9.9, 15.0).. controls (9.8, 15.0) and (9.7, 15.0) .. (9.8,
15.0) -- (9.9, 15.1) -- (9.8, 15.1).. controls (9.7, 15.1) and (9.5, 15.1) ..
(9.2, 15.0).. controls (8.5, 15.0) and (8.0, 15.0) .. (7.9, 15.0) --
cycle(7.3, 16.0).. controls (7.3, 16.0) and (7.2, 16.0) .. (7.2, 16.1) --
(7.1, 16.2) -- (7.2, 16.1).. controls (7.3, 16.0) and (7.3, 16.0) .. (7.3,
16.0) -- cycle(9.5, 15.0).. controls (9.5, 15.0) and (9.6, 15.0) .. (9.6,
15.0).. controls (9.7, 15.0) and (9.6, 15.0) .. (9.6, 15.0).. controls (9.5,
15.0) and (9.5, 15.0) .. (9.5, 15.0) -- cycle(6.5, 15.5).. controls (6.5,
15.5) and (6.5, 15.6) .. (6.5, 15.5).. controls (6.5, 15.5) and (6.5, 15.4) ..
(6.5, 15.4).. controls (6.5, 15.4) and (6.5, 15.4) .. (6.5, 15.5) -- cycle;

\end{tikzpicture}
\end{document}


Compiling it, I get

Then, when I tried to add some color shading to get the horn to look more realistic, I got the following TikZ code which I cannot compile because the colorcodes (e.g., cb9b9b9) are not recognized by LaTeX. Moreover, I am not posting the code here because it is extremely long.

QUESTION: How may I produce a reasonable facsimile of the above Wiki image with LaTeX code? From the colorized bitmap trace from Inkscape, I thought I had it, but LaTeX does not recognize Inkscape's color codes; for example, \path[fill=c767676] (-11.7, 7.6).. controls (-11.7, 7.6) and (-11.3, 8.0) ..

• Is TikZ required? Would you accept other solutions (PSTricks or asymptote for example?) Commented Jun 28 at 3:07
• @WillieWong pstricks is fine; As for Asymptote, I have not been able to successfully run it in Latex---I tried to just a couple of days ago or so.
– DDS
Commented Jun 28 at 3:15
• @WillieWong I just edited the title, removing the reference to TIKZ,
– DDS
Commented Jun 28 at 3:23
• Hey uh... can I take this bad render? I'd love to use this for an album cover. Commented Jun 28 at 12:58

## 3 Answers

Almost same image but from a different point of view and with the sun in a different position.

Using only tikz with the library math and layers. It may take some time to execute; the time can be shorten by modifying the integers \Nx and \Nyz in the pic element horn.

The code is lengthy since it includes the definitions of the observer's position, the sun's position, and the construction of the colors of the small polygonal faces.

The code

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{math}
\usepackage{tikz-3dplot}
\begin{document}
\makeatletter
\tikzset{%
view/.style 2 args={%  observer longitude and latitude (y upwards)
%  Remark. lomg=0 means x=0
z={({-sin(#1)}, {-cos(#1)*sin(#2)})},
x={({cos(#1)}, {-sin(#1)*sin(#2)})},
y={(0, {cos(#2)})},
evaluate={%
\tox={sin(#1)*cos(#2)};
\toy={sin(#2)};
\toz={cos(#1)*cos(#2)};
},
longitude = #1,
latitude = #2
},
sun/.style n args={3}{% longitude, latitude, light contrast in [0, 1]
sun longitude = #1,
sun latitude = #2,
contrast = #3,
evaluate={%
real \sunx, \suny, \sunz, \lightC;
\sunx = sin(\sLongit)*cos(\sLatit);
\suny = sin(\sLatit);
\sunz = cos(\sLongit)*cos(\sLatit);
}
}
}
\pgfkeys{/tikz/.cd,
latitude/.store in=\aLatit,  % observer's latitude
latitude=0
}
\pgfkeys{/tikz/.cd,
longitude/.store in=\aLongit,  % observer's longitude
longitude=0  % corresponds to x=0
}
\pgfkeys{/tikz/.cd,
sun latitude/.store in=\sLatit,
sun latitude = 80
}
\pgfkeys{/tikz/.cd,
sun longitude/.store in=\sLongit,
sun longitude=90
}
\pgfkeys{/tikz/.cd,
contrast/.store in=\lightC,  % light contrast \in [0, 1]
contrast=.5
}
\tikzmath{%
function hornFaceColor(\i, \j, \N, \M) {%
% Verifies if seen when the cone has no base; the color number is
% modified by -2000.
real \ang;
\p@x = 1/\rB +(\i-.5)/\N*(1/\rT -1/\rB);
\r@ = 1/\p@x;
\t = 360*((\j-.5)/\M);
\ux = \vx*cos(\t) +\wx*sin(\t);
\uy = \vy*cos(\t) +\wy*sin(\t);
\uz = \vz*cos(\t) +\wz*sin(\t);
% modification needed when the radii are different
\ang = atan(\r@*\r@); % angle with (Oy)
\ux = \ux*cos(\ang) +\nx*sin(\ang);
\uy = \uy*cos(\ang) +\ny*sin(\ang);
\uz = \uz*cos(\ang) +\nz*sin(\ang);
\res = \ux*\tox + \uy*\toy + \uz*\toz;
\tmp = int(100*\lightC*(\ux*\sunx + \uy*\suny + \uz*\sunz));
if \res>0 then {% if seen
return \tmp;
} else {return {-2000 +\tmp};};
};
}
\makeatother
\tikzset{%
pics/horn/.style args={xB=#1, xT=#2}{%
% The interval for which the horn will be drawn (the curve y=1/x
% rotated around the (Ox) axis).
code={%
\colorlet{mainColor}{.}
\colorlet{innerColor}{-mainColor!50!gray}
\colorlet{leftRGB{1}}{white}
\colorlet{leftRGB{0}}{mainColor!50!black}
\colorlet{leftRGB{3}}{white}
\colorlet{leftRGB{2}}{innerColor!50!black}
\tikzmath{%
real \rB, \rT;
\rB = 1/#1;
\rT = 1/#2;
integer \Nx, \Nyz, \k, \j, \prevj, \i, \previ;
\Nx = 50;
\Nyz = 64;
real \tmpBT, \tmpx, \tmpy, \tmpz, \tmpcst, \cstForColor;
real \px, \nx, \ny, \nz, \vx, \vy, \vz, \wx, \wy, \wz;
\nx = 1;
\ny = 0;
\nz = 0;
\vx = 0;
\vy = 1;
\vz = 0;
\wx = 0;
\wy = 0;
\wz = 1;
%% points \P{\i,\j}
% \i for x direction and
% \j for directions in the plane (Oyz)
for \i in {0, ..., \Nx}{%
\px = #1 +\i/\Nx*(#2 -#1);
\r = 1/\px;
for \j in {0, ..., \Nyz}{%
\t = \j/\Nyz*360;
\Px{\i,\j} = \px +\r*\vx*cos(\t) +\r*\wx*sin(\t);
\Py{\i,\j} = \r*\vy*cos(\t) +\r*\wy*sin(\t);
\Pz{\i,\j} = \r*\vz*cos(\t) +\r*\wz*sin(\t);
};
};
%% faces
for \i in {1, ..., \Nx}{%
\previ = \i -1;
for \j in {1, ..., \Nyz}{%
\prevj = \j -1;
\cstForColor = hornFaceColor(\i, \j, \Nx, \Nyz);
if \cstForColor>-999 then {%
if \cstForColor>=0. then { \k = 1; } else {%
\k = 0;  % in the shade for leftRGB{}
\cstForColor = int(abs(\cstForColor));
};
{%
\filldraw[leftRGB{\k}!\cstForColor!mainColor, line width=.001pt]
(\Px{\previ,\prevj}, \Py{\previ,\prevj}, \Pz{\previ,\prevj})
-- (\Px{\previ,\j}, \Py{\previ,\j}, \Pz{\previ,\j})
-- (\Px{\i,\j}, \Py{\i,\j}, \Pz{\i,\j})
-- (\Px{\i,\prevj}, \Py{\i,\prevj}, \Pz{\i,\prevj})
-- cycle;
};
} else {%
\cstForColor = -(\cstForColor +2000);  % back to -value
if \cstForColor>=0. then {%
\k = 3;
\cstForColor = \cstForColor;
} else {%
\k = 2;  % in the shade for leftRGB{}
\cstForColor = int(abs(\cstForColor));
};
{%
\begin{pgfonlayer}{background}
\filldraw[leftRGB{\k}!\cstForColor!innerColor,
line width=.001pt]
(\Px{\previ,\prevj}, \Py{\previ,\prevj}, \Pz{\previ,\prevj})
-- (\Px{\previ,\j}, \Py{\previ,\j}, \Pz{\previ,\j})
-- (\Px{\i,\j}, \Py{\i,\j}, \Pz{\i,\j})
-- (\Px{\i,\prevj}, \Py{\i,\prevj}, \Pz{\i,\prevj})
-- cycle;
\end{pgfonlayer}
};
};
};
};
}  % end tikzmath
}
},
}

\begin{tikzpicture}[view={-30}{15}, sun={-50}{45}{.75}]
\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

\draw[->] (0, 0, 0) -- (2, 0, 0) node[shift={(.2, 0, 0)}, above] {$x$};
\draw[->] (0, 0, 0) -- (0, 2, 0) node[shift={(0, .2, 0)}] {$y$};
\draw[->] (0, 0, 0) -- (0, 0, 2) node[shift={(0, 0, .2)}, left] {$z$};

\path (0, 0) pic[black!80!red!70, scale=1.5]
{horn={xB=.95, xT=7}};
\end{tikzpicture}
\end{document}

• Can't believe somebody was insane enough to actually do this in tikz :)-.
– cfr
Commented Jun 28 at 5:06
• Many, many thanks for this answer!
– DDS
Commented Jun 28 at 7:55
• @ch thanks for the compliment! Commented Jun 28 at 14:47
• So wait, did you just implement a rudimentary ray-tracer? Wow! Commented Jun 29 at 1:28
• How may the displayed axes be removed? Thanks.
– DDS
Commented Jul 31 at 3:33

I don't know if this helps, but I was able to do it with pgfplots as follows;

\documentclass{beamer}
\beamertemplatenavigationsymbolsempty
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}
\begin{document}
\begin{frame}
\centering
\begin{tikzpicture}[scale=0.5]
\begin{axis}[
hide axis,
view={-30}{30},
scale=3,
unit vector ratio=1 1 1
]
\addplot3[
surf,
color=black,
opacity=0.2,
samples=40,
domain = 1:15,
%restrict z to domain=-4:4,
restrict x to domain=1:15,
]({x},{(1/x)*cos(deg(y))},{(1/x)*sin(deg(y))});
\end{axis}
\end{tikzpicture}
\end{frame}
\end{document}

• you could also just use the plot path with a parametric function in plain tikz too Commented Jun 28 at 18:50
• +1 Thank you for this very nice answer.
– DDS
Commented Jun 28 at 21:00

I was wondering how one could preserve the shadow effects of the source graphic.

Unfortunately I can only find the original graphic in png format.

So I turned the png graphic into an svg file using 'Vector Magic'.

This is the result:

Download-svg-File-GitHub

In LaTeX:

% arara: pdflatex: { shell: yes }

\documentclass{article}
\usepackage{svg}
\usepackage[margin=11mm]{geometry}
\begin{document}
\begin{figure}
\centering
\includesvg[scale=0.35]{GabrielsHorn}
\caption{Gabriels Horn}
\end{figure}
\end{document}