5

I have the following data:

Year     upper       lower
2007     3.2         -.81
2008     2.0         -.29
2009     1.8         -.95
2010     -.5         -3.9
2011     -2.         -7.3

And I'd like a graph that fills the area between upper and lower. The effect I'm going for is similar to Fill between two curves in pgfplots..

First question: If my data were organized as below, I think I could easily just use a fill command:

Year     upper
2007     3.2  
2008     2.0  
2009     1.8  
2010     -.5  
2011     -2.         
2011     -7.3
2010     -3.9 
2009     -.95
2008     -.29 
2007     -.81

Is there a way to use pgfplots, or any other tool, to plot the graph with shading between upper and lower boundary in this data format?

Second question: Also, I would like the shaded region between years 2009.5 and 2010.5 to have a different color. Is there a way to do this without having these points in my data?

After cobbling together solutions to other questions on this site, the closest I've come is the below minimal non-working example. I'm able to create macros for the new interpolated values, and I hoped to concatenate those into the existing table, but was unable to use the macros in the tableread command. I'm still woefully short of my goal, but this is advanced stuff for me.

\documentclass[border=5mm]{standalone}
\usepackage{pgfplots, pgfplotstable}
\usetikzlibrary{calc}

\pgfplotstableread{
Year     upper       lower
2007     3.2         -.81
2008     2.0         -.29
2009     1.8         -.95
2010     -.5         -3.9
2011     -2.         -7.3
}\datatable


\begin{document} 


% Interpolate 2009.5 upper
\pgfplotstablegetelem{2}{lower}\of\datatable
\pgfmathsetmacro{\y}{\pgfplotsretval}
\pgfplotstablegetelem{3}{lower}\of\datatable
\pgfmathsetmacro{\x}{\pgfplotsretval}
\pgfmathsetmacro{\firstupper}{\y-(\y-\x)/2}

% Interpolate 2009.5 lower
\pgfplotstablegetelem{2}{upper}\of\datatable
\pgfmathsetmacro{\y}{\pgfplotsretval}
\pgfplotstablegetelem{3}{upper}\of\datatable
\pgfmathsetmacro{\x}{\pgfplotsretval}
\pgfmathsetmacro{\firstlower}{\y-(\y-\x)/2}

% Interpolate 2010.5 upper
\pgfplotstablegetelem{3}{lower}\of\datatable
\pgfmathsetmacro{\y}{\pgfplotsretval}
\pgfplotstablegetelem{4}{lower}\of\datatable
\pgfmathsetmacro{\x}{\pgfplotsretval}
\pgfmathsetmacro{\firstupper}{\y-(\y-\x)/2}

% Interpolate 2010.5 lower
\pgfplotstablegetelem{3}{upper}\of\datatable
\pgfmathsetmacro{\y}{\pgfplotsretval}
\pgfplotstablegetelem{4}{upper}\of\datatable
\pgfmathsetmacro{\x}{\pgfplotsretval}
\pgfmathsetmacro{\secondlower}{\y-(\y-\x)/2}

\begin{tikzpicture}
\begin{axis}[
    /pgf/number format/1000 sep={},
xmin=2007,
xmax=2011,
ymin=-8,
ymax=5,
    enlarge x limits=false
]
\addplot [draw=none, stack plots=y,forget plot] table [y=lower] {\datatable};
\addplot [draw=none, fill=gray, opacity=.5,stack plots=y] table [y expr=\thisrow{upper}-\thisrow{lower}] {\datatable} \closedcycle;
\addplot [stack plots=y, stack dir=minus,forget plot, draw=none] table [y expr=\thisrow{upper}-\thisrow{lower}] {\datatable};
\end{axis}
\begin{axis}[
    /pgf/number format/1000 sep={},
xmin=2007,
xmax=2011,
ymin=-8,
ymax=5,
    enlarge x limits=false
]
\addplot [draw=none, stack plots=y, forget plot, restrict x to domain=2009.5:2010.5] table [y=lower]{\datatable};
\addplot [draw=none, fill=white,opacity=.5,stack plots=y, restrict x to domain=2009.5:2010.5] table [y expr=\thisrow{upper}-\thisrow{lower}] {\datatable} \closedcycle;
\end{axis} 

\end{tikzpicture}

\end{document}

Thanks!

PaulB
  • 737
  • I'm not sure I understand your second question. Could you post a picture of a mock-up of what you're trying to achieve? – Jake Oct 22 '13 at 05:31
  • does my edit make it more clear? I couldn't think of an easy way to make the mock up. – PaulB Oct 22 '13 at 15:40

3 Answers3

4

For the first question: You can use stack plots=y to stack the plots on top of each other, and put \closedcycle at the end of the second one to fill the area between the two curves:

\documentclass[border=5mm]{standalone}
\usepackage{pgfplots, pgfplotstable}

\pgfplotstableread{
Year     upper       lower
2007     3.2         -.81
2008     2.0         -.29
2009     1.8         -.95
2010     -.5         -3.9
2011     -2.         -7.3
}\datatable

\begin{document}
\begin{tikzpicture}
\begin{axis}[
    /pgf/number format/1000 sep={},
    enlarge x limits=false
]
\addplot [draw=none, stack plots=y] table [y=lower] {\datatable};
\addplot [draw=none, fill=orange, stack plots=y] table [y expr=\thisrow{upper}-\thisrow{lower}] {\datatable} \closedcycle;
\end{axis}
\end{tikzpicture}
\end{document}
Jake
  • 232,450
3

enter image description here

This is MWE with the other tool, Asymptote. It loads the data from a file, fills the main region and then split out the inner part defined by real innerLeft=2009.5; and real innerRight=2010.5; time stamps and fills it with different colors.

% yearplot.tex :    
%
\begin{filecontents*}{data.dat}
Year     upper       lower
2007     3.2         -.81
2008     2.0         -.29
2009     1.8         -.95
2010     -.5         -3.9
2011     -2.         -7.3
\end{filecontents*}
%
\documentclass{article}
\usepackage[inline]{asymptote}
\usepackage{lmodern}
\begin{document}
\begin{figure}
\begin{asy}
size(300,160,IgnoreAspect);
import graph;
import fontsize;
defaultpen(fontsize(9pt));

string filename="data.dat";
pen lpen=mediumblue;
pen upen=lightblue;
pen lpenB=mediumred;
pen upenB=lightred;
pen axispen=darkblue+0.6bp+squarecap;

real innerLeft=2009.5; 
real innerRight=2010.5;

file fin=input(filename).line();

string s=fin.line(); // read title
string[] title=split(s); 

real[][] a=fin.dimension(0,0);  // read the data matrix
a=transpose(a);                 // a[0] = years, a[1] = upper, a[2] = lower

// +++ main UpperRegion
guide upper=graph(a[0],a[1]);
guide lower=graph(a[0],a[2]);
guide mid=graph(a[0],0.5*(a[1]+a[2]));

guide LowerRegion=lower--reverse(mid)--cycle;
guide UpperRegion=upper--reverse(mid)--cycle;
fill(LowerRegion,lpen);
fill(UpperRegion,upen);
// --- main UpperRegion

// +++ inner UpperRegion
real[] timesLeft;
real[] timesRight;
timesLeft=times(LowerRegion,innerLeft);
timesRight=times(LowerRegion,innerRight);

guide innerLower=subpath(LowerRegion,timesLeft[0],timesRight[0]);
guide innerMiddle=subpath(LowerRegion,timesRight[1],timesLeft[1]);

timesLeft=times(UpperRegion,innerLeft);
timesRight=times(UpperRegion,innerRight);

guide innerUpper=subpath(UpperRegion,timesLeft[0],timesRight[0]);

fill(innerLower--innerMiddle--cycle,lpenB);
fill(innerUpper--innerMiddle--cycle,upenB);

// --- inner UpperRegion

xaxis(Label(title[0],0.5),YEquals(min(a[2])-1),min(a[0])-0.5,max(a[0])+0.5,axispen,LeftTicks(Step=1));
yaxis(XEquals(min(a[0])-0.5),min(a[2])-1,max(a[1]),axispen,RightTicks(Step=2,step=1));

shipout(bbox(Fill(lightyellow)));
\end{asy}
\end{figure}
\end{document}
%
% Process:
%
% pdflatex yearplot.tex 
% asy yearplot-*.asy
% pdflatex yearplot.tex 
g.kov
  • 21,864
  • 1
  • 58
  • 95
  • This is exactly the effect I'm looking for, but I hope to achieve it with pgfplots. Is there no end to the number of useful and cool LaTeX packages? – PaulB Oct 22 '13 at 13:16
2

I finally answered the second part of my question by gathering bits and pieces from Jake's answers to other questions. I've learned quite a bit in this process. I'm sure this can more efficiently be done using loops, but this will serve my purpose.enter image description here

\documentclass[border=5mm]{standalone}
\usepackage{pgfplots, pgfplotstable}
\usetikzlibrary{calc}

\pgfplotstableread{
Year     upper       lower
2007     3.2         -.81
2008     2.0         -.29
2009     1.8         -.95
2010     -.5         -3.9
2011     -2.         -7.3
}\datatable


\newcommand\addrows[1]{
\pgfplotstablegetelem{2}{upper}\of#1
\pgfmathsetmacro{\y}{\pgfplotsretval}
\pgfplotstablegetelem{3}{upper}\of#1
\pgfmathsetmacro{\x}{\pgfplotsretval}
\pgfmathsetmacro{\firstnewupper}{\y-(\y-\x)/2}

\pgfplotstablegetelem{2}{lower}\of#1
\pgfmathsetmacro{\y}{\pgfplotsretval}
\pgfplotstablegetelem{3}{lower}\of#1
\pgfmathsetmacro{\x}{\pgfplotsretval}
\pgfmathsetmacro{\firstnewlower}{\y-(\y-\x)/2}

\pgfplotstablegetelem{3}{upper}\of#1
\pgfmathsetmacro{\y}{\pgfplotsretval}
\pgfplotstablegetelem{4}{upper}\of#1
\pgfmathsetmacro{\x}{\pgfplotsretval}
\pgfmathsetmacro{\secondnewupper}{\y-(\y-\x)/2}

\pgfplotstablegetelem{3}{lower}\of#1
\pgfmathsetmacro{\y}{\pgfplotsretval}
\pgfplotstablegetelem{4}{lower}\of#1
\pgfmathsetmacro{\x}{\pgfplotsretval}
\pgfmathsetmacro{\secondnewlower}{\y-(\y-\x)/2}

\edef\makenew{\noexpand\pgfplotstableread[header=has colnames,col sep=comma,row sep=crcr]{
    Year,upper,lower\noexpand\\
    2009.5,\firstnewupper,\firstnewlower\noexpand\\
    2010.5,\secondnewupper,\secondnewlower\noexpand\\
}\noexpand\interpolated}
\makenew

\pgfplotstablevertcat#1{\interpolated}
\pgfplotstablesort[sort cmp=float >]{#1}{#1}
}
\begin{document} 
\addrows{\datatable}


\begin{tikzpicture}
\begin{axis}[
    /pgf/number format/1000 sep={},
xmin=2007,
xmax=2011,
ymin=-8,
ymax=5,
    enlarge x limits=false
]
\addplot [draw=none, stack plots=y,forget plot] table [y=lower] {\datatable};
\addplot [draw=none, fill=gray, opacity=.5,stack plots=y] table [y expr=\thisrow{upper}-\thisrow{lower}] {\datatable} \closedcycle;
\addplot [stack plots=y, stack dir=minus,forget plot, draw=none] table [y expr=\thisrow{upper}-\thisrow{lower}] {\datatable};
\end{axis}
\begin{axis}[
    /pgf/number format/1000 sep={},
xmin=2007,
xmax=2011,
ymin=-8,
ymax=5,
    enlarge x limits=false
]
\addplot [draw=none, stack plots=y, forget plot, restrict x to domain=2009.5:2010.5] table [y=lower]{\datatable};
\addplot [draw=none, fill=white,opacity=.5,stack plots=y, restrict x to domain=2009.5:2010.5] table [y expr=\thisrow{upper}-\thisrow{lower}] {\datatable} \closedcycle;
\end{axis} 

\end{tikzpicture}

\end{document}
David Carlisle
  • 757,742
PaulB
  • 737