2

In the code below, an extra column is created by adding Proc1 and Proc2 columns explicitly. How can I make this addition in a loop when more than two columns exist?

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.3}

\pgfplotstableread[col sep=comma]{
    Function,Proc1,Proc2
    Add,1,2
    Sub,3,4
    Div,2,3
}{\data}

% sort the table
\pgfplotstablesort[
    create on use/sum/.style={
        create col/expr={
            \thisrow{Proc1} + \thisrow{Proc2}
        },
    },
    sort cmp=float >,
    sort key=sum,
]{\dataSorted}{\data}
Shibli
  • 452

2 Answers2

2

You do not need a loop, I think.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.3}

\pgfplotstableread[col sep=comma]{
    Function,Proc1,Proc2,Proc3
    Add,1,2,3
    Sub,3,4,4
    Div,2,3,5
}{\data}

% sort the table
\pgfplotstablesort[
    create on use/sum/.style={
        create col/expr={
            \thisrow{Proc1} + \thisrow{Proc2} + \thisrow{Proc3}
        },
    },
    sort cmp=float >,
    sort key=sum,
]{\dataSorted}{\data}
\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        cycle list=Dark2,
        ybar stacked,
        ymin=0,
        xtick=data,
        xtick pos=left,
        ytick pos=left,
        axis lines=left,
        xticklabels from table={\dataSorted}{Function},
        x tick label style={rotate=45, anchor=north east, inner sep=0mm},
        ylabel=Elapsed seconds,
        xlabel=Function,
        legend pos=outer north east,
        legend style={draw=none},
        enlarge x limits=0.1,
    ]
            \pgfplotstablegetcolsof{\dataSorted}
            \pgfmathtruncatemacro\numberofcols{\pgfplotsretval-1}
        \foreach \i in {1,...,\numberofcols} {
            \addplot table [y index=\i, x expr=\coordindex] {\dataSorted};
        }
    \end{axis}
\end{tikzpicture}
\end{document}

enter image description here

The lower part of my answer is borrowed from this answer.

You could also use

\pgfplotstablesort[
    create on use/sum/.style={
        create col/expr={
            \thisrowno{1} + \thisrowno{2} + \thisrowno{3}
        },
    },
    sort cmp=float >,
    sort key=sum,
]{\dataSorted}{\data}
  • But I don't want to add columns explicitly. What if there are 50 columns? – Shibli Apr 28 '18 at 11:29
  • @Shibli But why would a loop be less effort than just adding these explicitly? Since you have the table anyway, you can just copy and paste the relevant part of the header and replace then comma by } + \thisrow{. I think that any loop, if possible at all, will be very fragile. –  Apr 28 '18 at 11:35
  • Image you have different number of columns and different column titles. Also as I said imagine you have 50 columns. I think a loop would be much less effort. – Shibli Apr 28 '18 at 11:43
  • @Shibli You can achieve the same with \thisrowno, see my edit. To me it is not straightforward to create \thisrow{1} + \thisrow{2} + ... + \thisrow{50} in a loop because of expansion issues. Even if I could, it may still clash with the internal expansion of pgfplots. –  Apr 28 '18 at 12:03
1

This can be done with some "TeX hackery". Here a solution where all columns with a column index greater than 0 are summed up and sorted.

% used PGFPlots v1.16
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
    \pgfplotsset{compat=1.3}
    % added columns `Proc3' and `Proc4'
    \pgfplotstableread[col sep=comma]{
        Function,Proc1,Proc2,Proc3,Proc4
        Add,1,2,3,4
        Sub,3,4,2,5
        Div,2,3,1,2
    }{\data}
    \pgfplotstableset{
        % ---------------------------------------------------------------------
        % (provided by Christian Feuersänger)
        create on use/sum/.code={
            \let\expr=\empty
            % sum all selected row values:
            \pgfplotstableforeachcolumn\data\as{\X}{%
                \ifnum\pgfplotstablecol>0 % skip the first column
                    \ifx\expr\empty
                        \edef\expr{\noexpand\thisrow{\X}}%
                    \else
                        \toks0=\expandafter{\expr}%
                        \edef\expr{\the\toks0 + \noexpand\thisrow{\X}}%
                    \fi
                \fi
            }%
            \message{Using expr=\meaning\expr^^J}%
            \pgfkeysalso{/pgfplots/table/create col/expr=\expr}%
        },
        % ---------------------------------------------------------------------
    }
    % sort the table
    \pgfplotstablesort[
        % ... which we then use to sort the table
        sort key=sum,
    % the sorted table is then stored in `\dataSorted', which of course then
    % has to be used everywhere in the `axis' environment
    ]{\dataSorted}{\data}
\begin{document}
%    \pgfplotstabletypeset[string type]\dataSorted
\begin{tikzpicture}
    \begin{axis}[
        ybar stacked,
        ymin=0,
        ylabel=Elapsed seconds,
        xlabel=Function,
        xtick=data,
        axis lines=left,
        xticklabels from table={\dataSorted}{Function},
        x tick label style={rotate=45, anchor=north east, inner sep=0mm},
        xtick pos=left,
        ytick pos=left,
        enlarge x limits=0.1,
    ]
            \pgfplotstablegetcolsof{\dataSorted}
            \pgfmathtruncatemacro\numberofcols{\pgfplotsretval-1}
        \foreach \i in {1,...,\numberofcols} {
            \addplot table [x expr=\coordindex,y index=\i] {\dataSorted};
        }
    \end{axis}
\end{tikzpicture}
\end{document}

image showing the result of above code

Stefan Pinnow
  • 29,535