5

I want to create a plot where positive and negative values have a different color. MWE:

\documentclass[tikz]{standalone}
\usepackage{filecontents}
\usepackage{xstring}

\begin{filecontents}{data.txt}
-3.5 nan
-3.375 nan
-3.25 nan
-3.125 0.000121769833828
-3.0 0.000901599938148
-2.875 0.0014834598325
-2.625 0.00588102803508
-2.25 0.0720113632674
-2.125 0.0314393757219
-1.875 0.0306933267171
-1.75 0.07029144932
-1.375 -0.0342012822215
-1.125 -0.0171975784671
-0.75 -0.0405296273749
-0.625 -0.0330713662613
-0.375 -0.00156002201142
0.0 0.044002036309
0.125 0.0634327667271
0.375 0.0153149732892
0.75 -0.00313272843988
0.875 0.0229547104663
1.125 0.0219197613133
1.625 0.0112441717079
1.875 -0.000229179659447
2.0 nan
2.625 nan
\end{filecontents}


\usepackage{pgfplots}

\begin{document}
\begin{tikzpicture}
\pgfplotsset{onlyPositive/.style={y filter/.code={
        \pgfmathparse{##1<0 ? nan : ##1}}, unbounded coords=jump}}
\pgfplotsset{onlyNegative/.style={y filter/.code={
        \pgfmathparse{##1>=0 ? nan : ##1}}, unbounded coords=jump}}
  \begin{axis}[grid]
    \addplot [] file {data.txt};
    \addplot [onlyPositive,blue,xshift=2mm,very thick] file {data.txt};
    \addplot [onlyNegative,red,xshift=2mm,very thick] file {data.txt};
  \end{axis}
\end{tikzpicture}
\end{document}

Now, I want for example the graphs positive part be blue, negative be red. I tried math. expressions to add 2 plots, one for neg, one for pos. But then, there are holes in the graph between sign change, since I have two plots now (as you can see in the figure). What I really want is that the color automatically changes on the lines.enter image description here

Thank you for helping me out! Max

Max
  • 53
  • 4
  • Welcome to TeX.SX! Seeing also one of your failed attempts might help. – egreg Oct 14 '14 at 06:58
  • In your real application, do you use a line plot for displaying your data, or a scatter plot? If you use a line plot, if you have a sign change between two consecutive data points, do you want the line to change colour midway? – Jake Oct 14 '14 at 07:05
  • I added a larger MWE, expressing my intent more. – Max Oct 14 '14 at 07:28

1 Answers1

4

What you need is some kind of decomposition into intersection segments of your path with the X axis.

There is the fillbetween library in pgfplots which allows to compute (and, typically, fill) intersection segments of path segments. It can also be used to draw individual intersection segments:

enter image description here

\documentclass[tikz]{standalone}
\usepackage{filecontents}

\begin{filecontents}{data.txt}
-3.5 nan
-3.375 nan
-3.25 nan
-3.125 0.000121769833828
-3.0 0.000901599938148
-2.875 0.0014834598325
-2.625 0.00588102803508
-2.25 0.0720113632674
-2.125 0.0314393757219
-1.875 0.0306933267171
-1.75 0.07029144932
-1.375 -0.0342012822215
-1.125 -0.0171975784671
-0.75 -0.0405296273749
-0.625 -0.0330713662613
-0.375 -0.00156002201142
0.0 0.044002036309
0.125 0.0634327667271
0.375 0.0153149732892
0.75 -0.00313272843988
0.875 0.0229547104663
1.125 0.0219197613133
1.625 0.0112441717079
1.875 -0.000229179659447
2.0 nan
2.625 nan
\end{filecontents}


\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}
\pgfplotsset{compat=1.11}

\begin{document}
\begin{tikzpicture}
  \begin{axis}[grid]
    \addplot [draw=none,name path=PATH] file {data.txt};
    \path[name path=0 line] (-10,0) -- (10,0);

    \draw[
        intersection segments={
            of=0 line and PATH,
            sequence=R2 R4 R6}, 
        blue, very thick];
    \draw[
        intersection segments={
            of=0 line and PATH,
            sequence=R3 R5}, 
        red, very thick];
  \end{axis}
\end{tikzpicture}
\end{document}

As you see, the approach is less automatic than a math expression. However, it is much more precise: the intersections are computed explicitly and each segment can be addressed and drawn explicitly. The syntax inside of sequence is that L1 is the first segment of the Left input segment (called 0 line here) and R1 is the first segment of the Rright input segment (called PATH here). I draw every second segment; the start offset and the end segment is manual work.

  • Thank you for this example. Usually, this would solve the problem, so I marked it accordingly. Unfortunately, I was looking for a fully-automatic approach, as I automatically generate these plots. What I did in this case: Since my data is in a file, I could run another (external program) filter on the data, which linearly interpolates between sign changes and hence adds zeros to the graph. Then I could use the onlyPositive and onlyNegative styles to automatically achieve my solution. – Max Oct 16 '14 at 05:46
  • @Christian Feuersänger I too need this functionality in an automated fashion. I tried using y expr={max(\thisrow{\colname},0) but of course the slope is different for the lines above and below the axis and smooth does not work. Is there a way we can do this like a point meta function of y? – SpmP Feb 08 '15 at 23:51
  • @SpmP I will take a note on it for my list of feature reqests, I see its uses. In fact, I considered such an approach and postponed it when I wrote the initial version of fillbetween. However, the use of point meta might turn out to be difficult in this context. I will think about solutions. – Christian Feuersänger Feb 09 '15 at 05:55
  • @Christian Feuersänger I had partial success with \addplot+[black, mark = none,mesh, shader=flat corner,point meta = (y<0)-(y>0)] table ...; but of course the line did not change colour neatly at the zero. Look forward to your solution. Where do can we see your progress on such things? – SpmP Feb 12 '15 at 00:01
  • @SpmP the progress can be seen by (a) watching for changes in the "unstable" section on http://pgfplots.sourceforge.net/ and/or (b) by subscribing as commit watcher on https://sourceforge.net/projects/pgfplots/. To this end you might need a sourceforge login. – Christian Feuersänger Feb 12 '15 at 22:35