4

As a followup question to Filling the area under a graph based on intersection with another graph, I'm looking to create the following effect:

  • Fill based on the coordinates of the intersection between the two graphs.
  • Plots stacked, so area under the normal-curve, but between the two graphs (under normal but above skew) should be cyan!20. The area under the other curve should be green!20.
  • None of those graphical anomalies... problem is though, that the first intersection of the graph disappears within the animation and the intersection segments key is completely static (it will always use the n-th intersection of the n-th path, bugger!).

I've fiddled around with the domain key, but I'm getting very underwhelming results. :-(

The intended result I can only reproduce at specific points, not for the entire animation:

http://i.imgur.com/gvvNzc4.png?1

Christian Feuersänger suspects a bug, so I've moved the original animation code downward.

\documentclass{article}
\usepackage{tikz,pgfplots}
\pgfplotsset{compat=newest}
\usepgfplotslibrary{fillbetween}
\usetikzlibrary{intersections}
\usepackage{animate}
\pgfmathdeclarefunction{normal}{2}{%
  \pgfmathparse{1/(#2*sqrt(2*pi))*exp(-((x-#1)^2)/(2*#2^2))}%
}
\makeatletter
\pgfmathdeclarefunction{erf}{1}{%
  \begingroup
    \pgfmathparse{#1 > 0 ? 1 : -1}%
    \edef\sign{\pgfmathresult}%
    \pgfmathparse{abs(#1)}%
    \edef\x{\pgfmathresult}%
    \pgfmathparse{1/(1+0.3275911*\x)}%
    \edef\t{\pgfmathresult}%
    \pgfmathparse{%
      1 - (((((1.061405429*\t -1.453152027)*\t) + 1.421413741)*\t 
      -0.284496736)*\t + 0.254829592)*\t*exp(-(\x*\x))}%
    \edef\y{\pgfmathresult}%
    \pgfmathparse{(\sign)*\y}%
    \pgfmath@smuggleone\pgfmathresult%
  \endgroup
}
\makeatother
\pgfmathdeclarefunction{skew}{3}{%
        \pgfmathparse{(exp(-((x-#1)^2)/(2*(#2)^2))*((erf((#3*(x-#1))/(sqrt(2)*#2)))+1))/(sqrt(2*pi)*#2)}%
}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
      hide y axis,
      axis lines*=center, 
      axis on top,
      no markers, 
      domain=-1:18, 
      samples=20,
      xlabel=\empty, 
      ylabel=\empty,
      every axis x label/.style={at=(current axis.right of origin),anchor=west},
      every axis y label/.style={at=(current axis.above origin),anchor=south},
      height=5cm, width=12cm,
      xmin = -1, xmax=18,
      xtick=, ytick=\empty,
      enlargelimits=false, 
      clip=false
  ]
  \addplot [name path=normal,very thick,cyan!85!black!50] {normal(10,3.416969)};
  \addplot [name path=skew,very thick,red!85!black!50] {skew(1,4,10)};
  \path [name path=lower, name intersections={of=skew and normal}, intersection segments={of=skew and normal,sequence=B1 -- A2}];
  \path[name path=axis]
(axis cs:\pgfkeysvalueof{/pgfplots/xmin},0) --
(axis cs:\pgfkeysvalueof{/pgfplots/xmax},0);
  \addplot [draw=green!80,fill=green!20] fill between [of=lower and axis, soft clip={(intersection-2) rectangle (axis cs:\pgfkeysvalueof{/pgfplots/xmax},0)}];
\end{axis}
\end{tikzpicture}
\end{document}



\documentclass{article}
\usepackage{tikz,pgfplots}
\pgfplotsset{compat=newest}
\usepgfplotslibrary{fillbetween}
\usetikzlibrary{intersections}
%\usetikzlibrary{calc}
\usepackage{animate}
%\usepackage{fp}
\pgfmathdeclarefunction{normal}{2}{%
  \pgfmathparse{1/(#2*sqrt(2*pi))*exp(-((x-#1)^2)/(2*#2^2))}%
}
\makeatletter
\pgfmathdeclarefunction{erf}{1}{%
  \begingroup
    \pgfmathparse{#1 > 0 ? 1 : -1}%
    \edef\sign{\pgfmathresult}%
    \pgfmathparse{abs(#1)}%
    \edef\x{\pgfmathresult}%
    \pgfmathparse{1/(1+0.3275911*\x)}%
    \edef\t{\pgfmathresult}%
    \pgfmathparse{%
      1 - (((((1.061405429*\t -1.453152027)*\t) + 1.421413741)*\t 
      -0.284496736)*\t + 0.254829592)*\t*exp(-(\x*\x))}%
    \edef\y{\pgfmathresult}%
    \pgfmathparse{(\sign)*\y}%
    \pgfmath@smuggleone\pgfmathresult%
  \endgroup
}
\makeatother
\pgfmathdeclarefunction{skew}{3}{%
        \pgfmathparse{(exp(-((x-#1)^2)/(2*(#2)^2))*((erf((#3*(x-#1))/(sqrt(2)*#2)))+1))/(sqrt(2*pi)*#2)}%
}
\newcommand*{\power}[1]{
\begin{tikzpicture}
\begin{axis}[
      hide y axis,
      axis lines*=center, 
      axis on top,
      no markers, 
      domain=-1:18, 
      samples=20,
      xlabel=\empty, 
      ylabel=\empty,
      every axis x label/.style={at=(current axis.right of origin),anchor=west},
      every axis y label/.style={at=(current axis.above origin),anchor=south},
      height=5cm, width=12cm,
      xmin = -1, xmax=18,
      xtick=, ytick=\empty,
      enlargelimits=false, 
      clip=false
  ]
  \addplot [name path=normal,very thick,cyan!85!black!50] {normal(0.125*#1,3.416969)};
  \addplot [name path=skew,very thick,red!85!black!50] {skew(1,4,10)};
  \path [name path=lower, name intersections={of=skew and normal}, intersection segments={of=skew and normal,sequence=B1 -- A2}];
  \path[name path=axis]
(axis cs:\pgfkeysvalueof{/pgfplots/xmin},0) --
(axis cs:\pgfkeysvalueof{/pgfplots/xmax},0);
  \addplot [draw=cyan!80,fill=cyan!20, stack plots=y] fill between [of=normal and skew,domain=(intersection-2):\pgfkeysvalueof{/pgfplots/xmax}] ;
  \addplot [draw=green!80,fill=green!20, stack plots=y] fill between [of=lower and axis, soft clip={(intersection-2) rectangle (axis cs:\pgfkeysvalueof{/pgfplots/xmax},0)}];
\end{axis}
\end{tikzpicture}
}
\begin{document}
\begin{animateinline}[controls,loop,palindrome]{32}
  \multiframe{94}{ik=32+1}{
    \power{\ik}
    }
    \end{animateinline}
\end{document}
1010011010
  • 6,357
  • That could be a bug in the intersections lib. Can you reduce the example to something without animation? If it is a bug, it should show up in the results of either name intersections, intersection segments or fill between - all rely on the same sub-routine. – Christian Feuersänger May 24 '14 at 21:55
  • Note: stack plots=y is unsupported for \addplot fill between. – Christian Feuersänger May 24 '14 at 21:57
  • @ChristianFeuersänger I have updated my question/request post with the code without any animations in it. You can move around the graph normal between values of the first argument between 10 and 11 (any value will do - I have set normal(10,3.416969) in the example code). – 1010011010 May 24 '14 at 22:52

1 Answers1

4

That is a bug in the intersections library of tikz which becomes evident once we show all intersection nodes:

\documentclass{standalone}
\usepackage{tikz,pgfplots}
\pgfplotsset{compat=newest}
\usepgfplotslibrary{fillbetween}
\usetikzlibrary{intersections}
\pgfmathdeclarefunction{normal}{2}{%
  \pgfmathparse{1/(#2*sqrt(2*pi))*exp(-((x-#1)^2)/(2*#2^2))}%
}
\makeatletter
\pgfmathdeclarefunction{erf}{1}{%
  \begingroup
    \pgfmathparse{#1 > 0 ? 1 : -1}%
    \edef\sign{\pgfmathresult}%
    \pgfmathparse{abs(#1)}%
    \edef\x{\pgfmathresult}%
    \pgfmathparse{1/(1+0.3275911*\x)}%
    \edef\t{\pgfmathresult}%
    \pgfmathparse{%
      1 - (((((1.061405429*\t -1.453152027)*\t) + 1.421413741)*\t 
      -0.284496736)*\t + 0.254829592)*\t*exp(-(\x*\x))}%
    \edef\y{\pgfmathresult}%
    \pgfmathparse{(\sign)*\y}%
    \pgfmath@smuggleone\pgfmathresult%
  \endgroup
}
\pgfmathdeclarefunction{skew}{3}{%
        \pgfmathparse{(exp(-((x-#1)^2)/(2*(#2)^2))*((erf((#3*(x-#1))/(sqrt(2)*#2)))+1))/(sqrt(2*pi)*#2)}%
}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
      hide y axis,
      axis lines*=center, 
      axis on top,
      no markers, 
      domain=-1:18, 
      samples=20,
      xlabel=\empty, 
      ylabel=\empty,
      every axis x label/.style={at=(current axis.right of origin),anchor=west},
      every axis y label/.style={at=(current axis.above origin),anchor=south},
      height=5cm, width=12cm,
      xmin = -1, xmax=18,
      xtick=, ytick=\empty,
      enlargelimits=false, 
      clip=false
  ]
  \addplot [name path=normal,very thick,cyan!85!black!50] {normal(10,3.416969)};
  \addplot [name path=skew,very thick,red!85!black!50] {skew(1,4,10)};
  \path [name intersections={of=skew and normal},font=\tiny] 
    node[draw] at (intersection-1) {1/\pgfintersectionsolutions} 
    node[draw] at (intersection-2) {2/\pgfintersectionsolutions}
    node[draw] at (intersection-3) {3/\pgfintersectionsolutions}
  ;
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

Apparently, the node 1/3 should not be there at all.

Unfortunately, that makes it hard to find a suitable workaround: if you modify your code such that it uses node 3 instead of 2, your example will fail to compile as soon as you receive a new version of TikZ which contains the fix.

  • Thanks for investigating. :-) I'll be waiting for the next version of TikZ then, I guess. – 1010011010 May 25 '14 at 16:50
  • Would it be possible to choose, e.g., whichever intersection point is farthest right, regardless of how many intersection points are computed? – Charles Staats May 25 '14 at 17:58
  • Good idea, @CharlesStaats. I arrived at a suitable solution which always relies on the last intersection, but some frames of the animation still failed to produce the expected output. I will look into it. Anyway, this question lead to some improvements already, so future versions will become easier for related tasks. – Christian Feuersänger May 25 '14 at 19:19