3

I'm trying to do a nested donut-shaped chart in tikz for the percentage of different cell types used in recent studies with MEA systems. The outer layer is divided in two: Non-neuronal and neuronal studies. And my inner layer is divided in the number of studies which comprise the neuronal and non-neuronal cells. I have the following questions:

  • Is it possible to align the inner circle with the percentage of neuronal cells with the "Neuronal" part of the outer cell (and vice-versa). Maybe if there was an option to rotate the inner circle, that way it would be easy to align.
  • How can I make the lines which depart from the inner circle start from the each corresponding black dot (as done in the outer circle) ?

Lastly, if you have any other suggestion regarding aesthetics of my chart feel free to give some input ! My code (bellow) is a fork from this comment here.

Thank your for your time.

\documentclass{scrartcl}
\usepackage{tikz}
\usetikzlibrary{fadings}

% POR AS PERCENTAGENS COMO NO LATEX DA QUESTAO !

\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
            \shadedraw\[left color=\col!20!\piechartthreedmixcolor,
                       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
            \shadedraw\[left color=\col!20!\piechartthreedmixcolor,
                       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 pt5
            \shadedraw\[left color=\col!20!\piechartthreedmixcolor,
                       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
            \shadedraw\[left color=\col!20!\piechartthreedmixcolor,
                       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}
}
\newcommand{\innerchartthreed}\[1\]{
   % Calculate total
   \pgfmathsetmacro{\totalnum}{0}
   \foreach \value/\colour/\name in {#1} {
     \pgfmathparse{\value+\totalnum}
     \global\let\totalnum=\pgfmathresult
   }


  \pgfmathsetmacro{\wheelwidth}{\outerradius-\innerradius}
  \pgfmathsetmacro{\midradius}{(\outerradius+\innerradius)/2}

  \begin{scope}\[rotate=90,xscale=0.6,yscale=1\]

    \pgfmathsetmacro{\cumnum}{0}
    \foreach \[count=\n\] \value/\colour/\name in {#1} {
        \pgfmathsetmacro{\newcumnum}{\cumnum + \value/\totalnum*360}

        \pgfmathsetmacro{\midangle}{-(\cumnum+\newcumnum)/2}

        \filldraw\[draw=black,fill=\colour\] (-\cumnum:\outerradius) arc (-\cumnum:-(\newcumnum):\outerradius) --
        (-\newcumnum:\innerradius) arc (-\newcumnum:-(\cumnum):\innerradius) -- cycle;

        \fill\[transparent\] circle (\innerradius);

        \draw node \[text=white, font=\bfseries\] (inner \n) at (\midangle:{\innerradius+\wheelwidth/2}) {\name};


        \global\let\cumnum=\newcumnum
    }


  \end{scope}

  }
\begin{document} 

\begin{tikzpicture}
%\fill (1.8,-2.1) circle (.5mm);
\end{tikzpicture}

\definecolor{ao(english)}{rgb}{0.0, 0.5, 0.0}
\definecolor{azure(colorwheel)}{rgb}{0.0, 0.5, 1.0}
\definecolor{cardinal}{rgb}{0.77, 0.12, 0.23}
\definecolor{caribbeangreen}{rgb}{0.0, 0.8, 0.6}
\definecolor{carolinablue}{rgb}{0.6, 0.73, 0.89}


\begin{tikzpicture}
%\fill (0,0) circle (.5mm);
\piechartthreed\[scale=0.8,
                   background color=orange!50,
                   mix color=darkgray\]
                   {261/red,99/green}

\foreach \i in {1,...,2} { \fill (pc \i) circle (.8mm);}

\draw\[darkgray\] (pc 1)  -- ++(-2.95,0.5) coordinate (s1) node\[anchor=south east\] {\Large{\textbf{Non-neuronal}}}
                                                    node\[anchor=north east\] {\Large{72.3\%}};

\draw\[darkgray\] (pc 2)  -- (5.5,-2) coordinate(s2) node\[anchor=south west\] {\Large{\textbf{Neuronal}}} 
                                 node\[anchor=north west\] {\Large{45.5\%}}; 
%
%\draw\[darkgray\] (pc 3)  -- ++(3,-1) coordinate (s3) node\[anchor=south west\] {Sector 3}
%%                                                    node\[anchor=north west\] {14\%};
%%
%\draw\[darkgray\] (pc 4)  -- ++(3,0) coordinate (s4) node\[anchor=south west\] {Sector 4}
%%                                                   node\[anchor=north west\] {25\%};
%%
%\draw\[darkgray\] (pc 2)  -- ++(3,-2) coordinate (s2) -- (s2 -| s4) node\[anchor=south west\] {Sector 5}                                                                  node\[anchor=north west\] {17\%}; 

\def\innerradius{0.7cm}
\def\outerradius{1.75cm}
\pgfmathsetlengthmacro{\centerradius}{(\outerradius + \innerradius)/2}
\pgfmathsetlengthmacro{\donutcenter}{\innerradius/2}

% Clock-wise order, with cardiomyocyte: 

%Non-neuronal (cardinal): cardiomyocite, fibroblast, hek-293, sh-sy5y,rbl-1
%Neuronal (green): cortex, hippocampus, ventricular, drg
\innerchartthreed{95/cardinal!95/,38/cardinal!60/,38/cardinal!50/,38/cardinal!40/,19/cardinal!40/,56/green!90/,38/green!70/,19/green!50/,19/green!50/}

    \fill (inner 1) circle (.5mm);
  \draw\[darkgray\] (inner 1.center)  -- (4.2,1) node\[anchor=south west\] {Cardiomyocyte};

  \fill (inner 2) circle (.5mm);
  \draw\[darkgray\] (inner 2.center)  -- (4.5,-.5) node\[anchor=west\] {Fibroblast};

    \fill (inner 3) circle (.5mm);
    \draw\[darkgray\] (inner 3.center)  -- (3.5,-3) node\[anchor=west\] {HEK-293};

    \fill (inner 4) circle (.5mm);
    \draw\[darkgray\] (inner 4.center)  -- (2,-3.9) node\[anchor=north\] {SH-SY5Y};

    \fill (inner 4) circle (.5mm);
    \draw\[darkgray\] (inner 4.center)  -- (2,-3.9) node\[anchor=north\] {SH-SY5Y};

    \fill (inner 5) circle (.5mm);
    \draw\[darkgray\] (inner 5.center)  -- (-1,-4.2) node\[anchor=north\] {RBL-1};

    \fill (inner 6) circle (.5mm);
    \draw\[darkgray\] (inner 6.center)  -- (-3.5,-3.9) node\[anchor=north\] {Cortex};

    \fill (inner 7) circle (.5mm);
    \draw\[darkgray\] (inner 7.center)  -- (-6.5,-0.6) node\[anchor=north\] {Hippocampus};

    \fill (inner 8) circle (.5mm);
    \draw\[darkgray\] (inner 8.center)  -- (-1.85,3.2) node\[anchor=south east\] {Ventricular};

    \fill (inner 9) circle (.5mm);
    \draw\[darkgray\] (inner 9.center)  -- (0,3.2) node\[anchor=south west\] {DRG};

\end{tikzpicture}

\end{document}


%     TO-DO: 

%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][2]][2]

[Here is the what the compiled .pdf looks like with the code I provide][3]

Last edit: Here is my final image if anyone is interested:

6
  • Welcome! The codes are a bit mixed up. To draw the lines all the way to the centers, you can use \draw[darkgray] (inner 1.center) -- (4.2,1) node[anchor=south west] {Cardiomyocyte}; instead of \draw[darkgray] (inner 1) -- (4.2,1) node[anchor=south west] {Cardiomyocyte};. However, I struggle with the interpretation of "Is it possible to align the inner circle with the percentage of neuronal cells with the "Neuronal" part of the outer cell (and vice-versa). " – user194703 Apr 29 '20 at 17:25
  • Thank you for the quick answer, you've already fixed one of my requests ! To answer your question, what I mean is that, the inner circle percentages in varying red color should be aligned to the percentage of red color of the outer circle (and the same for the green ones). The outer circle represents the two categories of cells, and in the inner circle I have the subcategories. If you still did not understood I can try to post a longer explanation maybe ? Also I'm fairly new to later so I might be asking some impossible thing. Thank you. – preposteroustomato Apr 29 '20 at 17:29
  • Well, the other one I do not understand. Do you want the outer radius of the inner donut to coincide with the inner radius of the outer donut? – user194703 Apr 29 '20 at 17:34
  • In the inner circle I have various percentages sections but they belong to just 2 categories: Neuronal (green) and Non-Neuronal (red). As such I made the percentages in the inner circle corresponding to the Neuronal category to be of different green shades and the equivalent to the Non-neuron percentages. What I want is that the region of the inner circle which has the varying green sections to be aligned with the region of the outer circle which is green and equivalent for the red section. I hope I was more clear this time. Thank you – preposteroustomato Apr 29 '20 at 17:48
  • 1
    72.3% + 45.5% > 100% ?!? – Paul Gaborit Apr 29 '20 at 22:40
2

I think that you are looking for something like this:

enter image description here

To get this I hacked the \innerchartthreed macro so that it now takes a comma separated list of quadruplues: amount, colour, name, offset. The OP has the amounts adding up to 360 but, in fact, the code computes the appropriate angles as a percentage of the total the sum of these amounts so you could use your raw data to specify the amounts.

Next, I changed the \innerchartthreed macro so that it adds the names outside the circles, together with a line to bullet inside each segment. As the circles in the picture are actually ellipses, I could not see a straightforward way to automate how far out from the centre the names are placed, because the distance from the center of the diagram changes with the angle, so instead I added the offsets to move the label further out along the radial line. In addition, I added an optional argument to \innerchartthreed to set the starting angle of the inner circle, relative to the outer disc. This allows you to adjust the inner circle to match the outer circle (curiously, the adjustment should be 228 but I found that 222 looks better).

The end result is that the inner disc, complete with labels, is drawn by:

  \innerchartthreed[222]{% amount/colour/name/label offset
      95/cardinal!95/Cardiomyocyte/1.2,
      38/cardinal!60/Fibroblast/0.2,
      38/cardinal!50/HEK-293/0,
      38/cardinal!40/SH-SY5Y/0.5,
      19/cardinal!40/RBL-1/0.5,
      56/green!90/Cortex/1,
      38/green!70/Hippocampus/1.8,
      19/green!50/Ventricular/1.8,
      19/green!50/DRG/1.5
    }

After this, I then made some similar adjustments to \piechartthreed to allow the placement of the outer circle labels. Thee outer disc, with labels is not drawn by:

  % amount/color/name
  \piechartthreed[scale=0.8, background color=orange!50, mix color=darkgray]{
      228/red/Non-neuronal\\72.3\%,
      132/green/Neuronal\\45.5\%
  }

Of course, I have just hacked the code in the question and, as the OP says, most of the hard work was done by Alain Matthes in his nice answer to How to design a 3D donut pie chart with pgf-plot?.

Oh, the OP had the SH-SY5 label entered twice so I removed one. Not sure about 72.3% and 45.5% but I did not change this.

Here is the updated code:

\documentclass{scrartcl}
\usepackage{tikz}
\usetikzlibrary{fadings}

\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/\name [count=\xi] in {#2}{%
        \ifdim 180pt>\totan pt
         \ifdim 0pt=\toptoman pt
            \shadedraw[left color=\col!20!\piechartthreedmixcolor,
                       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
            \shadedraw[left color=\col!20!\piechartthreedmixcolor,
                       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 pt5
            \shadedraw[left color=\col!20!\piechartthreedmixcolor,
                       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
            \shadedraw[left color=\col!20!\piechartthreedmixcolor,
                       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
        \node (\piechartthreedname\xi) at (\totan+2*\an/3:0.75cm){$\bullet$};
        \node[align=center] (\piechartthreedname label\xi) at (\totan+2*\an/3:1.75cm) {\Large\name};
        \draw[darkgray](\piechartthreedname\xi.center)--(\piechartthreedname label\xi);
        \pgfmathsetmacro\totan{\totan+\an}  \global\let\totan\totan
       }
    \end{scope}
    \draw[thin,black](0,0) circle (0.5cm);
   \end{scope}
\end{scope}
}
\newcommand{\innerchartthreed}[2][0]{
   % Calculate total
   \pgfmathsetmacro{\totalnum}{0}
   \foreach \value/\colour/\name/\offset in {#2} {
     \pgfmathparse{\value+\totalnum}
     \global\let\totalnum=\pgfmathresult
   }

  \pgfmathsetmacro{\wheelwidth}{\outerradius-\innerradius}
  \pgfmathsetmacro{\midradius}{(\outerradius+\innerradius)/2}

  \begin{scope}[rotate=90,xscale=0.6,yscale=1]
    \pgfmathsetmacro{\cumnum}{#1}
    \foreach [count=\n] \value/\colour/\name/\offset in {#2} {
        \pgfmathsetmacro{\newcumnum}{\cumnum + \value/\totalnum*360}

        \pgfmathsetmacro{\midangle}{Mod(-(\cumnum+\newcumnum)/2, 360)}

        \filldraw[draw=black,fill=\colour] (-\cumnum:\outerradius) arc (-\cumnum:-(\newcumnum):\outerradius) --
        (-\newcumnum:\innerradius) arc (-\newcumnum:-(\cumnum):\innerradius) -- cycle;

        \draw node [text=black, font=\bfseries] (inner \n) at (\midangle:{\innerradius+\wheelwidth/2}) {$\bullet$};
        \node (inner label \n) at (\midangle:{5+\offset}) {\name};
        \draw[darkgray] (inner \n.center)  -- (inner label \n);

        \global\let\cumnum=\newcumnum
    }
    \fill[transparent] circle (\innerradius);
  \end{scope}
  }
\begin{document}

\definecolor{ao(english)}{rgb}{0.0, 0.5, 0.0}
\definecolor{azure(colorwheel)}{rgb}{0.0, 0.5, 1.0}
\definecolor{cardinal}{rgb}{0.77, 0.12, 0.23}
\definecolor{caribbeangreen}{rgb}{0.0, 0.8, 0.6}
\definecolor{carolinablue}{rgb}{0.6, 0.73, 0.89}

\def\innerradius{0.7cm}
\def\outerradius{1.75cm}
\pgfmathsetlengthmacro{\centerradius}{(\outerradius + \innerradius)/2}
\pgfmathsetlengthmacro{\donutcenter}{\innerradius/2}

\begin{tikzpicture}

  % amount/color/name
  \piechartthreed[scale=0.8, background color=orange!50, mix color=darkgray]{
      228/red/Non-neuronal\\72.3\%,
      132/green/Neuronal\\45.5\%
  }

  % Clock-wise order, with cardiomyocyte:
  % Non-neuronal (cardinal): cardiomyocite, fibroblast, hek-293, sh-sy5y,rbl-1
  % Neuronal (green): cortex, hippocampus, ventricular, drg

  % amount/colour/name/label offset
  \innerchartthreed[222]{
      95/cardinal!95/Cardiomyocyte/1.2,
      38/cardinal!60/Fibroblast/0.2,
      38/cardinal!50/HEK-293/0,
      38/cardinal!40/SH-SY5Y/0.5,
      19/cardinal!40/RBL-1/0.5,
      56/green!90/Cortex/1,
      38/green!70/Hippocampus/1.8,
      19/green!50/Ventricular/1.8,
      19/green!50/DRG/1.5
    }
\end{tikzpicture}

\end{document}
1
  • This is exactly what I had in mind, plus the detailed explanation which serves to improve my Latex knowledge. As I had commented before, I forgot to edit the percentages I had put randomly but Paul Gaborit did well in alerting me. I really appreciate the time you took to help me, thank you ! – preposteroustomato Apr 30 '20 at 9:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.