pgf 3d 饼图 - 复兴

pgf 3d 饼图 - 复兴

我一直在使用 Alain Matthes 发布的非常漂亮的 3D 饼图代码来回答这个问题很长一段时间以来。我一直在不断调整它,以使某些功能更好地发挥作用 - 例如,现在可以命名各个扇区(而不仅仅是使用它们的索引)。我最近添加的是尝试旋转整个东西,这样角度就不一定从数学 0 位置开始,而是可以任意移动。然而,我似乎无法让它工作:

\documentclass{standalone}

\usepackage{pgfplots,tikz}
\usetikzlibrary{fadings}

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

\newcommand\piechartthreed[2][]{% 
  \pgfkeys{/piechartthreed/.cd,
    scale            = 1,
    mix color        = gray,
    mix rate high    = 20,
    mix rate low     = 5,
    background color = white,
    zeroangle/.store in = \zeroan,
    zeroangle        = 0,
    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\topan{0}\global\let\topan\topan
      \begin{scope}[draw=black,thin]
        \def\piechartthreed@norm{0}
        \foreach \name/\an/\col [count=\xi] in {#2}{%
          \pgfmathparse{\piechartthreed@norm+\an}\xdef\piechartthreed@norm{\pgfmathresult}
        }
        \foreach \name/\val/\col [count=\xi] in {#2}{%
          \pgfmathparse{360/\piechartthreed@norm * \val}\let\an\pgfmathresult
          \pgfmathsetmacro\finan{\totan+\an+\zeroan}
          \pgfmathsetmacro\midan{\totan+\an/2+\zeroan}
          \pgfmathsetmacro\began{\totan+\zeroan}
          \def\space{ } 
          \coordinate (\piechartthreedname\space\name) at (\midan:0.75cm);
          \ifdim 180pt>\began pt 
          % inner border
          \shadedraw[left color=\col!\piechartthreedmixratehigh!\piechartthreedmixcolor,right color=\col!\piechartthreedmixratelow!\piechartthreedmixcolor,draw=black,very thin]
          (\began:.5cm)-- ++(0,-3mm) arc(\began:\finan:.5cm) -- ++(0,3mm)  arc(\finan:\began:.5cm);
          \fi
          \ifdim 360pt<\finan pt 
          % inner border
          \shadedraw[left color=\col!\piechartthreedmixratehigh!\piechartthreedmixcolor,right color=\col!\piechartthreedmixratelow!\piechartthreedmixcolor,draw=black,very thin]
          (\began:.5cm)-- ++(0,-3mm) arc(\began:\finan:.5cm) -- ++(0,3mm)  arc(\finan:\began:.5cm);
          \fi   
          \fill[\col!\piechartthreedmixratehigh!\piechartthreedmixcolor,draw=black] (\began:0.5cm)--(\began:1cm)  arc(\began:\finan:1cm) --(\finan:0.5cm) arc(\finan:\began :0.5cm);     
          \ifdim 180pt<\finan pt
          % outer border
          \pgfmathsetmacro\bbegan{max(\began,180)}
          \pgfmathsetmacro\bfinan{min(\finan,360)}
        \shadedraw[left color=\col!\piechartthreedmixratehigh!\piechartthreedmixcolor,right color=\col!\piechartthreedmixratelow!\piechartthreedmixcolor,draw=black,very thin]
        (\bbegan:1cm)-- ++(0,-3mm) arc(\bbegan:\bfinan:1cm) -- ++(0,3mm)  arc(\bfinan:\bbegan:1cm);
          \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}
  \begin{tikzpicture}
    \piechartthreed[scale=0.7,
      mix color=gray,
      mix rate high=80,
      mix rate low=60,
      zeroangle = 180,
    ]{%
      yy/0.228/yellow,
      zz/2.67/pink,
      cc/2.9/orange,
      tt/6.3/green,
      gg/8.56/red,
      ww/21.6/blue,
      bb/57.5/brown%
    }
    \draw[black] (pc bb)  -- (-4, 2  ) --++ (-3,0) node[anchor=south west] {$H \to b\bar{b}    $} node[anchor=north west] {$ 57.5 \pm 1.9  $};
    \draw[black] (pc ww)  -- (-4,-2  ) --++ (-3,0) node[anchor=south west] {$H \to W^+W^-      $} node[anchor=north west] {$ 21.6 \pm 0.9  $};
    \draw[black] (pc yy)  -- (-4, 0  ) --++ (-3,0) node[anchor=south west] {$H \to \gamma\gamma$} node[anchor=north west] {$0.228 \pm 0.011$};

    \draw[black] (pc gg)  -- ( 4,-2    ) --++ ( 3,0) node[anchor=south east] {$H \to gg          $} node[anchor=north east] {$ 8.56 \pm 0.86 $};
    \draw[black] (pc tt)  -- ( 4,-0.75 ) --++ ( 3,0) node[anchor=south east] {$H \to \tau^+\tau^-$} node[anchor=north east] {$ 6.30 \pm 0.36 $};
    \draw[black] (pc cc)  -- ( 4, 0.75 ) --++ ( 3,0) node[anchor=south east] {$H \to c\bar{c}   $}  node[anchor=north east] {$ 2.90 \pm 0.35 $};
    \draw[black] (pc zz)  -- ( 4, 2    ) --++ ( 3,0) node[anchor=south east] {$H \to ZZ         $}  node[anchor=north east] {$ 2.67 \pm 0.11 $};
  \end{tikzpicture}
\end{document}

稍微调整zeroangle一下参数,您会发现它在 0-90 范围内的值上运行良好,但之后会出现奇怪的图形效果,我不太明白为什么会发生这种情况。

关于如何修复此问题有什么建议吗?

奇怪的叠加效果

答案1

这是饼图代码的完全不同(并且有点不完整)的版本,它结合了层的使用以及略有不同的绘制内侧和外侧的逻辑。

它比阿兰·马特斯非常好的答案,并且与他的光泽阴影风格不太匹配,但这可以通过修改pie slice innerpie slice outerpie slice top样式来实现。

\documentclass[tikz,border=5]{standalone}
\usepackage{xxcolor}
\usetikzlibrary{calc,arrows,fadings}
\def\pieifthenelse#1#2#3{%
  \def\pienext{#3}%
  \pgfmathparse{#1}%
  \ifdim\pgfmathresult pt=1pt\relax%
    \def\pienext{#2}%
  \fi%
  \pienext}
\tikzset{%
    zero angle/.initial=0,
    start angle/.initial=0,
    end angle/.initial=0,
    pie inner x radius/.initial=2,
    pie inner y radius/.initial=1,
    pie outer x radius/.initial=4,
    pie outer y radius/.initial=2,
    inner radius/.style args={#1 and #2}{%
      pie inner x radius=#1,
      pie inner y radius=#2
    },
    outer radius/.style args={#1 and #2}{%
      pie outer x radius=#1,
      pie outer y radius=#2
    },
    pie thickness/.initial=1,
    pie slice name/.initial=slice,
    pie slice top/.style={fill=gray},
    pie slice inner/.style={fill=gray!50!black},
    pie slice outer/.style={fill=gray!75!black}
}

\pgfdeclarelayer{shadow}
\pgfdeclarelayer{inner}
\pgfdeclarelayer{outer}
\pgfsetlayers{shadow,inner,outer,main}
\newcommand\pieslice[1][]{%
\begingroup%
  \tikzset{#1}%
  \pgfmathparse{Mod(\pgfkeysvalueof{/tikz/start angle}, 360)}%
  \let\pa=\pgfmathresult%
  \pgfmathparse{Mod(\pgfkeysvalueof{/tikz/end angle}, 360)}%
  \let\pb=\pgfmathresult%
  %
  \pgfmathparse{\pb<\pa ? \pb+360 : \pb}%
  \let\pc=\pgfmathresult%
  %
  \edef\rx{\pgfkeysvalueof{/tikz/pie inner x radius}}%
  \edef\ry{\pgfkeysvalueof{/tikz/pie inner y radius}}%
  \edef\Rx{\pgfkeysvalueof{/tikz/pie outer x radius}}%
  \edef\Ry{\pgfkeysvalueof{/tikz/pie outer y radius}}%
  \edef\r{\rx\space and \ry}%
  \edef\R{\Rx\space and \Ry}%
  \edef\t{\pgfkeysvalueof{/tikz/pie thickness}}%
  \edef\name{\pgfkeysvalueof{/tikz/pie slice name}}%
  \begin{pgfonlayer}{shadow}
  \foreach \i [evaluate={\x=\i/5;}] in {0,0.1,...,1}
    \path [fill=black, opacity=0.01, shift=(270:\t), even odd rule]
      (0:\Rx+\x\space and \Ry+\x) arc (0:360:\Rx+\x\space and \Ry+\x) -- cycle
      (0:\rx-\x\space and \ry-\x) arc (0:360:\rx-\x\space and \ry-\x) -- cycle;
  \end{pgfonlayer}
  \pieifthenelse{\pa==\pb}{%
    % Only one slice!
    \begin{pgfonlayer}{inner}%
    \path [every pie slice/.try, pie slice inner/.try]
      (0:\r) arc (0:180:\r) -- ++(0,-\t) arc (180:0:\r) -- cycle;
    \end{pgfonlayer}%
    \begin{pgfonlayer}{outer}%
      \path [every pie slice/.try, pie slice outer/.try]
    (360:\R) arc (360:180:\R) -- ++(0,-\t) arc (180:360:\R) -- cycle;
    \end{pgfonlayer}%
    \path [every pie slice/.try, pie slice top/.try, even odd rule]
      (0:\R) arc (0:360:\R) -- cycle
      (0:\r) arc (0:360:\r) -- cycle;
    }{%
      % Inner
      \begin{pgfonlayer}{inner}%
      \pieifthenelse{\pa>\pb}{%
        \pieifthenelse{\pb<180}{%
          \path [every pie slice/.try, pie slice inner/.try]
            (0:\r) arc (0:\pb:\r) -- ++(0,-\t) arc (\pb:0:\r);
        }{%
          \path [every pie slice/.try, pie slice inner/.try]
            (0:\r) arc (0:180:\r) -- ++(0,-\t) arc (180:0:\r);
        }%
      }{%
        \pieifthenelse{\pa<180}{%
           \pieifthenelse{\pb<180}{%
             \path [every pie slice/.try, pie slice inner/.try]
               (\pa:\r) arc (\pa:\pb:\r) -- ++(0,-\t) arc (\pb:\pa:\r);
           }{%
             \path [every pie slice/.try, pie slice inner/.try]
               (\pa:\r) arc (\pa:180:\r) -- ++(0,-\t) arc (180:\pa:\r);
           }%
        }{%
           \path [every pie slice/.try, pie slice inner/.try]
            (\pa:\r) arc (\pa:\pb:\r) -- ++(0,-\t) arc (\pb:\pa:\r);
         }%
       }%
     \end{pgfonlayer}%
     % Outer
     \begin{pgfonlayer}{outer}%
       \pieifthenelse{\pa>\pb}{%
         \path [every pie slice/.try, pie slice outer/.try]
           (\pa:\R) arc (\pa:360:\R) -- ++(0,-\t) arc (360:\pa:\R) -- cycle;
         \pieifthenelse{\pb>180}{%
           \path [every pie slice/.try, pie slice outer/.try]
             (180:\R) arc (180:\pb:\R) -- ++(0,-\t) arc (\pb:180:\R) -- cycle;
         }{}%
       }{%
      \pieifthenelse{\pa>180}{%
        \path [every pie slice/.try, pie slice outer/.try]
          (\pa:\R) arc (\pa:\pb:\R) -- ++(0,-\t) arc (\pb:\pa:\R) -- cycle;
      }{%
        \pieifthenelse{\pb>180}{%
          \path [every pie slice/.try, pie slice outer/.try]
            (180:\R) arc (180:\pb:\R) -- ++(0,-\t) arc (\pb:180:\R) -- cycle;}{}
        }}%
      \end{pgfonlayer}%
    % Top
    \path [every pie slice/.try, pie slice top/.try] (\pa:\r) -- (\pa:\R)
      arc (\pa:\pc:\R) -- (\pb:\r) arc (\pc:\pa:\r) -- cycle;
  }%
  \path
    (\pa:\r) coordinate (\name-start-inner)
    (\pa:\R) coordinate (\name-start-outer)
    (\pa/2+\pc/2:\r) coordinate (\name-mid-inner)
    (\pa/2+\pc/2:\R) coordinate (\name-mid-outer)
    (\pb:\r) coordinate (\name-end-inner)
    (\pb:\R) coordinate (\name-end-outer);
\endgroup
}

\newcommand\pie[2][]{%
  \begingroup%
  \tikzset{#1}%
  \pgfmathparse{\pgfkeysvalueof{/tikz/zero angle}}%
  \let\zeroangle=\pgfmathresult%
  \foreach \l/\n/\c [remember=\total (initially 0),
    evaluate={\total=\total+\n;}]in {#2}{}%
    \foreach \l/\n/\c [remember=\angleoffset (initially \zeroangle),
    evaluate={\startangle=\angleoffset; \endangle=\startangle+\n/\total*360;
      \angleoffset=\angleoffset+\n/\total*360;}] in {#2}{
      \colorlet{pie slice}{\c}%
      \pieslice[%
        start angle=\startangle,
        end angle=\endangle,
        pie slice name/.expanded=\l]%
    }
  \endgroup%
}
\begin{document}
\foreach \z in {0, 10, ..., 350}{
  \begin{tikzpicture}[>=stealth, line join=round, line cap=round]
  \useasboundingbox (-2,-2) rectangle (2,4);
  \begin{colormixin}{80!white}
\pie[every pie slice/.style={
      pie slice top/.style={fill=pie slice, draw=pie slice},
      pie slice inner/.style={fill=pie slice!50!black, draw=pie slice!50!black},
      pie slice outer/.style={fill=pie slice!50!black, draw=pie slice!50!black}
    },
    inner radius=1 and 1/2,
    outer radius=2 and 1,
    pie thickness=1/2,
    zero angle=\z]
{%
  Red/1/red,
  Yellow/2/yellow,
  Pink/3/pink,
  Green/4/green,
  Orange/5/orange,
  Purple/6/purple,
  Blue/7/blue%
}
\end{colormixin}
\draw [*-, thick, draw=black!80]
  ($(Orange-mid-inner)!0.5!(Orange-mid-outer)$)
  -- ++(0,2) node [above, font=\sffamily] {Orange};
\draw [*-, thick, draw=black!80]
  ($(Blue-mid-inner)!0.5!(Blue-mid-outer)$)
   -- ++(0,2) node [above, font=\sffamily] {Blue};
\end{tikzpicture}
}
\end{document}

在此处输入图片描述

答案2

在这种情况下,问题可能可以通过分层来解决:

\documentclass{standalone}

\usepackage{pgfplots,tikz}
\usetikzlibrary{fadings}
\pgfdeclarelayer{sides}
\pgfdeclarelayer{shadow}
\pgfsetlayers{shadow,sides,main}
\pgfkeys{%
  /piechartthreed/.cd,
  scale/.code                =  {\def\piechartthreedscale{#1}},
  mix color/.code            =  {\def\piechartthreedmixcolor{#1}},
  mix rate high/.code        =  {\def\piechartthreedmixratehigh{#1}},
  mix rate low/.code         =  {\def\piechartthreedmixratelow{#1}},
  background color/.code     =  {\def\piechartthreedbackcolor{#1}},
  name/.code                 =  {\def\piechartthreedname{#1}}}

\newcommand\piechartthreed[2][]{% 
  \pgfkeys{/piechartthreed/.cd,
    scale            = 1,
    mix color        = gray,
    mix rate high    = 20,
    mix rate low     = 5,
    background color = white,
    zeroangle/.store in = \zeroan,
    zeroangle        = 0,
    name             = pc} 
  \pgfqkeys{/piechartthreed}{#1}
  \begin{scope}[scale=\piechartthreedscale] 
    \begin{scope}[xscale=5,yscale=3]
      \begin{pgfonlayer}{shadow}
      \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);
      \end{pgfonlayer}
      \pgfmathsetmacro\totan{0}\global\let\totan\totan
      \pgfmathsetmacro\bottoman{180}\global\let\bottoman\bottoman 
      \pgfmathsetmacro\topan{0}\global\let\topan\topan
      \begin{scope}[draw=black,thin]
        \def\piechartthreed@norm{0}
        \foreach \name/\an/\col [count=\xi] in {#2}{%
          \pgfmathparse{\piechartthreed@norm+\an}\xdef\piechartthreed@norm{\pgfmathresult}
        }
        \foreach \name/\val/\col [count=\xi] in {#2}{%
          \pgfmathparse{360/\piechartthreed@norm * \val}\let\an\pgfmathresult
          \pgfmathsetmacro\finan{\totan+\an+\zeroan}
          \pgfmathsetmacro\midan{\totan+\an/2+\zeroan}
          \pgfmathsetmacro\began{\totan+\zeroan}
          \def\space{ } 
          \coordinate (\piechartthreedname\space\name) at (\midan:0.75cm);
          \ifdim 180pt>\began pt
          \begin{pgfonlayer}{sides}
          % inner border
          \shadedraw[left color=\col!\piechartthreedmixratehigh!\piechartthreedmixcolor,right color=\col!\piechartthreedmixratelow!\piechartthreedmixcolor,draw=black,very thin]
          (\began:.5cm)-- ++(0,-3mm) arc(\began:\finan:.5cm) -- ++(0,3mm)  arc(\finan:\began:.5cm);
          \end{pgfonlayer}
          \fi
          \ifdim 360pt<\finan pt 
          % inner border
           \begin{pgfonlayer}{sides}
          \shadedraw[left color=\col!\piechartthreedmixratehigh!\piechartthreedmixcolor,right color=\col!\piechartthreedmixratelow!\piechartthreedmixcolor,draw=black,very thin]
          (\began:.5cm)-- ++(0,-3mm) arc(\began:\finan:.5cm) -- ++(0,3mm)  arc(\finan:\began:.5cm);
          \end{pgfonlayer}%
          \fi   
          \fill[\col!\piechartthreedmixratehigh!\piechartthreedmixcolor,draw=black] (\began:0.5cm)--(\began:1cm)  arc(\began:\finan:1cm) --(\finan:0.5cm) arc(\finan:\began :0.5cm);     
          \ifdim 180pt<\finan pt
          % outer border
          \begin{pgfonlayer}{sides}
          \pgfmathsetmacro\bbegan{max(\began,180)}
          \pgfmathsetmacro\bfinan{min(\finan,360)}
        \shadedraw[left color=\col!\piechartthreedmixratehigh!\piechartthreedmixcolor,right color=\col!\piechartthreedmixratelow!\piechartthreedmixcolor,draw=black,very thin]
        (\bbegan:1cm)-- ++(0,-3mm) arc(\bbegan:\bfinan:1cm) -- ++(0,3mm)  arc(\bfinan:\bbegan:1cm);
        \end{pgfonlayer}%
          \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}
  \begin{tikzpicture}
    \piechartthreed[scale=0.7,
      mix color=gray,
      mix rate high=80,
      mix rate low=60,
      zeroangle = 180,
    ]{%
      yy/0.228/yellow,
      zz/2.67/pink,
      cc/2.9/orange,
      tt/6.3/green,
      gg/8.56/red,
      ww/21.6/blue,
      bb/57.5/brown%
    }
  \end{tikzpicture}
\end{document}

在此处输入图片描述

相关内容