Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

This question is related to Fill between two curves in pgfplots. which started me of.

However, I need to have just the area above the reference line filled.

\begin{tikzpicture}

\pgfplotstableread{data.dat}\data
\pgfplotstablesort[sort cmp={float >}]\coordinates{
0 0.9
33 0.9}

\pgfplotstablevertcat{\filledcurve}{\coordinates}
\pgfplotstablevertcat{\filledcurve}{\data}
\pgfplotstabletypeset{\filledcurve}

\begin{axis}[xlabel=Time of day, ylabel=Volume,xtick=\empty,ytick=\empty, axis x line=bottom, axis y line=left,enlargelimits=true]
\addplot[fill=gray!40,draw=none] table {\filledcurve}; 
\addplot[blue,mark=*,line width=2pt] table {\data};
\addplot[orange,mark=*,line width=2pt] table {\coordinates};
\end{axis}
\end{tikzpicture}

The datafile looks like:

0 0.2
1 0.217
2 0.255
3 0.288
6 0.58
7 0.9
8 1.02

In the code above I would like that just the area of \data above \coordinates is filled grey. Does anyone got a hint?

share|improve this question
    
Welcome to Tex.SX. Please provide a full MWE including \documentclass. You could try to use the solution you liked to and fill the area between the curve and the line y=<y axis max> and use draw=none for that line so it does not get drawn. –  Peter Grill Aug 15 '11 at 20:13
add comment

2 Answers

up vote 8 down vote accepted

Here's a macro that generates a new table \interpolated that places points on your original data at every intersection with a certain y-value. You call it using \findintersections{<table macro}{<value>}.

To plot the area above the line, you would then use \addplot[fill,gray!20!white,no markers,line width=2pt] table [y=above line] {\interpolated};, or ...table [y=below line] for the area below the line.

In order to close the area properly in case your plot stops or begins above the cutoff line, you should add |- (current plot begin) at the end of the plot command.

\documentclass{article}

\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\usetikzlibrary{calc}
\begin{filecontents}{data.dat}
0 0.2
1 0.217
2 0.255
3 0.288
6 0.58
7 0.91
8 1.02
10 1.05
12 0.92
13 0.78
15 0.56
17 1.1
\end{filecontents}

\pgfplotstableread{data.dat}\data

\newcommand\findintersections[2]{
    \def\prevcell{#1}
    \pgfplotstableforeachcolumnelement{1}\of#2\as\cell{%
        \pgfmathparse{!or(
            and(
                \prevcell>#1,\cell>#1
            ),
            and(
                \prevcell<#1,\cell<#1
            )
        )}

        \ifnum\pgfmathresult=1
            \pgfplotstablegetelem{\pgfplotstablerow}{0}\of{\data} \let\xb=\pgfplotsretval
            \pgfplotstablegetelem{\pgfplotstablerow}{1}\of{\data} \let\yb=\pgfplotsretval
            \pgfmathtruncatemacro\previousrow{ifthenelse(\pgfplotstablerow>0,\pgfplotstablerow-1,0)}
            \pgfplotstablegetelem{\previousrow}{0}\of{\data} \let\xa=\pgfplotsretval
            \pgfplotstablegetelem{\previousrow}{1}\of{\data} \let\ya=\pgfplotsretval
            \pgfmathsetmacro\newx{
                \xa+(\ya-#1)/(ifthenelse(\yb==\ya,1,\ya-\yb) )*(\xb-\xa)    }

            \edef\test{\noexpand\pgfplotstableread[col sep=comma,row sep=crcr,header=has colnames]{
                0,1\noexpand\\
                \newx,#1\noexpand\\
            }\noexpand\newrow}
            \test
            \pgfplotstablevertcat\interpolated{\newrow}
        \fi
        \let\prevcell=\cell
    }
    \pgfplotstablevertcat\interpolated{#2}
    \pgfplotstablesort[sort cmp={float <}]\interpolated{\interpolated}
    \pgfplotstableset{
        create on use/above line/.style={
            create col/expr={max(\thisrow{1},#1)}
        },
        create on use/below line/.style={
            create col/expr={min(\thisrow{1},#1)}
        },
    }
}


\begin{document}
\pgfplotsset{compat=newest} % For nicer label placement

\findintersections{0.9}{\data}

\begin{tikzpicture}
\begin{axis}[
    xlabel=Time of day,
    ylabel=Volume,
    ytick=\empty,
    axis x line=bottom,
    axis y line=left,
    enlargelimits=true
    ]
\addplot[fill,gray!20!white,no markers,line width=2pt] table [y=above line] {\interpolated} |- (current plot begin);
\addplot[fill,yellow!20!white,no markers,line width=2pt] table [y=below line] {\interpolated} |- (current plot begin);
\addplot[orange,no markers,line width=2pt,domain=-1:20] {0.9};
\addplot[blue,line width=2pt,mark=*] table  {\data};
\end{axis}
\end{tikzpicture}

\end{document}
share|improve this answer
    
Thanks a lot! That exactly works as I needed! –  ThijsMuis Aug 16 '11 at 6:31
    
This works great, unless there is a file named data.dat.tex in the same directory. Took my quite some time to figure this out so thought I'd put that info here in case others encounter problems with this. –  Peter Grill Aug 16 '11 at 16:06
    
Note though that this happens because I used the filecontents environment in my example to keep everything in one file. In a real application, the filecontents package and environment would not be used. –  Jake Aug 16 '11 at 22:42
add comment

With the recently released pgfplots 1.10 and its fillbetween library (I learned it from Elke here) it's much easier.

  • Load the library: \usepgfplotslibrary{fillbetween}
  • Give the plots a name: \addplot[name path=curve,orange, ...
  • Add a fill plot:

      \addplot fill between[ 
        of = curve and line, 
        split, % calculate segments
        every even segment/.style = {yellow!20!white},
        every odd segment/.style ={gray!20!white}
      ]; 
    

Complete example:

Filled area between curve and line

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepackage{pgfplotstable}
\usepgfplotslibrary{fillbetween}
\usetikzlibrary{calc}
\usepackage{filecontents}
\begin{filecontents}{data.dat}
0 0.2
1 0.217
2 0.255
3 0.288
6 0.58
7 0.91
8 1.02
10 1.05
12 0.92
13 0.78
15 0.56
17 1.1
\end{filecontents}

\pgfplotstableread{data.dat}\data

\begin{document}
\begin{tikzpicture}
\begin{axis}[
    xlabel=Time of day,
    ylabel=Volume,
    ytick=\empty,
    axis x line=bottom,
    axis y line=left,
    enlargelimits=true
    ]
  \addplot[name path=curve,orange,no markers,line width=2pt,domain=0:17] {0.9};
  \addplot[name path=line,blue,line width=2pt,mark=*] table  {\data};
  \addplot fill between[ 
    of = curve and line, 
    split, % calculate segments
    every even segment/.style = {yellow!20!white},
    every odd segment/.style ={gray!20!white}
  ]; 
\end{axis}
\end{tikzpicture}
\end{document}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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