pgf-pie.sty 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. % Start of pgf-pie.sty
  3. %
  4. % Some LaTeX macros for pie chart by using PGF/Tikz package.
  5. % Home page of project: http://pgf-pie.googlecode.com/
  6. % Author: Xu Yuan <xuyuan.cn@gmail.com>
  7. %
  8. \NeedsTeXFormat{LaTeX2e}[1999/12/01]
  9. \ProvidesPackage{pgf-pie}[2011/10/02 v0.2 Some LaTeX macros for pie
  10. chart by using PGF/Tikz package.]
  11. \RequirePackage{tikz}
  12. \RequirePackage{ifthen}
  13. \RequirePackage{scalefnt}
  14. % args:
  15. % #1: begin angle
  16. % #2: end angle
  17. % #3: number
  18. % #4: label
  19. % #5: explode
  20. % #6: fill color
  21. % #7: radius
  22. % #8: center
  23. \newcommand{\pgfpie@slice}[8]{
  24. \pgfmathparse{0.5*(#1)+0.5*(#2)}
  25. \let\midangle\pgfmathresult
  26. \path (#8) -- ++(\midangle:#5) coordinate(O);
  27. \pgfmathparse{#7+#5}
  28. \let\radius\pgfmathresult
  29. % slice
  30. \draw[line join=round, fill=#6, \style] (O) -- ++(#1:#7) arc (#1:#2:#7) -- cycle;
  31. \pgfmathparse{min(((#2)-(#1)-10)/110*(-0.3),0)}
  32. \let\temp\pgfmathresult
  33. \pgfmathparse{(max(\temp,-0.5) + 0.8)*#7}
  34. \let\innerpos\pgfmathresult
  35. \ifthenelse{\equal{\pgfpie@text}{inside}}
  36. {
  37. % label and number together
  38. \path (O) -- ++(\midangle:\innerpos) node
  39. {\scalefont{#3}\shortstack{#4\\\beforenumber#3\afternumber}};
  40. }
  41. {
  42. % label
  43. \iflegend
  44. \else
  45. \path (O) -- ++ (\midangle:\radius)
  46. node[inner sep=0, \pgfpie@text=\midangle:#4]{};
  47. \fi
  48. % number
  49. \path (O) -- ++(\midangle:\innerpos) node
  50. {\scalefont{#3}\beforenumber#3\afternumber};
  51. }
  52. }
  53. \newcommand{\pgfpie@findColor}[1]
  54. {
  55. \pgfmathparse{int(mod(#1,\value{pgfpie@colorLength}))}
  56. \let\ci\pgfmathresult
  57. \foreach \c [count=\j from 0] in \color {
  58. \ifnum \j=\ci
  59. \xdef\thecolor{\c}
  60. \thecolor
  61. \breakforeach
  62. \fi
  63. }
  64. }
  65. \newcommand{\pgfpie@findExplode}[1]
  66. {
  67. \pgfmathparse{int(mod(#1,\value{pgfpie@explodeLength}))}
  68. \let\ei\pgfmathresult
  69. \foreach \e [count=\j from 0] in \explode {
  70. \ifnum \j=\ei
  71. \xdef\theexplode{\e}
  72. \breakforeach
  73. \fi
  74. }
  75. }
  76. % #1: bottom left point
  77. % #2: size
  78. % #3: number
  79. % #4: color
  80. % #5: text
  81. \newcommand{\pgfpie@square}[5]
  82. {
  83. \ifthenelse{\equal{\pgfpie@text}{inside}}
  84. {
  85. \draw[fill=#4, \style] (#1) rectangle node
  86. {\scalefont{#3}\shortstack{#5\\\beforenumber#3\afternumber}} ++(#2);
  87. }
  88. {
  89. \draw[fill=#4, \style] (#1) rectangle node
  90. {\scalefont{#3}\beforenumber#3\afternumber} ++(#2);
  91. }
  92. }
  93. % #1: pos
  94. % #2: radius
  95. % #3: number
  96. % #4: color
  97. % $5: style
  98. % $6: label
  99. \newcommand{\pgfpie@cloud}[6]
  100. {
  101. \draw[fill=#4, #5] (#1) circle[radius=#2];
  102. \ifthenelse{\equal{\pgfpie@text}{inside}}
  103. {
  104. \node at (#1) {\scalefont{#3}\shortstack{#6\\\beforenumber#3\afternumber}};
  105. }
  106. {
  107. \node at (#1) {\scalefont{#3}\beforenumber#3\afternumber};
  108. }
  109. }
  110. \newlength{\pgfpie@angleEnd}
  111. \newcounter{pgfpie@explodeLength}
  112. \newcounter{pgfpie@colorLength}
  113. \newcounter{pgfpie@sliceLength}
  114. \def\setexplode#1\pgfeov{\def\explode{#1}}
  115. \pgfkeyslet{/explode/.@cmd}{\setexplode}
  116. \def\setcolor#1\pgfeov{\def\color{#1}}
  117. \pgfkeyslet{/color/.@cmd}{\setcolor}
  118. \def\setradius#1\pgfeov{\def\radius{#1}}
  119. \pgfkeyslet{/radius/.@cmd}{\setradius}
  120. \def\setpos#1\pgfeov{\def\pos{#1}}
  121. \pgfkeyslet{/pos/.@cmd}{\setpos}
  122. \def\setstyle#1\pgfeov{\def\style{#1}}
  123. \pgfkeyslet{/style/.@cmd}{\setstyle}
  124. \def\setbeforenumber#1\pgfeov{\def\beforenumber{#1}}
  125. \pgfkeyslet{/before number/.@cmd}{\setbeforenumber}
  126. \def\setafternumber#1\pgfeov{\def\afternumber{#1}}
  127. \pgfkeyslet{/after number/.@cmd}{\setafternumber}
  128. \def\settext#1\pgfeov{\xdef\pgfpie@text{#1}}
  129. \pgfkeyslet{/text/.@cmd}{\settext}
  130. \def\setsum#1\pgfeov{\xdef\pgfpie@sum{#1}}
  131. \pgfkeyslet{/sum/.@cmd}{\setsum}
  132. \def\setrotate#1\pgfeov{\xdef\rotate{#1}}
  133. \pgfkeyslet{/rotate/.@cmd}{\setrotate}
  134. \newif\ifpolar
  135. \pgfkeys{/polar/.is if=polar}
  136. \newif\iflegend
  137. \newif\ifsquare
  138. \pgfkeys{/square/.is if=square}
  139. \newif\ifcloud
  140. \pgfkeys{/cloud/.is if=cloud}
  141. \newif\ifscalefont
  142. \pgfkeys{/scale font/.is if=scalefont}
  143. \let\scalefontorg\scalefont
  144. \renewcommand{\scalefont}[1]
  145. {
  146. \ifscalefont
  147. \pgfmathparse{#1 / \pgfpie@sum * 3 + 0.9}
  148. \scalefontorg{\pgfmathresult}
  149. \fi
  150. }
  151. \newcommand{\pie}[2][]
  152. {
  153. % load default parameters
  154. \pgfkeys{
  155. explode=0,
  156. color={blue!60, cyan!60, yellow!60, orange!60, red!60,
  157. blue!60!cyan!60, cyan!60!yellow!60, red!60!cyan!60,
  158. red!60!blue!60, orange!60!cyan!60},
  159. radius=3,
  160. pos={0,0},
  161. style={thick},
  162. before number=,
  163. after number=,
  164. text=label,
  165. sum=100,
  166. rotate=0,
  167. polar=false,
  168. square=false,
  169. cloud=false,
  170. scale font=false,
  171. }
  172. % load user's parameters
  173. \pgfkeys{#1}
  174. % add percentage automatically
  175. \ifthenelse{\equal{\pgfpie@sum}{100}}
  176. {
  177. \pgfkeys{after number=\%}
  178. \pgfkeys{#1}
  179. }{}
  180. % legend or not
  181. \ifthenelse{\equal{\pgfpie@text}{legend}}
  182. {\legendtrue}
  183. {\legendfalse}
  184. % handle sum
  185. \ifthenelse{\equal{\pgfpie@sum}{auto}}
  186. {
  187. % sum all input
  188. \xdef\pgfpie@sum{0}
  189. \foreach \p/\t in {#2}
  190. {
  191. \pgfmathparse{\pgfpie@sum + \p}
  192. \xdef\pgfpie@sum{\pgfmathresult}
  193. }
  194. }
  195. {}
  196. % init counters
  197. \setcounter{pgfpie@explodeLength}{0}
  198. \foreach \e in \explode { \addtocounter{pgfpie@explodeLength}{1} }
  199. \setcounter{pgfpie@colorLength}{0}
  200. \foreach \c in \color { \addtocounter{pgfpie@colorLength}{1} }
  201. \pgfmathsetlength{\pgfpie@angleEnd}{0}
  202. \setcounter{pgfpie@sliceLength}{0}
  203. \foreach \p/\e in {#2} { \addtocounter{pgfpie@sliceLength}{1} }
  204. \ifsquare
  205. %%%%%%%%%% SQUARE PIE BEGIN %%%%%%%%%%%
  206. \pgfmathparse{\radius*2}
  207. \xdef\verticalLength{\pgfmathresult}
  208. \xdef\horizontalLength{\pgfmathresult}
  209. \path (\pos) -- ++(-\radius, -\radius) coordinate (start);
  210. \pgfmathparse{\verticalLength * \horizontalLength / \pgfpie@sum}
  211. \let\squareUnit\pgfmathresult
  212. % drawing loop
  213. \foreach \p/\t [count=\i from 0] in {#2}
  214. {
  215. \pgfpie@findColor{\i}
  216. \ifthenelse{\lengthtest{\verticalLength cm > \horizontalLength cm}}
  217. {
  218. \pgfmathparse{\p * \squareUnit / \horizontalLength}
  219. \let\height\pgfmathresult
  220. \pgfpie@square{start}{\horizontalLength,\height}
  221. {\p}
  222. {\thecolor}
  223. {\t}
  224. %label
  225. \iflegend
  226. \else
  227. \ifthenelse{\equal{\pgfpie@text}{inside}}
  228. {}
  229. {
  230. \path (start) -- ++(\horizontalLength,\height*0.5) node[inner
  231. sep=0, \pgfpie@text=0:\t]{};
  232. }
  233. \fi
  234. \pgfmathparse{\verticalLength - \height}
  235. \xdef\verticalLength{\pgfmathresult}
  236. \path (start) -- ++(0, \height) coordinate (start);
  237. }
  238. {
  239. \pgfmathparse{\p * \squareUnit / \verticalLength }
  240. \let\width\pgfmathresult
  241. \pgfpie@square{start}{\width,\verticalLength}
  242. {\p}
  243. {\thecolor}
  244. {\t}
  245. %label
  246. \iflegend
  247. \else
  248. \ifthenelse{\equal{\pgfpie@text}{inside}}
  249. {}
  250. {
  251. \path (start) -- ++(\width*0.5,\verticalLength) node[inner
  252. sep=0, \pgfpie@text=90:\t]{};
  253. }
  254. \fi
  255. \pgfmathparse{\horizontalLength - \width}
  256. \xdef\horizontalLength{\pgfmathresult}
  257. \path (start) -- ++(\width, 0) coordinate (start);
  258. }
  259. }
  260. %%%%%%%%%% SQUARE PIE END %%%%%%%%%%%
  261. \else
  262. \ifcloud
  263. %%%%%%%%%% CLOUD PIE BGEIN %%%%%%%%%%%
  264. % drawing loop
  265. \foreach \p/\t [count=\i from 0] in {#2}
  266. {
  267. % find explode
  268. \pgfpie@findExplode{\i}
  269. \def\cloudGap{\theexplode + 0.1}
  270. \pgfmathparse{sqrt(\p / \pgfpie@sum) * \radius}
  271. \let\cloudR\pgfmathresult
  272. \ifnum \i = 0
  273. % first cloud
  274. \coordinate (O) at (\pos);
  275. \xdef\cloudRone{\cloudR}
  276. \xdef\cloudExtendDir{180+\rotate}
  277. \else
  278. \ifnum \i = 1
  279. % second cloud
  280. \xdef\cloudRtwo{\cloudR}
  281. \xdef\cloudExtendDir{45+\rotate}
  282. \path (O) -- ++(\cloudExtendDir:\cloudRone+\cloudGap+\cloudRtwo) coordinate (O);
  283. \else
  284. % next cloud
  285. \pgfmathparse{\cloudRone+\cloudGap+\cloudRtwo}
  286. \let\la\pgfmathresult
  287. \pgfmathparse{\cloudRone+\cloudGap+\cloudR}
  288. \let\lb\pgfmathresult
  289. \pgfmathparse{\cloudRtwo+\cloudGap+\cloudR}
  290. \let\lc\pgfmathresult
  291. \pgfmathparse{\la^2+\lc^2-\lb^2}
  292. \let\tmp\pgfmathresult
  293. \pgfmathparse{180 - acos(\tmp / 2 / \la / \lc)}
  294. \let\cloudRot\pgfmathresult
  295. \ifodd \i
  296. \pgfmathparse{-\cloudRot}
  297. \let\cloudRot\pgfmathresult
  298. \fi
  299. \pgfmathparse{\cloudExtendDir - \cloudRot}
  300. \xdef\cloudExtendDir{\pgfmathresult}
  301. \path (O) -- ++(\cloudExtendDir:\lc) coordinate (O);
  302. \xdef\cloudRone{\cloudRtwo}
  303. \xdef\cloudRtwo{\cloudR}
  304. \fi
  305. \fi
  306. % find color
  307. \pgfpie@findColor{\i}
  308. \pgfpie@cloud{O}{\cloudR}{\p}
  309. {\thecolor}{\style}{\t}
  310. % label
  311. \iflegend
  312. \else
  313. \ifthenelse{\equal{\pgfpie@text}{inside}}
  314. {}
  315. {
  316. \path (O) -- ++(\cloudExtendDir:\cloudR)
  317. node[inner sep=0, \pgfpie@text=\cloudExtendDir:\t] {};
  318. }
  319. \fi
  320. }
  321. %%%%%%%%%% CLOUD PIE BGEIN %%%%%%%%%%%
  322. \else
  323. %%%%%%%%%% CIRCLE PIE BGEIN %%%%%%%%%%%
  324. \ifpolar
  325. \xdef\maxValue{0}
  326. \foreach \p/\e in {#2} {
  327. \ifnum \maxValue < \p
  328. \xdef\maxValue{\p}
  329. \fi
  330. }
  331. \pgfmathparse{\pgfpie@sum / \value{pgfpie@sliceLength}}
  332. \xdef\polarangle{\pgfmathresult}
  333. \pgfmathparse{\radius / sqrt(\maxValue)}
  334. \xdef\polarRadiusUnit{\pgfmathresult}
  335. \else
  336. \xdef\theradius{\radius}
  337. \fi
  338. \xdef\pgfpie@angleBegin{\the\pgfpie@angleEnd}
  339. % drawing loop
  340. \foreach \p/\t [count=\i from 0] in {#2}
  341. {
  342. \pgfmathsetlength{\pgfpie@angleEnd}{\pgfpie@angleBegin}
  343. \ifpolar
  344. % Polar area diagram
  345. \pgfmathaddtolength{\pgfpie@angleEnd}{\polarangle}
  346. \pgfmathparse{sqrt(\p) * \polarRadiusUnit}
  347. \xdef\theradius{\pgfmathresult}
  348. \else
  349. % normal pie
  350. \pgfmathaddtolength{\pgfpie@angleEnd}{\p}
  351. \fi
  352. % find explode
  353. \pgfpie@findExplode{\i}
  354. % find color
  355. \pgfpie@findColor{\i}
  356. \pgfpie@slice{\pgfpie@angleBegin/\pgfpie@sum*360+\rotate}
  357. {\the\pgfpie@angleEnd/\pgfpie@sum*360+\rotate}
  358. {\p}
  359. {\t}
  360. {\theexplode}
  361. {\thecolor}
  362. {\theradius}
  363. {\pos}
  364. \xdef\pgfpie@angleBegin{\the\pgfpie@angleEnd}
  365. }
  366. %%%%%%%%%% CIRCLE PIE END %%%%%%%%%%%
  367. \fi
  368. \fi
  369. % legend
  370. \iflegend
  371. \coordinate[xshift=0.8cm,
  372. yshift=(\value{pgfpie@sliceLength}*0.5+1)*0.5cm] (legendpos) at
  373. (current bounding box.east);
  374. \begin{scope}[node distance=0.5cm]
  375. \foreach \p/\t [count=\i from 0] in {#2}
  376. {
  377. \pgfpie@findColor{\i}
  378. \node[draw, fill=\thecolor, \style, below of=legendpos, label=0:\t] (legendpos) {};
  379. }
  380. \end{scope}
  381. \fi
  382. }
  383. %%% End of pgf-pie.sty
  384. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%