# pgfplots: stacking plots in positive and negative y direction in the same diagram

I have several data files which I want to plot in the following manner:

I achieved this with the following code:

\documentclass{minimal}
\usepackage{pgfplots,filecontents}

\begin{filecontents}{total.dos}
0  0  0  0  0  0  0  0
1  2  0 -2  0  2  0 -2
2  4  0 -4  0  4  0 -4
3  2  0 -2  0  2  0 -2
4  0  0  0  0  0  0  0
5  1  0 -1  0  0  0  0
6  2  0 -2  0  0  0  0
7  1  0 -1  0  0  0  0
8  0  0  0  0  0  0  0
\end{filecontents}

\begin{document}
\begin{tikzpicture}
\begin{axis}[xlabel={Energy [eV]}, ylabel={Intensity}, no markers]
\addplot [fill=red,draw=none] table [x index=0,y index=5] {total.dos};
\addplot [fill=red,draw=red,fill opacity=0.25] table [x index=0,y index=1] {total.dos};
\addplot [fill=red,draw=none] table [x index=0, y index=7] {total.dos};
\addplot [fill=red,draw=red,fill opacity=0.25] table [x index=0,y index=3] {total.dos};
\end{axis}
\end{tikzpicture}
\end{document}


My Question: How can I stack several of those plots?

It should look similar to this:

The problem is that normal stacking doesn't work because this would stack every addplot which leads to wrong output since some y columns of my data have positive and some have negative values for the same x value and pgfplots stacks the plots only in one direction (either positive or negative). But I need to make pgfplots group some addplots, while within the respective groups there is no stacking, and then let it stack the groups. Is this possible?

Update: I have changed the title of my question since the discussions in the comment section revealed that the crucial point is to make pgfplots plot in the positive and negative y direction at the same time. This way I get the plots to appear the way I want.

-
I'm not sure that I'm following the question. What exactly is stopping you from putting all addplots (regardless of the file) in the same axis environment? –  qubyte Jan 24 '12 at 8:09
@MarkS.Everitt: The problem is, that I have positive and negative data columns, but pgfplots does just stack in one direction. So some of the data columns "cancel out each other". I could provide an example if you want. –  Philipp Jan 24 '12 at 8:12
I'm still not following, the plots are simply stacked in the order that you place them... –  qubyte Jan 24 '12 at 8:14
@MarkS.Everitt: I also tried to change the order of the addplots. That changed the result a bit but not essentially. The problem remains, that pgfplots either stacks in the positive or in the negative y direction. –  Philipp Jan 24 '12 at 8:30
Then as long as you know which columns are positive and which are negative, this can be done with two axes. I'll write it up. –  qubyte Jan 24 '12 at 15:44

Perhaps the below is close to what you want. The trick is to add only the positive columns in a stacked plot, and only the negative columns in another plot that pretends to share the same axes. To work, both the visible and invisible axes must have the same domain. I also used the units pgfplots library to separate the units out.

\documentclass{standalone}
\usepackage{pgfplots,filecontents}
\usepgfplotslibrary{units}

\begin{filecontents}{total.dos}
0  0  0  0  0  0  0  0
1  2  0 -2  0  2  0 -2
2  4  0 -4  0  4  0 -4
3  2  0 -2  0  2  0 -2
4  0  0  0  0  0  0  0
5  1  0 -1  0  0  0  0
6  2  0 -2  0  0  0  0
7  1  0 -1  0  0  0  0
8  0  0  0  0  0  0  0
\end{filecontents}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
stack plots=y,
xlabel={Energy},
x unit={eV},
ylabel={Intensity},
no markers,
ymin=-10,
ymax=10
]
\addplot [fill=red,draw=none] table [x index=0,y index=5] {total.dos}\closedcycle;
\addplot [fill=blue,draw=none,fill opacity=0.25] table [x index=0,y index=1] {total.dos}\closedcycle;
\end{axis}
\begin{axis}[
stack plots=y,
no markers,
ymin=-10,
ymax=10,
xtick=\empty,
ytick=\empty,
axis x line=none,
axis y line=none
]
\addplot [fill=red,draw=none] table [x index=0, y index=7] {total.dos}\closedcycle;
\addplot [fill=blue,draw=none,fill opacity=0.25] table [x index=0,y index=3] {total.dos}\closedcycle;
\end{axis}
\end{tikzpicture}
\end{document}


-
+1 for the idea with the second axis - certainly wouldn't have thought about that. Thanks for the effort. –  Philipp Jan 24 '12 at 16:12
@MarkSEveritt: can you include the preamble as well? It seems that some other library is needed to use x unit={eV}. Also am wondering, was there something else you did to get that image, as your graph looks very nice. –  Peter Grill Jan 24 '12 at 16:22
@PeterGrill: He used the preamble from my above example and added \usepgfplotslibrary{units} to provide the x unit command. –  Philipp Jan 24 '12 at 16:25
@Philipp: Thanks. I did not see that in your preamble. However, Mark's graph still looks nicer than what I get, wondering if it is the bold font. –  Peter Grill Jan 24 '12 at 16:28
@PeterGrill: My mistake, I'll put the missed pgfplots library into the answer. Otherwise this plot has the same preamble as in the question. It was converted using Preview on a Mac though, so it may have been subjected to stronger than normal hinting on the text. When I tried to upload this as a pdf the uploader was freaking out and making it weird and pixellated for some reason, thus the conversion this time. –  qubyte Jan 24 '12 at 16:30

For the sake of completeness I will add a different answer to my own question since it solves the problem of stacking in only one y direction without the need of a second axis. Actually pgfplots is able to stack in the positive and negative y direction at the same time if the data files contain positive as well as negative values.

I came across the solution while learning a bit more about the pgfplotstable package. Actually one could achieve the same result by manipulating the data with external tools (like python or bash) as Mark suggested in one of his comments. I prefered to let LaTeX do the job, so that I can use my data files directly.

My solution:

\documentclass{standalone}

\usepackage{pgfplots}
\usepgfplotslibrary{units}

\usepackage{pgfplotstable}
\usepackage{xcolor}
\colorlet{lightred}{red!25!white}
\colorlet{lightblue}{blue!25!white}

\usepackage{filecontents}

\begin{filecontents}{total.dos}
0  0  0  0  0  0  0  0
1  2  0 -2  0  2  0 -2
2  4  0 -4  0  4  0 -4
3  2  0 -2  0  2  0 -2
4  0  0  0  0  0  0  0
5  1  0 -1  0  0  0  0
6  2  0 -2  0  0  0  0
7  1  0 -1  0  0  0  0
8  0  0  0  0  0  0  0
\end{filecontents}

% sort original file from highest to lowest value
\pgfplotstablesort[sort cmp=float >]{\totalsorted}{\total}

% first auxiliary table derived from \total: \totaldummy
\pgfplotstableset{
create on use/x/.style={create col/copy column from table={\total}{[index] 0}},
create on use/dummya/.style={create col/copy column from table={\total}{[index] 1}},
create on use/dummyb/.style={create col/copy column from table={\total}{[index] 3}},
create on use/a/.style={create col/copy column from table={\total}{[index] 5}},
create on use/b/.style={create col/copy column from table={\total}{[index] 7}},
create on use/c/.style={create col/expr={\thisrow{dummya} - \thisrow{a}}},
create on use/d/.style={create col/expr={\thisrow{dummyb} - \thisrow{b}}}}
% create a new table:
\pgfplotstablenew[columns={x, dummya, dummyb, a, b, c, d}] {\pgfplotstablegetrowsof{\total}} {\totaldummy}

% second auxiliary table derived from \totalsorted: \totalsorteddummy
\pgfplotstableset{
create on use/x/.style={create col/copy column from table={\totalsorted}{[index] 0}},
create on use/dummya/.style={create col/copy column from table={\totalsorted}{[index] 3}},
create on use/dummyb/.style={create col/copy column from table={\totalsorted}{[index] 1}},
create on use/a/.style={create col/copy column from table={\totalsorted}{[index] 7}},
create on use/b/.style={create col/copy column from table={\totalsorted}{[index] 5}},
create on use/c/.style={create col/expr={\thisrow{dummya} - \thisrow{a}}},
create on use/d/.style={create col/expr={\thisrow{dummyb} - \thisrow{b}}}}
% create a new table:
\pgfplotstablenew[columns={x, dummya, dummyb, a, b, c, d}] {\pgfplotstablegetrowsof{\total}} {\totalsorteddummy}

% Concatenate the two dummy tables
\pgfplotstablevertcat{\result}{\totaldummy}
\pgfplotstablevertcat{\result}{\totalsorteddummy}

\begin{document}

\begin{tikzpicture}
\begin{axis}[
stack plots=y,
xlabel={Energy},
ylabel={Intensity},
x unit={eV}
]
\addplot [no markers, fill=lightblue, draw=blue] table [x=x, y=c] {\result};
\addplot [no markers, fill=blue, draw=blue] table [x=x, y=a] {\result};
\addplot [no markers, fill=lightred, draw=red] table [x=x, y=c] {\result};
\addplot [no markers, fill=red, draw=red] table [x=x, y=a] {\result};
\end{axis}
\end{tikzpicture}

\end{document}


This results in the following picture:

This way I achieved exactly the look I was aiming for: the right lobes of the plot are more lightly colored than the left ones and the lightly colored regions are coated by a darker line. To get the right look the data values had to be sorted according to the x values. This is done by using \pgfplotstablesort[sort cmp=float >]{\resulttable}{\table or filename} which sorts the data from highest to lowest x value. If one doesn't sort the values the following look would result:

So one could leave out the sorting step if the same colors are used for draw and fill or draw=none is used.

-
If this solves your question better than my answer does, then you should consider marking this as the correct one. –  qubyte Jan 26 '12 at 1:56
@MarkS.Everitt: The central point of my question (the stacking problem) is solved by your answer and in an easier fashion than in my answer which only gives the better results for my special data files. Furthermore it was only in the course of our discussion in the commentary section that I realized which way was to go in order to solve my problem. –  Philipp Jan 26 '12 at 11:39
Fair enough! I won't argue too hard. ;) –  qubyte Jan 26 '12 at 12:47