pgfplots:如何确保所有标记线都均匀绘制?

pgfplots:如何确保所有标记线都均匀绘制?

实际的
在此处输入图片描述

如何确保所有标签线都画得统一?

目标
在此处输入图片描述

(灰色垂直线只是指导线;不需要画出来。)

\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}

截屏

相关内容