LaTeX forum ⇒ Graphics, Figures & TablesMacros for piechart, barchart, spiderweb

Information and discussion about graphics, figures & tables in LaTeX documents.
koubi
Posts: 2
Joined: Fri Sep 16, 2016 4:39 pm

Macros for piechart, barchart, spiderweb

Postby koubi » Fri Sep 16, 2016 4:56 pm

Hi,

I spent few days trying to "macrofy" the rendering of piechart, barchart, and spiderweb from raw data input wihtin the document. I wanted some high level API like

  1. \barchart
  2. {5cm} %%label width
  3. { %% data (label/value)
  4. apples/432,
  5. banana/34,
  6. pineapples/1223
  7. }%%barchart
  8.  
  9. \spiderweb %% 0 to 100 grid
  10. {4,5cm} %% radius for labels
  11. {3,5cm} %% radius for spiderweb
  12. {70} %% baseline score
  13. { %% data (label/score)
  14. Fifty/10,
  15. Sixty/20,
  16. Seventy/50
  17. }%%spiderweb
  18.  
  19. or
  20.  
  21. \def\colorCycleList{{"blue","red","yellow","green", "orange", "gray" }}
  22. \piechart{
  23. (Very Low,37),
  24. (Low,23),
  25. (Average,34),
  26. (High,5),
  27. (Very High,1)
  28. }%%piechart


The above is how I currently use the macros I implemented. I had to use xintForPair for the last one, maybe foreach can be use instead... well although the spiderweb rendering isn't that short (few seconds...), it's fine for me, and I just wanted to share.

Macro for piechart with example :
  1. \documentclass{standalone}
  2.  
  3. \usepackage{tikz}
  4. \usepackage{fp}
  5. \usepackage{pgfplots}
  6. \usepackage{xintexpr}
  7. \usepackage{xstring}
  8.  
  9. %% originaly used with babel french, which causes some issues
  10. %% wihout the following line
  11. \usetikzlibrary{babel}
  12.  
  13.  
  14. \def\colorCycleList{{"blue","red","yellow","green", "orange", "gray" }}
  15.  
  16.  
  17. %%
  18. %% #1 = list of titles and values (not percents)
  19. %%
  20. %% example :
  21. %%
  22. %% \piechart{
  23. %% (Very Low,37),
  24. %% (Low,23),
  25. %% (Average,34),
  26. %% (High,5),
  27. %% (Very High,1)
  28. %% }
  29. %%
  30. \newcounter{totalPieChart}
  31. \newcommand{\piechart}[1]{
  32. %compute total in order to compute percentages
  33. \setcounter{totalPieChart}{0}
  34. \xintForpair ##1##2 in{#1} \do {\addtocounter{totalPieChart}{##2}}
  35.  
  36. %get the number of colors in the \colorCycleList
  37. \pgfmathparse{int(dim(\colorCycleList)-1)}
  38. \edef\cycleColorMax{\pgfmathresult}
  39.  
  40. \begin{tikzpicture}[nodes = {font=\sffamily}, scale=1]
  41. \def\angle{0}
  42. \def\radius{3}
  43. \newcount\cyclecount \cyclecount=-1
  44. \newcount\ind \ind=-1
  45. \xintForpair ##1##2 in{#1} \do {
  46. \def\currentLoc{##2}
  47. \def\name{##1}
  48. \FPeval{\percent}{round(\currentLoc*100/\thetotalPieChart,2)}
  49. \ifx\percent\empty\else % If \percent is empty, do nothing
  50. \global\advance\cyclecount by 1 % Advance cyclecount
  51. \global\advance\ind by 1 % Advance list index
  52. \ifnum\cycleColorMax<\cyclecount % If cyclecount is larger than list
  53. \global\cyclecount=0 % reset cyclecount and
  54. \global\ind=0 % reset list index
  55. \fi
  56. \pgfmathparse{\colorCycleList[\the\ind]} % Get color from cycle list
  57. \edef\color{\pgfmathresult} % and store as \color
  58. % Draw angle and set labels
  59. \draw[fill={\color!50},draw={\color!50!black!50}] (0,0) -- (\angle:\radius)
  60. arc (\angle:\angle+\percent*3.6:\radius) -- cycle;
  61. % do not print the percentage within the pie if the slice is too small
  62. \ifnum5<\percent
  63. \node at (\angle+0.5*\percent*3.6:0.7*\radius) {\percent\,\%};
  64. \node[pin=\angle+0.5*\percent*3.6:\name] at (\angle+0.5*\percent*3.6:\radius) {};
  65. \else
  66. \node at (\angle+0.5*\percent*3.6:0.7*\radius) {};
  67. \node[pin=\angle+0.5*\percent*3.6:\name~(\percent\,\%)] at (\angle+0.5*\percent*3.6:\radius) {};
  68. \fi
  69. %at (\angle+0.5*\percent*3.6:{\radius+1.3}) {\percent\%};
  70. \pgfmathparse{\angle+\percent*3.6} % Advance angle
  71. \xdef\angle{\pgfmathresult} % and store in \angle
  72. \fi
  73. };
  74. \end{tikzpicture}
  75. }
  76.  
  77.  
  78. \begin{document}
  79.  
  80. \piechart{
  81. (Very Low,873)
  82. }
  83. \piechart{
  84. (Very Low,873),
  85. (Low,1890)
  86. }
  87. \piechart{
  88. (Very Low,873),
  89. (Low,1890),
  90. (Average,3755)
  91. }
  92. \piechart{
  93. (Very Low,873),
  94. (Low,1890),
  95. (Average,3755),
  96. (High,1165),
  97. (Very High,325),
  98. (Low,1890),
  99. (Average,3755),
  100. (Low,1890),
  101. (Average,3755),
  102. (Very Very High,5)
  103. }
  104.  
  105. \end{document}


pie-chart-1.png
pie-chart-1.png (17.6 KiB) Viewed 992 times

pie-chart-2.png
pie-chart-2.png (35.81 KiB) Viewed 992 times


Macro for spiderweb with example:
  1. \documentclass{standalone}
  2.  
  3. \usepackage{tikz}
  4. \usepackage{pgfplots}
  5.  
  6. %% originaly used with babel french, which causes some issues
  7. %% wihout the following line
  8. \usetikzlibrary{babel}
  9.  
  10. %%
  11. %% #1 = radius (4cm is good)
  12. %% #2 = radius for labels (3.5cm)
  13. %% #3 = score baseline (blue line)
  14. %% #4 = list of titles and values
  15. %%
  16. %% example
  17. %%
  18. %% \spiderweb{4,5cm}{3,5cm}{70}{
  19. %% Sécurité/10,
  20. %% Maintenabilité/30,
  21. %% Fiabilité/50,
  22. %% Portabilité/70,
  23. %% Performance/90
  24. %% }
  25. %%
  26. \newcommand{\spiderweb}[4]{
  27.  
  28. \newcount\numberOfDimensionsForSpiderWebCounter \numberOfDimensionsForSpiderWebCounter=0
  29. \foreach \Title/\Score in {#4} {
  30. \global\advance\numberOfDimensionsForSpiderWebCounter by 1 % Advance cyclecount
  31. }
  32.  
  33. \def\numberOfDimensionsForSpiderWeb{\the\numberOfDimensionsForSpiderWebCounter} % number of dimensions (config option)
  34. \def\numberOfScaleUnits{100} % number of scale units (config option)
  35. \def\calculatedAngleBetweenDimAxes{360/\numberOfDimensionsForSpiderWeb} % calculated angle between dimension axes
  36.  
  37. \newdimen\R % maximal diagram radius (config option)
  38. \newdimen\L % radius to put dimension labels (config option)
  39.  
  40. \L=#1
  41. \R=#2
  42.  
  43. \begin{tikzpicture}[nodes = {font=\sffamily}, scale=1]
  44. \path (0:0cm) coordinate (O); % define coordinate for origin
  45. % draw the spiderweb
  46. \foreach \Title/\Value[count=\X] in {#4} {
  47. \draw (\X*\calculatedAngleBetweenDimAxes+90:0) -- (\X*\calculatedAngleBetweenDimAxes+90:\R);
  48. \node[pin=\X*\calculatedAngleBetweenDimAxes+90:{\Title}] at (\X*\calculatedAngleBetweenDimAxes+90:\R) {};
  49. }
  50. \foreach \Y in {0,...,10}{
  51. \draw [opacity=0.3] (90:\Y*\R*10/\numberOfScaleUnits)
  52. \foreach \X in {1,...,\numberOfDimensionsForSpiderWeb}{
  53. -- (\X*\calculatedAngleBetweenDimAxes+90:\Y*\R*10/\numberOfScaleUnits)
  54. } -- cycle;
  55. }
  56. % create paths
  57. \foreach \Y in {0,...,\numberOfScaleUnits}{
  58. \foreach \X in {1,...,\numberOfDimensionsForSpiderWeb}{
  59. \path (\X*\calculatedAngleBetweenDimAxes+90:\Y*\R/\numberOfScaleUnits) coordinate (D\X-\Y);
  60. \fill (D\X-\Y) circle (1pt);
  61. }
  62. }
  63.  
  64. \newcount\cyclecountDeux \cyclecountDeux=0
  65. \foreach \Title/\Score in {#4} {
  66. \global\advance\cyclecountDeux by 1 % Advance cyclecount
  67. \def\X{\the\cyclecountDeux}
  68. \def\Y{\Score}
  69. \path (\X*\calculatedAngleBetweenDimAxes+90:\Y*\R/\numberOfScaleUnits) coordinate (S\X);
  70. \fill (S\X) circle (1pt);
  71. }
  72.  
  73. \newcount\cyclecount \cyclecount=1
  74. \foreach \Title/\Score in {#4} {
  75. \global\advance\cyclecount by 1 % Advance cyclecount
  76. \ifnum\numberOfDimensionsForSpiderWebCounter<\cyclecount
  77. \global\cyclecount=1
  78. \fi
  79.  
  80. \newcount\nextcyclecount \nextcyclecount=\the\cyclecount;
  81. \global\advance\nextcyclecount by 1
  82. \ifnum\numberOfDimensionsForSpiderWebCounter<\nextcyclecount
  83. \global\nextcyclecount=1
  84. \fi
  85. \draw [color=blue,line width=4pt,opacity=0.5] (D\the\cyclecount-#3) -- (D\the\nextcyclecount-#3);
  86. \draw [color=red,line width=4pt,opacity=0.5] (S\the\cyclecount) -- (S\the\nextcyclecount);
  87.  
  88. }
  89.  
  90. \end{tikzpicture}
  91. }
  92.  
  93. \begin{document}
  94.  
  95. \spiderweb{4,5cm}{3,5cm}{70}{
  96. Chaos/10,
  97. Order/30,
  98. Neutral/50
  99. }
  100.  
  101. \spiderweb{4,5cm}{3,5cm}{70}{
  102. Security/10,
  103. Maintenability/30,
  104. Reliability/50,
  105. Portability/70,
  106. Efficiency/10
  107. }
  108.  
  109.  
  110. \spiderweb{4,5cm}{3,5cm}{70}{
  111. Security/10,
  112. Maintenability/30,
  113. Reliability/50,
  114. Portability/70,
  115. Maintenability/30,
  116. Reliability/50,
  117. Portability/70,
  118. Maintenability/30,
  119. Reliability/50,
  120. Portability/70,
  121. Maintenability/30,
  122. Reliability/50,
  123. Portability/70,
  124. Maintenability/30,
  125. Reliability/50,
  126. Portability/70,
  127. Efficiency/10
  128. }
  129.  
  130. \end{document}


spiderweb-chart-1.png
spiderweb-chart-1.png (39.83 KiB) Viewed 992 times

spiderweb-chart-2.png
spiderweb-chart-2.png (43.08 KiB) Viewed 992 times


Macro for barchart with example:
  1. \documentclass{report}
  2.  
  3. \usepackage[left=20mm,right=20mm, top=30mm, bottom=30mm,a4paper]{geometry}
  4. \usepackage[usenames,dvipsnames,table,xcdraw]{xcolor}
  5.  
  6. \usepackage{pgfplots}
  7. \usepackage{setspace}
  8.  
  9. \usepackage{siunitx}
  10. \usepackage{tikz}
  11. \usepackage{wallpaper}
  12. \usepackage{xintexpr}
  13. \usetikzlibrary{shadows}
  14.  
  15. %% originaly used with babel french, which causes some issues
  16. %% wihout the following line
  17. \usetikzlibrary{babel}
  18.  
  19. \makeatletter
  20. \newcommand*{\getlengthincm}[1]{\strip@pt\dimexpr0.035146\dimexpr#1\relax\relax}
  21. \makeatother
  22.  
  23.  
  24. \newcommand{\nume}[1]{\num[group-separator=\text{~},output-decimal-marker={,},group-digits=integer,group-minimum-digits=4]{#1}}
  25.  
  26. %%
  27. %% #1 = label width
  28. %% #2 = list of titles and values
  29. %%
  30. %% example:
  31. %%
  32. %% \barchart{6cm}{
  33. %% apples/2047,
  34. %% pears/1244,
  35. %% banana/1208,
  36. %% {a fruit name with slashes / well / ...}/1055,
  37. %% {a fruit name}/9009
  38. %% }
  39. %%
  40. \newcommand{\barchart}[2]{
  41. %% reorder list (thanks \foreach...)
  42. \foreach \l/\x[count=\y] in {#2} {
  43. \ifthenelse{\equal{\y}{1}}{
  44. \xdef\orderedList{{\l}/\x}
  45. }{
  46. \xdef\orderedList{{\l}/\x, \orderedList}
  47. }
  48. }
  49.  
  50. %% compute bar length to adjust to textwidth
  51. \newdimen\barlength
  52. \setlength{\barlength}{\textwidth}
  53. \addtolength{\barlength}{-#1}
  54. \addtolength{\barlength}{-2cm}
  55.  
  56. \def\maxval{0} %% stores the maximum value of input data
  57. \newcount\barcount \barcount=0
  58. \foreach \l/\x[count=\y] in \orderedList {
  59. \global\edef\maxval{\xinttheiiexpr max(\x,\maxval)\relax}
  60. \global\advance\barcount by 1
  61. }
  62. \edef\maxval{\xintthefloatexpr (\maxval*110)/100\relax} %% add 10% to the max value for dimensionning the graph
  63.  
  64. \def\xstep{\xinttheiexpr [10] \getlengthincm{\barlength}/\maxval \relax} %% compute the x steps
  65.  
  66. { %% add group to avoid spreading stretch value
  67. \setstretch{0.6}
  68. \begin{tikzpicture}[x={(\xstep,0)}]
  69. \foreach \l/\x[count=\y] in \orderedList {
  70. %% \l = label name
  71. %% \x = input data
  72. \node[left] at (0,\y) {
  73. %% surround the data within a tabular
  74. \begin{tabular}{>{
  75. %\columncolor{white}
  76. \raggedleft\arraybackslash}p{#1}} \small \l \end{tabular}
  77. };
  78. %% draw bar
  79. \filldraw[blue!50, draw=blue!50!black] (0,\y-.3) rectangle (\x,\y+.3);
  80. %% draw value as a node
  81. \node[right] at (\x, \y) {\small\nume{\x}};
  82. }
  83. %% draw axis bar
  84. \draw (0,0.5) -- (0,\xintthefloatexpr{\the\barcount + 0.5}\relax);
  85.  
  86. \end{tikzpicture}
  87. }
  88. }
  89.  
  90.  
  91. \begin{document}
  92.  
  93. \barchart{3cm}{
  94. {a line with slashes / and multiline}/666
  95. }
  96.  
  97. \begin{figure}
  98. \barchart{4cm}{
  99. TITI/25000,
  100. TATA/15000,
  101. TUTU/3900
  102. }
  103. \caption{test bar chart}
  104. \end{figure}
  105.  
  106. \end{document}


Image

Feel free to use and comment.

Best regards.
Last edited by koubi on Mon Sep 19, 2016 9:59 am, edited 2 times in total.

Tags:

User avatar
Stefan Kottwitz
Site Admin
Posts: 8790
Joined: Mon Mar 10, 2008 9:44 pm

Postby Stefan Kottwitz » Fri Sep 16, 2016 5:54 pm

Hi koubi,

welcome to the forum!

Very interesting macros. Thank you for sharing! I added images to your post, so readers can immediately see the examples as compiled images too.

When I tested the bar chart example, I got

! Undefined control sequence.
\XINT_expr_scanfunc_panic ...rror:bigtroubleahead
(0\relax
l.94 }


but I must admit that I tested it on a PC with a TeX installation of 2014. I will test it again on TeX Live 2016 at home.

Stefan
Site admin

koubi
Posts: 2
Joined: Fri Sep 16, 2016 4:39 pm

Postby koubi » Fri Sep 16, 2016 6:07 pm

I compiled that on archlinux with texlive from repo. It also works with latest stable miktex on windows.


Return to “Graphics, Figures & Tables”

Who is online

Users browsing this forum: No registered users and 3 guests