[Tex/LaTex] Pie chart with color palette, info inside and legend

tikz-pgf

I am trying to build the following pie chart with latex and the code below, however it seems quite difficult to match the legend, colors palette and external circle grouping colors.

enter image description here

\documentclass[tikz,border=10pt]{standalone}
\begin{document}
\def\angle{0}
\def\radius{3}
\def\cyclelist{{"orange","blue","red","green"}}
\newcount\cyclecount \cyclecount=-1
\newcount\ind \ind=-1
\begin{tikzpicture}[nodes = {font=\sffamily}]
 \foreach \percent/\name in {
  0.01/1\% Cash,
  4.26/ 5\% Miton Multi-Cap Income,
  6.86/6\% Schroder Income Maximiser,
  3.82/6\% Trojan Income,
  3.32/7\% CF Woodford Equity Income,
  2.91/7\% Artemis Global Income,
  2.87/4\% First State Global Listed Infraestructure
  2.63/4\% Lazard Global Listed Infraestructure
  3.50/4\% Legg Mason RARE Global Income
  2.55/6\% Newton Global Income
  4.6/5\% Henderson Strategic Bond
  5.01/4\% Invesco Perpetual Monthly Income Plus
  4.4/5\% Jupiter Strategic Bond
  0/4\% L&G All Stocks Index Linked Gilt Index
  2.3/5\% L&G Short Dated Sterling Corporate Bond Index
  5.95/4\% Royal London Short Duration Global High Yield Bond
  3.55/4\% Twenty Four Corporate Bond
  5.03/4\% Twenty Four Dynamic Bond
  4.8/5\% F&C Property Growth & Income
  4.44/5\% Aviva Multi Strategy Target Income
  3.45/5\% Invesco Perpetual Global Targeted Income
} {
  \ifx\percent\empty\else               % If \percent is empty, do nothing
    \global\advance\cyclecount by 1     % Advance cyclecount
    \global\advance\ind by 1            % Advance list index
    \ifnum3<\cyclecount                 % If cyclecount is larger than list
      \global\cyclecount=0              %   reset cyclecount and
      \global\ind=0                     %   reset list index
    \fi
    \pgfmathparse{\cyclelist[\the\ind]} % Get color from cycle list
    \edef\color{\pgfmathresult}         %   and store as \color
    % Draw angle and set labels
    \draw[fill={\color!50},draw={\color}] (0,0) -- (\angle:\radius)
      arc (\angle:\angle+\percent*3.6:\radius) -- cycle;
    \node at (\angle+0.5*\percent*3.6:0.7*\radius) {\percent\,\%};
    \node[pin=\angle+0.5*\percent*3.6:\name]
      at (\angle+0.5*\percent*3.6:\radius) {};
    \pgfmathparse{\angle+\percent*3.6}  % Advance angle
    \xdef\angle{\pgfmathresult}         %   and store in \angle
  \fi
};
\end{tikzpicture}
\end{document}

I found particularly complex to replicate it with latex, so any help will be welcome. Thanks for your support!

Best Answer

It's a start:

enter image description here

I added a few counters to the \foreach to replace your \global\advance.. structure. The legend entries are added on a chain, that places them automatically. The number of entries in one arc and the start and stop angle of the arc can be adjusted with \maxLeg and \legBound respectively.

The placing of the nodes inside the wedges is harder and I haven't found a solution for that. Maybe I will ook into it later. (For other users: feel free to use my code as a starting point for a better answer.)

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

\usetikzlibrary{chains}

\begin{document}
\def\cyclelist{{"orange","blue","red","green"}}
\pgfmathsetmacro\startAngle{+90}
\pgfmathsetmacro\radius{+5}
\pgfmathsetmacro\maxLeg{+10}
\pgfmathsetmacro\legBound{60}
\pgfmathsetmacro\legSpacing{2*\legBound/\maxLeg}
\begin{tikzpicture}[
    nodes = {font=\sffamily},
    start chain=legend placed {at={(%
        {1.1*\radius*cos(mod(\tikzchaincount-1,\maxLeg)*\legSpacing-\legBound)+(\tikzchaincount-1 >= \maxLeg)*5*floor((\tikzchaincount-1)/\maxLeg)},%
        {1.1*\radius*sin(mod(\tikzchaincount-1,\maxLeg)*\legSpacing-\legBound)}%
    )}}
]
\foreach \percent/\percenttwo/\name [count=\i from 0, evaluate=\i as \ind using {mod(\i,4)},count=\j] in {
    1/1/Cash,
    5/5/Miton Multi-Cap Income,
    6/6/Schroder Income Maximiser,
    6/6/Trojan Income,
    7/7/CF Woodford Equity Income,
    7/7/Artemis Global Income,
    4/4/First State Global Listed Infraestructure,
    4/4/Lazard Global Listed Infraestructure,
    4/4/Legg Mason RARE Global Income,
    6/6/Newton Global Income,
    5/5/Henderson Strategic Bond,
    4/4/Invesco Perpetual Monthly Income Plus,
    5/5/Jupiter Strategic Bond,
    4/4/L\&G All Stocks Index Linked Gilt Index,
    5/5/L\&G Short Dated Sterling Corporate Bond Index,
    4/4/Royal London Short Duration Global High Yield Bond,
    4/4/Twenty Four Corporate Bond,
    4/4/Twenty Four Dynamic Bond,
    5/5/F\&C Property Growth \& Income,
    5/5/Aviva Multi Strategy Target Income,
    5/5/Invesco Perpetual Global Targeted Income,
} {
    \ifx\percent\empty\else               % If \percent is empty, do nothing
        \pgfmathsetmacro\myColor{\cyclelist[\ind]} % Get color from cycle list
        \pgfmathsetmacro\endAngle{\startAngle + \percent * 3.6}
        \pgfmathsetmacro\midAngle{(\startAngle+\endAngle)/2}
        % Draw angle and set labels
        \draw[fill={\myColor!50},draw={\myColor}] (0,0) -- (\startAngle:\radius)
            arc (\startAngle:\endAngle:\radius) -- cycle;
        \node at (\midAngle:0.7*\radius) {\percent\,\%};
        \node[anchor=west,on chain,fill=\myColor!50,circle,inner sep=2pt] {\percenttwo\,\%};
        \node[at={(legend-\j.east)},anchor=west,text width=4cm,font=\sffamily\footnotesize] {\name};
        \xdef\startAngle{\endAngle}         %   and store in \angle
    \fi
};
\end{tikzpicture}
\end{document}

Edit
A small edit that uses the colors from the source image, but no clever way to determine them, simply using a predefined color-list. I also noticed that the legend was drawn the wrong way around.

enter image description here

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

\usetikzlibrary{chains}

\definecolor{wedge1}{RGB}{ 190  30  46}
\definecolor{wedge2}{RGB}{ 240  65  54}
\definecolor{wedge3}{RGB}{ 241  90  43}
\definecolor{wedge4}{RGB}{ 247 148  30}
\definecolor{wedge5}{RGB}{  43  56 144}
\definecolor{wedge6}{RGB}{  28 117 188}
\definecolor{wedge7}{RGB}{  40 170 225}
\definecolor{wedge8}{RGB}{ 119 179 225}
\definecolor{wedge9}{RGB}{ 181 212 239}
\definecolor{wedge10}{RGB}{  0 104  56}
\definecolor{wedge11}{RGB}{  0 148  69}
\definecolor{wedge12}{RGB}{ 57 181  74}
\definecolor{wedge13}{RGB}{141 199  63}
\definecolor{wedge14}{RGB}{215 244  34}
\definecolor{wedge15}{RGB}{249 237  50}
\definecolor{wedge16}{RGB}{248 241 148}
\definecolor{wedge17}{RGB}{242 245 205}
\definecolor{wedge18}{RGB}{123  82  49}
\definecolor{wedge19}{RGB}{104  73 158}
\definecolor{wedge20}{RGB}{102  45 145}
\definecolor{wedge21}{RGB}{148 149 151}

\begin{document}
\def\groupTotals{{1,4,5,8,1,2}}
\pgfmathsetmacro\startAngle{90-3.6/2}
\pgfmathsetmacro\radius{+5}
\pgfmathsetmacro\maxLeg{+12}
\pgfmathsetmacro\legBound{+60}
\pgfmathsetmacro\legSpacing{2*\legBound/(\maxLeg-1)}
\begin{tikzpicture}[
    nodes = {font=\sffamily},
    start chain=legend placed {at={(%
        {1.3*\radius*cos(-mod(\tikzchaincount-1,\maxLeg)*\legSpacing+\legBound)+(\tikzchaincount-1 >= \maxLeg)*5*floor((\tikzchaincount-1)/\maxLeg)},%
        {1.3*\radius*sin(-mod(\tikzchaincount-1,\maxLeg)*\legSpacing+\legBound)}%
    )}}
]
\foreach \yield/\percent/\name [count=\i] in {
    4.26/5/Miton Multi-Cap Income,
    6.86/6/Schroder Income Maximiser,
    3.82/6/Trojan Income,
    3.32/7/CF Woodford Equity Income,
    2.91/7/Artemis Global Income,
    2.87/4/First State Global Listed Infraestructure,
    2.63/4/Lazard Global Listed Infraestructure,
    3.50/4/Legg Mason RARE Global Income,
    2.55/6/Newton Global Income,
    4.6 /5/Henderson Strategic Bond,
    5.01/4/Invesco Perpetual Monthly Income Plus,
    4.4 /5/Jupiter Strategic Bond,
    0   /4/L\&G All Stocks Index Linked Gilt Index,
    2.3 /5/L\&G Short Dated Sterling Corporate Bond Index,
    5.95/4/Royal London Short Duration Global High Yield Bond,
    3.55/4/Twenty Four Corporate Bond,
    5.03/4/Twenty Four Dynamic Bond,
    4.8 /5/F\&C Property Growth \& Income,
    4.44/5/Aviva Multi Strategy Target Income,
    3.45/5/Invesco Perpetual Global Targeted Income,
    0.01/1/Cash,
} {
    \ifx\percent\empty\else               % If \percent is empty, do nothing
        \pgfmathsetmacro\endAngle{\startAngle - \percent * 3.6}
        \pgfmathsetmacro\midAngle{(\startAngle+\endAngle)/2}
        % Draw angle and set labels
        \fill[wedge\i] (0,0) -- (\startAngle:\radius)
            arc (\startAngle:\endAngle:\radius) -- cycle;
        \ifnum\i<21
            \node at (\midAngle:0.7*\radius) {\yield\%};
        \fi
        \node[anchor=west,on chain,fill=wedge\i,circle,inner sep=2pt] {\percent\,\%};
        \node[at={(legend-\i.east)},anchor=west,text width=4cm,font=\sffamily\footnotesize] {\name};
        \xdef\startAngle{\endAngle}         %   and store in \angle
    \fi
};
\end{tikzpicture}
\end{document}
Related Question