第四版

第四版

我最近偶然发现了这一点邮政,解释了如何使用 制作极坐标直方图R。可以找到 R 包的改进版本这里。虽然看上去有些陌生,但我认为效果还是不错的。

我认为在 LaTeX 中直接生成这样的图表会很棒。不幸的是,它还pgfplots没有这样的功能,但也许这里有人知道如何实现极坐标直方图。

这是页面上提供的示例直方图。

在此处输入图片描述

答案1

第四版

对第三版进行了一些修正:组标签的自动定位、弯曲箭头的正确长度、更好的刻度结尾(您注意到了吗666?;-))、样式分解(有两种全局样式: dartstyleorig)。

以下是两个结果(使用dartstyle然后使用orig):

在此处输入图片描述

在此处输入图片描述

代码:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.text}
\usepackage{ifthen}
\tikzset{
  orig/.style={
    hist 1/.style={fill=red!70!gray},
    hist 2/.style={fill=blue!60!white},
    hist 3/.style={fill=green!50!gray},
    arrow group/.style={draw,color=black,very thick,latex-latex},
    target/.style={fill=pink!60!black,draw=black,
      line width=1pt,double distance=1pt,double=white},
    rev text on arc/.style={
      decorate,decoration={text along path,
        text={##1},text align={align=center},
        text color=black,reverse path}
    },
    text on arc/.style={
      decorate,decoration={text along path,
        text={##1},text align={align=center},
        text color=black,
      },
    },
    major tick/.style={draw=white,thick},
    minor tick/.style={draw=white,thin,draw opacity=.5},
    tick label/.style={font=\tiny\bfseries},
    text=black,
    font=\bfseries\sffamily,
  },
  dartstyle/.style={
    hist 1/.style={fill=red!80!white},
    hist 2/.style={fill=yellow!60!white},
    hist 3/.style={fill=green!70!black},
    arrow group/.style={draw=white,white,very thick,latex-latex},
    target/.style={fill=black,draw=black,
      line width=1pt,double distance=1pt,double=white},
    rev text on arc/.style={
      decorate,decoration={text along path,
        text={##1},text align={align=center},
        text color=white,reverse path}
    },
    text on arc/.style={
      decorate,decoration={text along path,
        text={##1},text align={align=center},
        text color=white}
    },
    major tick/.style={draw=white,thick},
    minor tick/.style={draw=white,thin,draw opacity=.5},
    tick label/.style={font=\tiny\bfseries},
    text=white,
    font=\bfseries\sffamily,
  },
}

\def\astep{9} % step (degree) between sectors
\def\mstep{3} % half width (degree) of each sector
\def\min{8mm} % min distance from center
\def\max{4cm} % max distance from center

\def\mydata{%
  First Group/{%
    xxx/{10,30,60},%
    aab/{20,30,50},%
    aba/{30,30,40},%
    aad/{40,30,30},%
    aca/{50,30,20},%
    zcb/{60,10,30},%
    aaa/{10,30,60},%
    aab/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60}%
  },%
  Second Group/{%
    yyy/{60,10,30},%
    zcb/{60,10,30},%
    aaa/{10,30,60},%
    aab/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60},%
    zcb/{60,10,30},%
    zcb/{75,10,15},%
    aaa/{10,30,60}%
  },%
  Third Group/{%
    zzz/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60},%
    zcb/{60,10,30},%
    zcb/{60,10,30},%
    aaa/{10,30,60},%
    aab/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60},%
    zcb/{60,30,10}% 
  }%
}

\begin{document}
\begin{tikzpicture}[orig]
  \tikzset{
    declare function={
      secttoangle(\sect)=(\sect)*\astep;
      percenttodist(\percent)=\min+(\max-\min)/100*\percent;
    },
  }

  \path[target]
  circle(\max+1.6cm);

  \def\cursectinit{-.666}
  \foreach \curgroup/\curdata in \mydata {
    \foreach \curlabel/\values [count=\cp] in \curdata {
      % angle for this current label
      \pgfmathsetmacro{\angle}{secttoangle(\cursectinit+\cp)}
      % percent
      \xdef\total{0}
      % histogram
      \foreach \val [count=\cv] in \values {
        \pgfmathsetmacro{\nexttotal}{\total+\val}
        \pgfmathsetmacro{\dmin}{percenttodist(\total)}
        \pgfmathsetmacro{\dmax}{percenttodist(\nexttotal)}
        % sector
        \path[hist \cv=\angle] (\angle+\mstep:\dmin pt)
        arc(\angle+\mstep:\angle-\mstep:\dmin pt) -- (\angle-\mstep:\dmax pt)
        arc(\angle-\mstep:\angle+\mstep:\dmax pt) -- cycle;
        % iteration
        \xdef\total{\nexttotal}
      }
      % label (with autorotation)
      \pgfmathtruncatemacro{\revlab}{and(\angle>90,\angle<270)?1:0}
      \ifthenelse{\equal{\revlab}{1}}{ 
        \node[rotate=180+\angle,anchor=east] at (\angle:\max) {\curlabel};
      }{
        \node[rotate=\angle,anchor=west] at (\angle:\max) {\curlabel};
      }
    }
    % group limits
    \pgfmathsetmacro{\newsectinit}{\cursectinit+\cp}
    \pgfmathsetmacro{\angleinit}{secttoangle(\cursectinit + 1)-\mstep}
    \pgfmathsetmacro{\anglefinal}{secttoangle(\newsectinit)+\mstep}
    % group label
    {
      \Large\bfseries\sffamily
      \pgfmathtruncatemacro{\anglem}{(\angleinit+\anglefinal)/2}
      \pgfmathtruncatemacro{\revtext}{and(\anglem>0,\anglem<180)?1:0}
      \ifthenelse{\equal{\revtext}{1}}{ 
        \draw[rev text on arc=\curgroup] (\angleinit:\max+1.1cm)
        arc(\angleinit:\anglefinal:\max+1.1cm);
      }{
        \draw[text on arc=\curgroup] (\angleinit:\max+1.1cm+.5em)
        arc(\angleinit:\anglefinal:\max+1.1cm+.5em);
      }
    }
    % group arrow
    \path[arrow group]
    (\angleinit:\max+9mm) arc(\angleinit:\anglefinal:\max+9mm);
    % iteration
    \pgfmathsetmacro{\newsectinit}{\newsectinit+1}
    \xdef\cursectinit{\newsectinit}
  }

  % level ticks
  \pgfmathsetmacro{\angleinit}{secttoangle(0)}
  \pgfmathsetmacro{\anglefinal}{secttoangle(\cursectinit-1)+\mstep}
  % major ticks with labels
  \foreach \percent in {0,50,100}{
    \pgfmathsetmacro{\dist}{percenttodist(\percent)}
    % tick
    \path[major tick] (\angleinit:\dist pt)
    arc(\angleinit:\anglefinal:\dist pt);
    % label
    \node[tick label,below,rotate=secttoangle(0)]
    at ({secttoangle(0)}:\dist pt) {\percent\%};
  }
  % minor ticks
  \foreach \percent in {10,20,30,40,60,70,80,90}{
    \pgfmathsetmacro{\dist}{percenttodist(\percent)}
    % tick
    \path[minor tick] (\angleinit:\dist pt)
    arc(\angleinit:\anglefinal:\dist pt);
  }

  % legend
  \foreach \mycat [count=\c] in {Bad,Mediocre,Good}{
    \path[hist \c=0] (2.75,-.5-.5*\c) rectangle ++(.2,.2) ++(0,-.1)
    node[right]{\mycat};
  }
\end{tikzpicture}
\end{document}

第三版

这是我的第三个版本:飞镖风格,更好的级别标记,图例......

在此处输入图片描述

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.text,shadows}
\usepackage{ifthen}
\tikzset{
  hist 1/.style={fill=red!80!white},
  hist 2/.style={fill=yellow!60!white},
  hist 3/.style={fill=green!70!black},
}

\def\astep{9} % step (degree) between sectors
\def\mstep{3} % half width (degree) of each sector
\def\min{8mm} % min distance from center
\def\max{4cm} % max distance from center

\def\mydata{%
  First Group/{%
    xxx/{10,30,60},%
    aab/{20,30,50},%
    aba/{30,30,40},%
    aad/{40,30,30},%
    aca/{50,30,20},%
    zcb/{60,10,30},%
    aaa/{10,30,60},%
    aab/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60}%
  },%
  Second Group/{%
    yyy/{60,10,30},%
    zcb/{60,10,30},%
    aaa/{10,30,60},%
    aab/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60},%
    zcb/{60,10,30},%
    zcb/{60,10,30},%
    aaa/{10,30,60}%
  },%
  Third Group/{%
    zzz/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60},%
    zcb/{60,10,30},%
    zcb/{60,10,30},%
    aaa/{10,30,60},%
    aab/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60},%
    zcb/{60,10,30}% 
  }%
}

\begin{document}
\begin{tikzpicture}%
  [text=white,font=\bfseries\sffamily,
  declare function={
    secttoangle(\sect)=(\sect)*\astep;
    percenttodist(\percent)=\min+(\max-\min)/100*\percent;
  }]

  \path[fill=black] circle(\max+1.6cm);

  \def\cursectinit{0}
  \foreach \curgroup/\curdata in \mydata {
    \foreach \curlabel/\values [count=\cp] in \curdata {
      % angle for this current label
      \pgfmathsetmacro{\angle}{secttoangle(\cursectinit+\cp)}
      % percent
      \xdef\total{0}
      % histogram
      \foreach \val [count=\cv] in \values {
        \pgfmathsetmacro{\nexttotal}{\total+\val}
        \pgfmathsetmacro{\dmin}{percenttodist(\total)}
        \pgfmathsetmacro{\dmax}{percenttodist(\nexttotal)}
        % sector
        \path[hist \cv=\angle] (\angle+\mstep:\dmin pt)
        arc(\angle+\mstep:\angle-\mstep:\dmin pt) -- (\angle-\mstep:\dmax pt)
        arc(\angle-\mstep:\angle+\mstep:\dmax pt) -- cycle;
        % iteration
        \xdef\total{\nexttotal}
      }
      % label (with autorotation)
      \pgfmathtruncatemacro{\anglenode}{\angle}
      \ifthenelse{\( \anglenode > 90 \) \AND \( \anglenode < 270 \)}{ 
        \node[rotate=180+\anglenode,anchor=east] at (\angle:\max) {\curlabel};
      }{
        \node[rotate=\anglenode,anchor=west] at (\angle:\max) {\curlabel};
      }
      \typeout{label:\curlabel}
    }
    % group limits
    \pgfmathsetmacro{\newsectinit}{\cursectinit+\cp}
    \pgfmathsetmacro{\angleinit}{secttoangle(\cursectinit + 1)}
    \pgfmathsetmacro{\anglefinal}{secttoangle(\newsectinit)}
    \typeout{from:\angleinit,to:\anglefinal}
    % group label
    {
      \Large\bfseries\sffamily
      \draw[decorate,decoration={text along path,
        text=\curgroup,text align={align=center},
        text color=white,reverse path}]
      (\angleinit:\max+1.1cm) arc(\angleinit:\anglefinal:\max+1.1cm);
    }
    % group arrow
    \draw[white,very thick,latex-latex]
    (\angleinit:\max+9mm) arc(\angleinit:\anglefinal:\max+9mm);
    % iteration
    \pgfmathsetmacro{\newsectinit}{\newsectinit+1}
    \xdef\cursectinit{\newsectinit}
  }

  % levels
  \pgfmathsetmacro{\angleinit}{secttoangle(0)}
  \pgfmathsetmacro{\anglefinal}{secttoangle(\cursectinit-1)+\astep/2}
  % thick ticks with labels
  \foreach \percent in {0,50,100}{
    \pgfmathsetmacro{\dist}{percenttodist(\percent)}
    % tick
    \draw[white,thick] (\angleinit:\dist pt)
    arc(\angleinit:\anglefinal:\dist pt);
    % label
    \node[below,font=\tiny\bfseries,rotate=secttoangle(0)]
    at ({secttoangle(0)}:\dist pt) {\percent\%};
  }
  % thin ticks
  \foreach \percent in {10,20,30,40,60,70,80,90}{
    \pgfmathsetmacro{\dist}{percenttodist(\percent)}
    % tick
    \draw[white,draw opacity=.5] (\angleinit:\dist pt)
    arc(\angleinit:\anglefinal:\dist pt);
  }

  % legend
  \foreach \mycat [count=\c] in {Bad,Mediocre,Good}{
    \path[hist \c] (3,-.25+-.5*\c) rectangle ++(.2,.2) ++(0,-.1)
    node[right]{\mycat};
  }
\end{tikzpicture}
\end{document}

第二版

这是带有一些修饰的新版本:群组、阴影背景、级别……

在此处输入图片描述

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.text,shadows}
\usepackage{ifthen}
\tikzset{
  shaded/.style 2 args={
    draw=black,
    thin,rounded corners=1pt,
    top color=#1!50!black,
    bottom color=#1!30!black,
    middle color=#1,
    shading angle=#2-90,
  },
  hist 1/.style={shaded={cyan}{#1}},
  hist 2/.style={shaded={orange}{#1}},
  hist 3/.style={shaded={yellow}{#1}},
}

\def\astep{9} % width (degree) of each sector
\def\min{1cm} % min distance from center
\def\max{3cm} % max distance from center

\def\mydata{%
  First Group/{%
    xxx/{10,30,60},%
    aab/{20,30,50},%
    aba/{30,30,40},%
    aad/{40,30,30},%
    aca/{50,30,20},%
    zcb/{60,10,30},%
    aaa/{10,30,60},%
    aab/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60}%
  },%
  Second Group/{%
    yyy/{60,10,30},%
    zcb/{60,10,30},%
    aaa/{10,30,60},%
    aab/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60},%
    zcb/{60,10,30},%
    zcb/{60,10,30},%
    aaa/{10,30,60}%
  },%
  Third Group/{%
    zzz/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60},%
    zcb/{60,10,30},%
    zcb/{60,10,30},%
    aaa/{10,30,60},%
    aab/{30,30,40},%
    aba/{10,80,10},%
    aad/{30,30,40},%
    aca/{10,30,60},%
    zcb/{60,10,30}% 
  }%
}

\begin{document}
\begin{tikzpicture}[text=white,font=\bfseries,
  declare function={secttoangle(\sect)=(\sect)*\astep+\astep);},
  ]
  \sffamily
  \shade[top color=gray,bottom color=gray,middle color=black,shading angle=45]
  circle(\max+2cm);
  %\pgfmathsermacro{\angle}{-270}
  \def\cursectinit{0}
  \foreach \curgroup/\curdata in \mydata {
    \foreach \curlabel/\values [count=\cp] in \curdata {
      % angle for this current label
      \pgfmathsetmacro{\angle}{secttoangle(\cursectinit+\cp)}
      % distance from center
      \pgfmathsetmacro{\total}{\min}
      \pgfmathsetmacro{\am}{\max-\min}
      \xdef\total{\total}
      % histogram
      \foreach \val [count=\cv] in \values {
        \pgfmathsetmacro{\nexttotal}{\total pt+\am/100*\val}
        % sector
        \path[hist \cv=\angle]
        (\angle+\astep/2:\total pt)
        arc(\angle+\astep/2:\angle-\astep/2:\total pt)
        -- (\angle-\astep/2:\nexttotal pt)
        arc(\angle-\astep/2:\angle+\astep/2:\nexttotal pt)
        -- cycle;
        % iteration
        \xdef\total{\nexttotal}
      }
      % label (with autorotation)
      \pgfmathtruncatemacro{\anglenode}{\angle}
      \ifthenelse{\( \anglenode > 90 \) \AND \( \anglenode < 270 \)}{ 
        \node[rotate=180+\anglenode,anchor=east] at (\angle:\max) {\curlabel};
      }{
        \node[rotate=\anglenode,anchor=west] at (\angle:\max) {\curlabel};
      }
      \typeout{label:\curlabel}
    }
    \pgfmathsetmacro{\newsectinit}{\cursectinit+\cp}
    \pgfmathsetmacro{\angleinit}{secttoangle(\cursectinit + 1)}
    \pgfmathsetmacro{\anglefinal}{secttoangle(\newsectinit)}
    \typeout{from:\angleinit,to:\anglefinal}
    {
      \LARGE\bfseries
      \draw[decorate,
      font=\LARGE\bfseries,
      decoration={text along path,
        text=\curgroup,
        text align={align=center},
        text color=white,
        reverse path,
      }]
      (\angleinit:\max+1.2cm) arc(\angleinit:\anglefinal:\max+1.2cm);
    }

    \draw[white,very thick,latex-latex]
    (\angleinit:\max+1cm) arc(\angleinit:\anglefinal:\max+1cm);
    \pgfmathsetmacro{\newsectinit}{\newsectinit+1}
    \xdef\cursectinit{\newsectinit}
  }

  \pgfmathsetmacro{\angleinit}{secttoangle(0)}
  \pgfmathsetmacro{\anglefinal}{secttoangle(\cursectinit-1)+\astep/2}

  \foreach \percent in {25,50,75}{
    \pgfmathsetmacro{\dist}{\min+(\max-\min)/100*\percent}
    \draw[white,thick] (\angleinit:\dist pt)
    arc(\angleinit:\anglefinal:\dist pt);
    \node[font=\tiny\bfseries,rotate=secttoangle(-1)]
    at ({secttoangle(-1)}:\dist pt) {\percent\%};
  }

\end{tikzpicture}
\end{document}

第一个版本

这是 TikZ 极坐标直方图的示例。

在此处输入图片描述

\documentclass{standalone}
\usepackage{tikz}
\usepackage{ifthen}
\tikzset{
  hist 1/.style={fill=orange},
  hist 2/.style={fill=lime},
  hist 3/.style={fill=cyan},
}

\def\astep{6} % width (degree) of each sector
\def\min{5mm} % min distance from center
\def\max{3cm} % max distance from center

\begin{document}
\begin{tikzpicture}[text=white,font=\bfseries]
  \fill[green!30!black] circle(\max+1cm);
  \foreach \curlabel/\values [count=\cp] in {%
    aaa/{10,30,60},
    aab/{20,30,50},
    aba/{30,30,40},
    aad/{40,30,30},
    aca/{50,30,20},
    zcb/{60,10,30},
    aaa/{10,30,60},
    aab/{30,30,40},
    aba/{10,80,10},
    aad/{30,30,40},
    aca/{10,30,60},
    /,
    zcb/{60,10,30},
    zcb/{60,10,30},
    aaa/{10,30,60},
    aab/{30,30,40},
    aba/{10,80,10},
    aad/{30,30,40},
    aca/{10,30,60},
    zcb/{60,10,30}, 
    zcb/{60,10,30},
    aaa/{10,30,60},
    /,
    aab/{30,30,40},
    aba/{10,80,10},
    aad/{30,30,40},
    aca/{10,30,60},
    zcb/{60,10,30}, 
    zcb/{60,10,30},
    aaa/{10,30,60},
    aab/{30,30,40},
    aba/{10,80,10},
    aad/{30,30,40},
    aca/{10,30,60},
    zcb/{60,10,30}% 
  }{
    \ifthenelse{\equal{\curlabel}{}}{}{
      % angle for this current label
      \pgfmathsetmacro{\angle}{(\cp-1)*\astep-90+\astep/2}
      % distance from center
      \pgfmathsetmacro{\total}{\min}
      \pgfmathsetmacro{\am}{\max-\min}
      \xdef\total{\total}
      % histogram
      \foreach \val [count=\cv] in \values {
        \pgfmathsetmacro{\nexttotal}{\total pt+\am/100*\val}
        % sector
        \filldraw[hist \cv]
        (\angle+\astep/2:\total pt)
        arc(\angle+\astep/2:\angle-\astep/2:\total pt)
        -- (\angle-\astep/2:\nexttotal pt)
        arc(\angle-\astep/2:\angle+\astep/2:\nexttotal pt)
        -- cycle;
        % iteration
        \xdef\total{\nexttotal}
        \typeout{\val:\total}
      }
      % label (with autorotation)
      \pgfmathtruncatemacro{\anglenode}{\angle}
      \ifthenelse{\( \anglenode > 90 \) \AND \( \anglenode < 270 \)}{ 
        \node[rotate=180+\anglenode,anchor=east] at (\angle:\max) {\curlabel};
      }{
        \node[rotate=\anglenode,anchor=west] at (\angle:\max) {\curlabel};
      }
    }
  }
\end{tikzpicture}
\end{document}

答案2

以下答案使用轮图包,是我写的。

数据首先存储在宏中\WClist。这里,第一个值对应红色部分,第二个值对应黄色部分。

使用密钥获取每个切片之间的间隙gap polar=5

共有 3 个轮图。第一个绘制红色部分,第二个绘制黄色部分,最后一个绘制绿色部分。

data月份。它们的旋转和固定取决于 给出的角度\WCmidangle。这是在键 中设置的data style

在此处输入图片描述

\documentclass[border=6pt]{standalone}
\usepackage{wheelchart}
\begin{document}
\begin{tikzpicture}[scale=0.05,white]
\def\WClist{%
  10/30/January,
  20/30/February,
  30/30/March,
  40/30/April,
  50/30/May,
  60/10/June,
  10/30/July,
  30/30/August,
  10/80/September,
  30/30/October,
  10/10/November,
  20/20/December%
}
\pgfkeys{
  /wheelchart,
  data=,
  gap polar=5,
  value=1
}
\def\r{20}
\def\WCdefradius#1{\fpeval{sqrt((#1)*(100-(\r/10)^2)+\r^2)}}
\fill[black] (0,0) circle[radius=110];
\wheelchart[
  radius={\r}{\WCdefradius{\WCvarA}},
  slices style=red
]{\WClist}
\wheelchart[
  radius={\WCdefradius{\WCvarA}}{\WCdefradius{\WCvarA+\WCvarB}},
  slices style=yellow
]{\WClist}
\wheelchart[
  data=\WCvarC,
  data style={
    /utils/exec={
      \pgfmathparse{\WCmidangle<225?1:(\WCmidangle<316?0:1)}
      \ifnum\pgfmathresult=1
        \pgfmathsetmacro{\WCrotate}{\WCmidangle-90}
        \def\WCanchor{south}
      \else
        \pgfmathsetmacro{\WCrotate}{\WCmidangle+90}
        \def\WCanchor{north}
      \fi
    },
    rotate=\WCrotate,
    anchor=\WCanchor
  },
  middle={\huge 2022},
  radius={\WCdefradius{\WCvarA+\WCvarB}}{100},
  slices style=green
]{\WClist}
\foreach\n in {0,...,10}{
  \draw (0,0) circle[radius={\WCdefradius{10*\n}}];
}
\end{tikzpicture}
\end{document}

相关内容