# How to design a 3D donut pie chart with pgf-plot?

It seems that pgfplots users don't like pie charts but sometimes we can't go without (for some reasons). So I was wondering if there was a way to make what is called a donut chart.

For example one like this:

• Such an example can be found in the user manual of TikZ. May 17, 2012 at 15:24
• Never do this in 3D. Ever. Please. See section 7.6 of the PGF/TikZ manual for reasons why not. Basically it skews the data. May 17, 2012 at 15:41
• Pie charts are fine by the way. I don't use them but I'm not in a field that deals with percentages. May 17, 2012 at 15:43
• I agree with you Mark but this time it's only for a design purpose not for a technically use. I swear )) Concerning Marco's comment are you talking about this one : ftp.snt.utwente.nl/pub/software/tex/graphics/pgf/base/doc/… Because i only found a picture about it, that's all.
– Rave
May 17, 2012 at 15:54
• Have a look at How to produce a ring chart? or pgf-pie May 17, 2012 at 16:33

Like T. Tantau and Mark S. Everitt, I think it's a bad thing to do this. I don't understand if you want to use pgfplots or pgf plots ? It's not exactly the same things. The code would be better if yshift for the shadow is calculated in function of the height of the picture.

Update 2

Some corrections, complete and clean the code.

\documentclass{scrartcl}
\usepackage{tikz}

\begin{document}
path fading=circle with fuzzy edge 20 percent}}]

\begin{scope}[xscale=5,yscale=3]
\path[fading style=black,transform canvas={yshift=-40pt}] (0,0) circle (1cm);
\fill[gray](0,0) circle (0.5cm);
\path[fading style=white,transform canvas={yshift=-16mm}] (0,0) circle (0.65cm);
\draw[yshift=-3mm](0,0) circle (0.5cm);

(90:0.5cm)--++(0,-3mm) arc(90:-5:0.5cm)--++(0,3mm)  arc(-5:90:0.5cm)--cycle;
(-105:0.5cm)--++(0,-3mm) arc(-105:-225 :0.5cm)--++(0,3mm)  arc(-225:-105:0.5cm)--cycle;
(135 :0.5cm)--++(0,-3mm) arc(135:90:0.5cm)--++(0,3mm)  arc(90:135:0.5cm)--cycle;

\begin{scope}[draw=black,thin]
\fill[green!20!gray](90 :0.5cm)--(90:1cm) arc(90:-5:1cm)--(-5:0.5cm) arc(-5:90 :0.5cm);
\fill[white!20!gray](-5 :0.5cm)--(-5:1cm) arc(-5:-105 :1cm)--(-105:0.5cm) arc(-105:-5:0.5cm);
\fill[orange!20!gray](-105:0.5cm)--(-105:1cm) arc(-105:-225 :1cm)--(-225:0.5cm) arc(-225:-105:0.5cm);
\fill[blue!50!white](135:0.5cm)--(135 :1cm) arc(135:90:1cm)--(90:0.5cm) arc(90:135:0.5cm);
\end{scope}
\draw[thin,black](0,0) circle (0.5cm);

(-180:1cm) --++(0,-3mm) arc (-180:-105 :1cm) -- ++(0,3mm)  arc (-105 :-180  :1cm) -- cycle;
(-105:1cm) --++(0,-3mm) arc (-105:0 :1cm) -- ++(0,3mm)  arc (0 :-105  :1cm) -- cycle;

\draw[very thin] (90:0.5cm) -- (90:1cm)
(-5:0.5cm) -- (-5:1cm)
(-105:0.5cm) -- (-105:1cm)
(135:0.5cm) -- (135 :1cm)
(0,0) circle (1cm)
(90:0.5cm)  arc (90 :135:0.5cm);

\coordinate (left border) at (1.5cm,0cm);
\coordinate (right border) at (-1.5cm,0cm);
\coordinate (l1) at (43.5:0.75 cm);
\coordinate (l2) at (-55:0.75 cm);
\coordinate (l3) at (117.5:0.75 cm);
\coordinate (l4) at (-160:0.75 cm);

\begin{scope}[lab/.style={gray!50!black,thick,draw}]
\fill[lab] (l1) circle(.4mm) -- (l1-| left border) node[anchor=south east] {Corporate}
node[anchor=north east] {26\%};
\fill[lab] (l2) circle(.4mm) -- (l2-| left border)  node[anchor=south east] {Plastique}
node[anchor=north east] {28\%};
\fill[lab] (l3) circle(.4mm) -- (l3-| right border) node[anchor=south west] {Rhodia}
node[anchor=north west] {12.5\%};
\fill[lab] (l4) circle(.4mm) -- (l4-| right border) node[anchor=south west] {Chimique}
node[anchor=north west] {43.5\%};
\end{scope}
\end{scope}
\end{tikzpicture}
\end{document}


Attempt to automate version 4

macro \piechartthreed

Two arguments #1 for the options #2 list of angles and colors (a1/col1,a2/col2,etc...)

Options scale scale the pie chart, mix color used to color the sector, background color color for the background, name used to name the point at the "center" of each sector.

\documentclass{scrartcl}
\usepackage{tikz}

\pgfkeys{%
/piechartthreed/.cd,
scale/.code                =  {\def\piechartthreedscale{#1}},
mix color/.code            =  {\def\piechartthreedmixcolor{#1}},
background color/.code     =  {\def\piechartthreedbackcolor{#1}},
name/.code                 =  {\def\piechartthreedname{#1}}}

\newcommand\piechartthreed[2][]{%
\pgfkeys{/piechartthreed/.cd,
scale            = 1,
mix color        = gray,
background color = white,
name             = pc}
\pgfqkeys{/piechartthreed}{#1}
\begin{scope}[scale=\piechartthreedscale]
\begin{scope}[xscale=5,yscale=3]
\path[preaction={fill=black,opacity=.8,
path fading=circle with fuzzy edge 20 percent,
transform canvas={yshift=-15mm*\piechartthreedscale}}] (0,0) circle (1cm);
\fill[gray](0,0) circle (0.5cm);
\path[preaction={fill=\piechartthreedbackcolor,opacity=.8,
path fading=circle with fuzzy edge 20 percent,
transform canvas={yshift=-10mm*\piechartthreedscale}}] (0,0) circle (0.5cm);
\pgfmathsetmacro\totan{0}
\global\let\totan\totan
\pgfmathsetmacro\bottoman{180} \global\let\bottoman\bottoman
\pgfmathsetmacro\toptoman{0}   \global\let\toptoman\toptoman
\begin{scope}[draw=black,thin]
\foreach \an/\col [count=\xi] in {#2}{%
\def\space{ }
\coordinate (\piechartthreedname\space\xi) at (\totan+\an/2:0.75cm);
\ifdim 180pt>\totan pt
\ifdim 0pt=\toptoman pt
right color=\col!5!\piechartthreedmixcolor,
draw=black,very thin] (0:.5cm) -- ++(0,-3mm) arc (0:\totan+\an:.5cm)
-- ++(0,3mm)  arc (\totan+\an:0:.5cm);
\pgfmathsetmacro\toptoman{180}
\global\let\toptoman\toptoman
\else
right color=\col!5!\piechartthreedmixcolor,
draw=black,very thin](\totan:.5cm)-- ++(0,-3mm) arc(\totan:\totan+\an:.5cm)
-- ++(0,3mm)  arc(\totan+\an:\totan:.5cm);
\fi
\fi
\fill[\col!20!gray,draw=black] (\totan:0.5cm)--(\totan:1cm)  arc(\totan:\totan+\an:1cm)
--(\totan+\an:0.5cm) arc(\totan+\an:\totan :0.5cm);
\pgfmathsetmacro\finan{\totan+\an}
\ifdim 180pt<\finan pt
\ifdim 180pt=\bottoman pt
right color=\col!5!\piechartthreedmixcolor,
draw=black,very thin] (180:1cm) -- ++(0,-3mm) arc (180:\totan+\an:1cm)
-- ++(0,3mm)  arc (\totan+\an:180:1cm);
\pgfmathsetmacro\bottoman{0}
\global\let\bottoman\bottoman
\else
right color=\col!5!\piechartthreedmixcolor,
draw=black,very thin](\totan:1cm)-- ++(0,-3mm) arc(\totan:\totan+\an:1cm)
-- ++(0,3mm)  arc(\totan+\an:\totan:1cm);
\fi
\fi
\pgfmathsetmacro\totan{\totan+\an}  \global\let\totan\totan
}
\end{scope}
\draw[thin,black](0,0) circle (0.5cm);
\end{scope}
\end{scope}
}

\begin{document}
\pagecolor{orange!50}
\begin{tikzpicture}
\piechartthreed[scale=0.8,
background color=orange!50,
mix color= darkgray]
{40/green,60/blue,90/red,50/orange,120/yellow}
\foreach \i in {1,...,5} { \fill (pc \i) circle (.5mm);}
\draw[darkgray] (pc 1)  -- ++(4,0) coordinate (s1) node[anchor=south east] {Sector 1}
node[anchor=north east] {11\%};
\draw[darkgray] (pc 5)  -- (pc 5 -| s1) node[anchor=south east] {Sector 5}
node[anchor=north east] {33\%};
\draw[darkgray] (pc 2)  -- ++(1,1) coordinate (s2) -- (s2 -| s1) node[anchor=south east] {Sector 2}
node[anchor=north east] {17\%};
\draw[darkgray] (pc 3)  -- ++(-4,0) coordinate (s3) node[anchor=south west] {Sector 3}
node[anchor=north west] {14\%};
\draw[darkgray] (pc 4)  -- ++(-1,-1) coordinate (s4) --(s4 -| s3) node[anchor=south west] {Sector 4}
node[anchor=north west] {25\%};
\end{tikzpicture}

\end{document}


todo

Clean the code and add some options.

• The best looking one so far Jun 12, 2012 at 9:41
• Deserves a gold medal.
– user10274
Oct 2, 2012 at 14:35
• Is it possible to make it more shinny? Apr 18, 2013 at 21:07
• This is really awesome! Jun 11, 2014 at 20:34
• Addendum: I also wanted the colors a bit more shiny. I was able to achieve this by adding pgfkeys for mix rate low and mix rate high and replace the values 20/5 in the code with \piechartthreedmixratehigh/\piechartthreedmixratelow. Then setting the high/low mix rates to 80/60 makes nice and shiny colors. You also need to replace the remaining occurence of gray in \col!20!gray with \piechartthreedmixcolor Jun 11, 2014 at 21:02

run it with xelatex or latex->dvips->ps2pdf

\documentclass{article}
\usepackage[dvipsnames,svgnames]{pstricks}
\usepackage{pst-solides3d}

\begin{document}
\begin{pspicture}(-3.5,-1.5)(3.5,1.5)
\psset[pst-solides3d]{viewpoint=50 20 20 rtp2xyz,
Decran=20}
\psSolid[object=anneau,h=1,R=8,r=6,ngrid=90,grid=false,
fcol= 0 1  19 { (Red) } for
20 1  59 { (LimeGreen) } for
60 1 179 { (Blue) } for
180 1 299 { (Sepia) } for
300 1 359 { (BrickRed) } for
](0,0,0)
\end{pspicture}
\end{document}


or with grid lines:

\documentclass{article}
\usepackage[dvipsnames,svgnames]{pstricks}
\usepackage{pst-solides3d}

\begin{document}
\begin{pspicture}(-3.5,-1.5)(3.5,1.5)
\psset[pst-solides3d]{viewpoint=50 20 20 rtp2xyz,
Decran=20}
\psSolid[object=anneau,h=1,R=8,r=6,ngrid=90,linewidth=0.1pt,
fcol= 0 1  19 { (Red) } for
20 1  59 { (LimeGreen) } for
60 1 179 { (Blue) } for
180 1 299 { (Sepia) } for
300 1 359 { (BrickRed) } for
](0,0,0)
\end{pspicture}
\end{document}


• The most elegant code so far. Jun 12, 2012 at 12:37

Here is a first version. So far you can only define the angles of the individual sectors. In the center of each sector there is a node n(sector number) which you can use for labeling.

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}

\global\edef\lastangle{0}
\newcounter{sectornumber}

\newcommand{\ring}[1]{% angles
\setcounter{sectornumber}{1}
\foreach \x in {#1}
{   \pgfmathsetmacro{\na}{\lastangle+\x}
\fill[red,draw=black] (\lastangle:3) arc (\lastangle:\na:3) -- ++(0,0,0.5) arc (\na:\lastangle:3) -- cycle;
\fill[blue,draw=black] (\lastangle:4) arc (\lastangle:\na:4) -- ++(0,0,0.5) arc (\na:\lastangle:4) -- cycle;
\global\edef\lastangle{\na}
}
\global\edef\lastangle{0}
\foreach \x in {#1}
{   \pgfmathsetmacro{\na}{\lastangle+\x}
\fill[green,draw=black] (0,0,0.5) ++(\lastangle:3) arc (\lastangle:\na:3) -- ++(\na:1) arc (\na:\lastangle:4) -- cycle;
\node (n\thesectornumber) at ($(0,0,0.5)+(\lastangle+\x/2:3.5)$) {};
\stepcounter{sectornumber}
\global\edef\lastangle{\na}
}
}

\begin{document}

\begin{tikzpicture}[x={(0.866cm,0.5cm)},y={(-0.866cm,0.5cm)},z={(0cm,1cm)}]
\ring{10,20,30,40,50,60,70,80}
\draw[thick] (n1) -- ++(5:2) node[above right] {Bla 1};
\draw[thick] (n3) -- ++(45:2) node[above] {Bla 2};
\draw[thick] (n6) -- ++(180:2) node[left] {Bla 3};
\draw[thick] (n8) -- ++(-45:2) node[right] {Bla 4};
\end{tikzpicture}

\end{document}


Edit 1: a revised version, with choosable colors and shaded edges. It only works for quite flat rings:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}

\global\edef\lastangle{0}
\newcounter{sectornumber}

\newcommand{\ring}[4]{% angles&colors, inner, outer radius, height
\begin{scope}[x={(0.866cm,0.5cm)},y={(-0.866cm,0.5cm)},z={(0cm,1cm)}]
\global\edef\lastangle{0}
\setcounter{sectornumber}{1}
\foreach \x/\ringcolor in {#1}
{   \pgfmathsetmacro{\na}{\lastangle+\x*3.6}
\colorlet{darkercolor}{\ringcolor!60!black}
\colorlet{darkestcolor}{\ringcolor!20!black}
\shadedraw[top color=darkercolor,bottom color=darkestcolor,draw=darkercolor] (\lastangle:#2) arc (\lastangle:\na:#2) -- ++(0,0,#4) arc (\na:\lastangle:#2) -- cycle;
\shadedraw[top color=darkercolor,bottom color=darkestcolor,draw=darkercolor] (\lastangle:#3) arc (\lastangle:\na:#3) -- ++(0,0,#4) arc (\na:\lastangle:#3) -- cycle;
\global\edef\lastangle{\na}
}
\global\edef\lastangle{0}
\foreach \x/\ringcolor in {#1}
{   \pgfmathsetmacro{\na}{\lastangle+\x*3.6}
\colorlet{darkercolor}{\ringcolor!60!black}
\colorlet{darkestcolor}{\ringcolor!20!black}
\fill[\ringcolor,draw=darkercolor] (0,0,#4) ++(\lastangle:#2) arc (\lastangle:\na:#2) -- ++(\na:#3-#2) arc (\na:\lastangle:#3) -- cycle;
\pgfmathsetmacro{\nodepos}{(#3+#2)*0.5}
\node (n\thesectornumber) at ($(0,0,#4)+(\lastangle+\x*1.8:\nodepos)$) {};
\stepcounter{sectornumber}
\global\edef\lastangle{\na}
}
\end{scope}
}

\begin{document}

\begin{tikzpicture}
\ring{5/red!80!gray,15/blue!80!gray,15/yellow!80!gray,25/green!80!gray,10/orange!80!gray,10/violet!80!gray,5/brown!80!gray,15/cyan!80!gray}{3}{4}{0.5}
\foreach \x/\label in {1/Kill Bill,2/The Godfather,3/Garden State,4/Sin City,5/Fight Club,6/Star Trek VI,7/Terminator 2,8/Gran Torino}
{   \draw[thick] (n\x) -- ++(0,0.5) node[fill=white,draw,rounded rectangle,inner sep=2pt,thin,fill opacity=0.7,text opacity=1] {\tiny\label};
}
\end{tikzpicture}

\begin{tikzpicture}[x={(0.866cm,0.5cm)},y={(-0.866cm,0.5cm)},z={(0cm,1cm)}]
\ring{5/red!80!gray,15/blue!80!gray,15/yellow!80!gray,25/green!80!gray,10/orange!80!gray,10/violet!80!gray,5/brown!80!gray,15/cyan!80!gray}{2}{4}{2}
\foreach \x/\label in {1/Kill Bill,2/The Godfather,3/Garden State,4/Sin City,5/Fight Club,6/Star Trek VI,7/Terminator 2,8/Gran Torino}
{   \draw[thick] (n\x) -- ++(0.5,0.5) node[fill=white,draw,rounded rectangle,inner sep=2pt,thin,fill opacity=0.7,text opacity=1] {\tiny\label};
}
\end{tikzpicture}

\end{document}