如何确保所有标签线都画得统一?
(灰色垂直线只是指导线;不需要画出来。)
\documentclass[border=5pt, tikz]{standalone}
\usepackage{amsmath, amssymb}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepgfplotslibrary{fillbetween}
\usetikzlibrary{calc}
% Input
\pgfmathsetmacro\r{5}
\pgfmathsetmacro\R{\r+3}
\pgfmathsetmacro\h{2}
\pgfmathsetmacro\Start{0}
\pgfmathsetmacro\End{0}
%
\pgfplotstableread{
Percent Color Text
21 red 1
27 cyan 2
6 green!80!black 3
46 brown 3
}\tabledata
\pgfplotstablegetrowsof{\tabledata}
\pgfmathsetmacro\RowNoMax{\pgfplotsretval-1}
\begin{document}
%\xdef\tempaaa{\pgfmathsetmacro\Eaand{0}}
\begin{tikzpicture}[every path/.style={thick},]
\begin{axis}[
clip=false,
axis lines=middle, axis equal, hide axis,
y dir=reverse,
samples y=0,
]
\pgfplotsinvokeforeach{0,...,\RowNoMax}{% =================
\pgfplotstablegetelem{#1}{Percent}\of{\tabledata}
\pgfmathsetmacro\Percent{\pgfplotsretval}
\pgfplotstablegetelem{#1}{Color}\of{\tabledata}
\pgfmathsetmacro\Color{"\pgfplotsretval"}
\pgfplotstablegetelem{#1}{Text}\of{\tabledata}
\pgfmathsetmacro\Text{"\pgfplotsretval"}
%
\pgfmathsetmacro\Start{\End}
\pgfmathsetmacro\End{\Start+\Percent*3.6}
\edef\temp{%%%%%%%%%%%%%%%%%%
%% Draw
\noexpand\addplot3[name path=ui, domain=\Start:\End]({\r*sin(x)}, {\r*cos(x)}, {\h}) coordinate[pos=0](uiStart) coordinate[](uiEnd) coordinate[pos=0.5](uiMid);
\noexpand\addplot3[name path=uo, domain=\Start:\End]({\R*sin(x)}, {\R*cos(x)}, {\h}) coordinate[pos=0](uoStart) coordinate[](uoEnd) coordinate[pos=0.5](uoMid);
%% Text
\noexpand\coordinate[] (Mid) at ($(uiMid)!0.5!(uoMid)$);
\noexpand\draw[fill] (Mid) circle(2pt) -- ([xshift=33mm]Mid) node[anchor=south east]{\Text} node[anchor=north east]{\Percent\%};
}\temp}% =========================
\end{axis}
\end{tikzpicture}
\end{document}
答案1
为了自动选择“标题”的左侧或右侧,最好将绘图转换为 2D 绘图,否则很难找到绘制线条的位置。以下是自动选择“正确”一侧的代码(基于相对于将两个椭圆分成两半的垂直线的位置):
\documentclass[border=5pt, tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{calc}
% Input
\pgfmathsetmacro\rA{5.0}
\pgfmathsetmacro\RA{7.0}
\pgfmathsetmacro\rB{1.5*\rA}
\pgfmathsetmacro\RB{1.5*\RA}
\pgfmathsetmacro\h{2}
\pgfmathsetmacro\Start{0}
\pgfmathsetmacro\End{0}
%
\pgfplotstableread{
Percent Color Text
21 red 1
27 cyan 2
6 green!80!black 3
46 brown 3
}\tabledata
\pgfplotstablegetrowsof{\tabledata}
\pgfmathsetmacro\RowNoMax{\pgfplotsretval-1}
\newif\ifcapleft
\begin{document}
\begin{tikzpicture}[every path/.style={thick}]
\begin{axis}[
clip=false,
axis lines=middle, axis equal, hide axis,
y dir=reverse,
samples y=0,
]
\pgfplotsinvokeforeach{0,...,\RowNoMax}{
\pgfplotstablegetelem{#1}{Percent}\of{\tabledata}
\pgfmathsetmacro\Percent{\pgfplotsretval}
\pgfplotstablegetelem{#1}{Color}\of{\tabledata}
\pgfmathsetmacro\Color{"\pgfplotsretval"}
\pgfplotstablegetelem{#1}{Text}\of{\tabledata}
\pgfmathsetmacro\Text{"\pgfplotsretval"}
\pgfmathsetmacro\Start{\End}
\pgfmathsetmacro\End{\Start+\Percent*3.6}
\pgfmathtruncatemacro\tmpLeft{
ifthenelse(Mod(0.5*(\Start+\End), 360) < 180, 0, 1)}
\ifnum\tmpLeft=1 \caplefttrue \else \capleftfalse \fi
\edef\Nanchor{\ifcapleft north west\else north east\fi}
\edef\Sanchor{\ifcapleft south west\else south east\fi}
\edef\temp{
% Draw
\noexpand\addplot[domain=\Start:\End, smooth]
({\RA*sin(x)}, {\rA*cos(x)}) coordinate[pos=0](uiStart)
coordinate[](uiEnd) coordinate[pos=0.5](uiMid);
\noexpand\addplot[domain=\Start:\End, smooth]
({\RB*sin(x)}, {\rB*cos(x)}) coordinate[pos=0](uoStart)
coordinate[](uoEnd) coordinate[pos=0.5](uoMid);
% Text
\noexpand\coordinate (Mid) at ($(uiMid)!0.5!(uoMid)$);
\noexpand\coordinate (X) at (Mid -| \ifcapleft-\fi 4cm,0);
%
\unexpanded{\begin{scope}[nodes={inner xsep=0pt, font=\footnotesize}]}
\noexpand\draw[fill] (Mid) circle[radius=2pt] -- (X)
node[anchor=\Sanchor] {\Text} node[anchor=\Nanchor] {$\Percent\,\%$};
\noexpand\end{scope}
}
\temp
}
\end{axis}
\end{tikzpicture}
\end{document}
笔记:
该
circle(2pt)
语法已过时,导致问题。 使用circle[radius=2pt]
。\pgfplotsset{compat=newest}
不会产生可重现的结果。最好\pgfplotsset{compat=1.16}
在类似这里的地方使用,因为人们可以在几年后重试代码。我添加了
smooth
椭圆图,否则可以看到连接样本点的线段。
以下是我的第一个答案,它重用了原始代码中椭圆的 3D 图 (!)。在这里,我们在表格中添加了一个新列,说明“标题”应该打印在左侧还是右侧。因此,必须为每个数据点(表格的行)手动选择一侧。
\documentclass[border=5pt, tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{calc}
% Input
\pgfmathsetmacro\r{5}
\pgfmathsetmacro\R{\r+3}
\pgfmathsetmacro\h{2}
\pgfmathsetmacro\Start{0}
\pgfmathsetmacro\End{0}
%
\pgfplotstableread{
Percent Color Text LabelPos
21 red 1 r
27 cyan 2 r
6 green!80!black 3 r
46 brown 3 l
}\tabledata
\pgfplotstablegetrowsof{\tabledata}
\pgfmathsetmacro\RowNoMax{\pgfplotsretval-1}
\newif\ifcapleft
\begin{document}
\begin{tikzpicture}[every path/.style={thick}]
\begin{axis}[
clip=false,
axis lines=middle, axis equal, hide axis,
y dir=reverse,
samples y=0,
]
\pgfplotsinvokeforeach{0,...,\RowNoMax}{
\pgfplotstablegetelem{#1}{Percent}\of{\tabledata}
\pgfmathsetmacro\Percent{\pgfplotsretval}
\pgfplotstablegetelem{#1}{Color}\of{\tabledata}
\pgfmathsetmacro\Color{"\pgfplotsretval"}
\pgfplotstablegetelem{#1}{Text}\of{\tabledata}
\pgfmathsetmacro\Text{"\pgfplotsretval"}
\pgfplotstablegetelem{#1}{LabelPos}\of{\tabledata}
\pgfmathsetmacro\LabelPos{"\pgfplotsretval"}
\pgfmathsetmacro\Start{\End}
\pgfmathsetmacro\End{\Start+\Percent*3.6}
\if\LabelPos l\caplefttrue\else\capleftfalse\fi
\edef\Nanchor{\ifcapleft north west\else north east\fi}
\edef\Sanchor{\ifcapleft south west\else south east\fi}
\edef\temp{
% Draw
\noexpand\addplot3[domain=\Start:\End, smooth]
({\r*sin(x)}, {\r*cos(x)}, {\h}) coordinate[pos=0](uiStart)
coordinate[](uiEnd) coordinate[pos=0.5](uiMid);
\noexpand\addplot3[domain=\Start:\End, smooth]
({\R*sin(x)}, {\R*cos(x)}, {\h}) coordinate[pos=0](uoStart)
coordinate[](uoEnd) coordinate[pos=0.5](uoMid);
% Text
\noexpand\coordinate (Mid) at ($(uiMid)!0.5!(uoMid)$);
\noexpand\coordinate (X) at (Mid -| \ifcapleft-\fi 4cm,0);
%
\unexpanded{\begin{scope}[nodes={inner xsep=0pt, font=\footnotesize}]}
\noexpand\draw[fill] (Mid) circle[radius=2pt] -- (X)
node[anchor=\Sanchor] {\Text} node[anchor=\Nanchor] {$\Percent\,\%$};
\noexpand\end{scope}
}
\temp
}
\end{axis}
\end{tikzpicture}
\end{document}
如果您希望保留 3D 图但仍自动放置“标题”,则可以使用以下代码。请注意,由于投影,所选的一侧乍一看并不明显:
\documentclass[border=5pt, tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{calc}
% Input
\pgfmathsetmacro\r{5}
\pgfmathsetmacro\R{\r+3}
\pgfmathsetmacro\h{2}
\pgfmathsetmacro\Start{0}
\pgfmathsetmacro\End{0}
%
\pgfplotstableread{
Percent Color Text
21 red 1
27 cyan 2
6 green!80!black 3
46 brown 3
}\tabledata
\pgfplotstablegetrowsof{\tabledata}
\pgfmathsetmacro\RowNoMax{\pgfplotsretval-1}
\newif\ifcapleft
\begin{document}
\begin{tikzpicture}[every path/.style={thick}]
\begin{axis}[
clip=false,
axis lines=middle, axis equal, hide axis,
y dir=reverse,
samples y=0,
]
\pgfplotsinvokeforeach{0,...,\RowNoMax}{
\pgfplotstablegetelem{#1}{Percent}\of{\tabledata}
\pgfmathsetmacro\Percent{\pgfplotsretval}
\pgfplotstablegetelem{#1}{Color}\of{\tabledata}
\pgfmathsetmacro\Color{"\pgfplotsretval"}
\pgfplotstablegetelem{#1}{Text}\of{\tabledata}
\pgfmathsetmacro\Text{"\pgfplotsretval"}
\pgfmathsetmacro\Start{\End}
\pgfmathsetmacro\End{\Start+\Percent*3.6}
\pgfmathtruncatemacro\tmpLeft{
ifthenelse(Mod(0.5*(\Start+\End), 360) < 180, 0, 1)}
\ifnum\tmpLeft=1 \caplefttrue \else \capleftfalse \fi
\edef\Nanchor{\ifcapleft north west\else north east\fi}
\edef\Sanchor{\ifcapleft south west\else south east\fi}
\edef\temp{
% Draw
\noexpand\addplot3[domain=\Start:\End, smooth]
({\r*sin(x)}, {\r*cos(x)}, {\h}) coordinate[pos=0](uiStart)
coordinate[](uiEnd) coordinate[pos=0.5](uiMid);
\noexpand\addplot3[domain=\Start:\End, smooth]
({\R*sin(x)}, {\R*cos(x)}, {\h}) coordinate[pos=0](uoStart)
coordinate[](uoEnd) coordinate[pos=0.5](uoMid);
% Text
\noexpand\coordinate (Mid) at ($(uiMid)!0.5!(uoMid)$);
\noexpand\coordinate (X) at (Mid -| \ifcapleft-\fi 4cm,0);
%
\unexpanded{\begin{scope}[nodes={inner xsep=0pt, inner ysep=2pt, font=\tiny}]}
\noexpand\draw[fill] (Mid) circle[radius=2pt] -- (X)
node[anchor=\Sanchor] {\Text} node[anchor=\Nanchor] {$\Percent\,\%$};
\noexpand\end{scope}
}
\temp
}
\end{axis}
\end{tikzpicture}
\end{document}