6

I am trying to connect a CSV file to a wheelchart of the tikzpicture package. The image below looks fine, the only issue is that currently the data entries are hard coded. In the code below you can see that I already generated a CSV file. Does somebody knows how to link this CSV to the wheelchart? enter image description here

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows}
\usepackage{filecontents}
\usepackage{pgfplots}
\usepackage{pgfplotstable}

% This CSV should be added to the /wheelchart command below
\begin{filecontents}{testdata.csv}
 Name,   Quantity
"Blueberries",  16
"Pears",    5
"Bananas",  4
"Grapes",   2
\end{filecontents}

\pgfplotstableread[col sep=comma]{testdata.csv}\datatable

\begin{document}

% Adjusts the size of the wheel:
\def\innerradius{2.8cm}
\def\outerradius{3.2cm}

% The main macro
\newcommand{\wheelchart}[1]{
    % Calculate total
    \pgfmathsetmacro{\totalnum}{0}
    \foreach \value/\colour/\name in {#1} {
        \pgfmathparse{\value+\totalnum}
        \global\let\totalnum=\pgfmathresult
    }
    \begin{center}
        \begin{tikzpicture}

        % Calculate the thickness and the middle line of the wheel
        \pgfmathsetmacro{\wheelwidth}{\outerradius-\innerradius}
        \pgfmathsetmacro{\midradius}{(\outerradius+\innerradius)/2}

        % Rotate so we start from the top
        \begin{scope}[rotate=90]

        % Loop through each value set. \cumnum keeps track of where we are in the wheel
        \pgfmathsetmacro{\cumnum}{0}
        \foreach \value/\colour/\name in {#1} {
            \pgfmathsetmacro{\newcumnum}{\cumnum + \value/\totalnum*360}

            % Calculate the percent value
            \pgfmathsetmacro{\percentage}{\value}
            % Calculate the mid angle of the colour segments to place the labels
            \pgfmathsetmacro{\midangle}{-(\cumnum+\newcumnum)/2}

            % This is necessary for the labels to align nicely
            \pgfmathparse{
                (-\midangle<180?"west":"east")
            } \edef\textanchor{\pgfmathresult}
            \pgfmathsetmacro\labelshiftdir{1-2*(-\midangle>180)}

            % Draw the color segments. Somehow, the \midrow units got lost, so we add 'pt' at the end. Not nice...
            \fill[\colour] (-\cumnum:\outerradius) arc (-\cumnum:-(\newcumnum):\outerradius) --
            (-\newcumnum:\innerradius) arc (-\newcumnum:-(\cumnum):\innerradius) -- cycle;

            % Draw the data labels
            \draw  [*-,thin] node [append after command={(\midangle:\midradius pt) -- (\midangle:\outerradius + 1ex) -- (\tikzlastnode)}] at (\midangle:\outerradius + 1ex) [xshift=\labelshiftdir*0.5cm,inner sep=0pt, outer sep=0pt, ,anchor=\textanchor]{\name: \pgfmathprintnumber{\percentage}};


            % Set the old cumulated angle to the new value
            \global\let\cumnum=\newcumnum
        }

        \end{scope}
        %      \draw[gray] (0,0) circle (\outerradius) circle (\innerradius);
        \end{tikzpicture}
    \end{center}
}

% This is where the CSV should be added instead of hard-coded data entries.
\wheelchart{16/blue/Blueberries,  5/green/Pears, 4/yellow/Bananas, 2/pink/Grapes}

\end{document}
1
  • Do you want to specify the color in the CSV as well? – Torbjørn T. Jun 5 '17 at 11:41
5

Here is a quick rewrite that reads the values from the table, so the argument to \wheelchart is \datatable instead. I made a second table to hold the colors. You have to make sure that there are at least as many colors in the colortable as in the datatable though, I haven't implemented any looping (my initial attempt failed).

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows}
\usepackage{filecontents}
\usepackage{pgfplotstable}

% This CSV should be added to the /wheelchart command below
\begin{filecontents*}{testdata.csv}
Name,   Quantity
Blueberries,  16
\end{filecontents*}
\begin{filecontents*}{testdata2.csv}
Name,   Quantity
Blueberries,  16
Pears,    5
Bananas,  4
Grapes,   2
\end{filecontents*}

\pgfplotstableread[col sep=comma]{testdata.csv}\datatableA

\pgfplotstableread[col sep=comma]{testdata2.csv}\datatableB

\pgfplotstableread{
clr
blue!70
red
yellow
green
}\MyColors

% Adjusts the size of the wheel:
\def\innerradius{2.8cm}
\def\outerradius{3.2cm}

\newcommand\LabelName{}
\newcommand\LabelValue{}
% The main macro
\newcommand{\wheelchart}[1]{
    % Calculate total
    \pgfmathsetmacro{\totalnum}{0}
    % get number of rows in table
    \pgfplotstablegetrowsof{#1}
    % minus 1 because indexing starts as zero
    \pgfmathsetmacro{\RowsInTable}{\pgfplotsretval-1}
    \foreach \i in {0,...,\RowsInTable} {
        \pgfplotstablegetelem{\i}{Quantity}\of{#1}
        \pgfmathparse{\pgfplotsretval+\totalnum}
        \global\let\totalnum=\pgfmathresult
    }
    \begin{center}
        \begin{tikzpicture}

        % Calculate the thickness and the middle line of the wheel
        \pgfmathsetmacro{\wheelwidth}{\outerradius-\innerradius}
        \pgfmathsetmacro{\midradius}{(\outerradius+\innerradius)/2}

        % Rotate so we start from the top
        \begin{scope}[rotate=90]

        % Loop through each value set. \cumnum keeps track of where we are in the wheel
        \pgfmathsetmacro{\cumnum}{0}

        \foreach \i in {0,...,\RowsInTable} {
            % get values from table
            \pgfplotstablegetelem{\i}{Name}\of{#1}\global\let\LabelName=\pgfplotsretval
            \pgfplotstablegetelem{\i}{Quantity}\of{#1}\renewcommand\LabelValue{\pgfplotsretval}

            \pgfmathsetmacro{\newcumnum}{\cumnum + \LabelValue/\totalnum*360}


            % Calculate the percent value
            \pgfmathsetmacro{\percentage}{\LabelValue}
            % Calculate the mid angle of the colour segments to place the labels
            \pgfmathsetmacro{\midangle}{-(\cumnum+\newcumnum)/2}

            % This is necessary for the labels to align nicely
            \pgfmathparse{
                (-\midangle<180?"west":"east")
            } \edef\textanchor{\pgfmathresult}
            \pgfmathsetmacro\labelshiftdir{ifthenelse(\RowsInTable==0,-1,1)*(1-2*(-\midangle>180))}

            % Draw the color segments. Somehow, the \midrow units got lost, so we add 'pt' at the end. Not nice...
            \pgfplotstablegetelem{\i}{clr}\of{\MyColors}
            \fill[color=\pgfplotsretval] (-\cumnum:\outerradius) arc (-\cumnum:-(\newcumnum):\outerradius) --
            (-\newcumnum:\innerradius) arc (-\newcumnum:-(\cumnum):\innerradius) -- cycle;

            % Draw the data labels
            \draw  [*-,thin] node [append after command={(\midangle:\midradius pt) -- (\midangle:\outerradius + 1ex) -- (\tikzlastnode)}] at (\midangle:\outerradius + 1ex) [xshift=\labelshiftdir*0.5cm,inner sep=0pt, outer sep=0pt, ,anchor=\textanchor]{\LabelName: \pgfmathprintnumber{\percentage}};


            % Set the old cumulated angle to the new value
            \global\let\cumnum=\newcumnum
        }

        \end{scope}
        %      \draw[gray] (0,0) circle (\outerradius) circle (\innerradius);
        \end{tikzpicture}
    \end{center}
}

\begin{document}

\wheelchart{\datatableA}

\wheelchart{\datatableB}

\end{document}
10
  • Awesome! Works well. How would I be able to specify custom colours? Preferably using 'cycle list colours'. \pgfplotscreateplotcyclelist{lexcolours}{ {draw=none,fill=lexblue, every node near coord/.append style=black}, {draw=none,fill=lexgreen, every node near coord/.append style=black}, {draw=none,fill=lexpink, every node near coord/.append style=black}, {draw=none,fill=lexyellow, every node near coord/.append style=black}, {draw=none,fill=lexred, every node near coord/.append style=black}, } – Raphael Spaans Jun 5 '17 at 12:36
  • @RaphaelSpaans I don't know how to do that specifically with a cycle list, but I made an alternative. – Torbjørn T. Jun 5 '17 at 12:52
  • Great stuff! Only problem still is that if my csv only has 1 row besides the labels, it will produce the following error: Package PGF Math Error: You've asked me to divide 75.0' by 0.0', but I cannot divide any number by `0.0' (in '(0+1)*75/0.0'). \wheelchart{\datatable}. Also, the label won't be nicely placed besides the wheelchart anymore. Apologies if I'm asking too much of you, but you are helping me heaps! – Raphael Spaans Jun 5 '17 at 15:06
  • @RaphaelSpaans That error must be from the previous version (specifically the evaluate in the \foreach), the code above works fine with just one data row. The label placement is not good though, that I can see. Don't have time to look at it right now though. – Torbjørn T. Jun 5 '17 at 15:20
  • Great! If you can find time to look at this, that would be awesome. Then I will be able to use it to its full potential, right now it doesn't look professional enough for 1 row csv files. – Raphael Spaans Jun 5 '17 at 19:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.