我一直在使用 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 inner
、pie slice outer
和pie 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}