4

I have a time series with values for x0 and x1. Depending on their distance, the system is in a specific state. Whenever the system is in the state 1, this should be highlighted with a colored background for all x values. The calculation for that state has been done and is offered in a third column called state.

The result should look similar to this:

The intended final output

Solution

In the following MWE, I added the red background "manually", i.e., I plotted the edges of a square for the area in question and used fillbetween to fill the area in between with a.

The grey'ish background is the result of my "programmatically" attempt. I plot two lines (A at xmax=1 and B at xmin=-1) along the y axis. I use x expr to only plot the coordinates where state=1 and skip others with assigning x=nan and y=nan.

I then use again fillbetween for filling the area in between these two plots. However, neither unbounded coords = discard nor unbounded coords = jump yields in two segments (like the image above), but the whole background between the segments is filled too.

\documentclass{article}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{filecontents}

\usetikzlibrary{patterns}
\usepgfplotslibrary{fillbetween}

\begin{filecontents}{servo.data}
t     x0      x1    state
1    0.1     0.1    0
2    0.2     0.2    0
3    0.4    -0.2    1
4    0.5    -0.8    1
5      0     0.1    0
6      0     0.1    0
7      0     0.0    0
8      0    -0.1    0
9   -0.4     0.9    1
10  -0.4     0.8    1
11     0    -0.1    0
12   0.1    -0.1    0
13  -0.1    -0.1    0
\end{filecontents}

\begin{document}
\begin{tikzpicture}
\begin{axis}[xmax=1, xmin=-1]

  \addplot table[x = x0, y = t]{servo.data};
  \addplot table[x = x1, y = t]{servo.data};

    % manually adding background    
    \addplot [draw=none,pattern = north east lines, pattern color=red] 
    coordinates {(-1, 3) (1, 3) (1, 4) (-1, 4)};

    \addplot [draw=none,pattern = north east lines, pattern color=red] 
    coordinates {(-1, 9) (1, 9) (1, 10) (-1, 10)};

  % programmatically
    \addplot[name path=A] table [x expr={\thisrow{state}==1?1:nan}, y expr={\thisrow{state}==1?\thisrow{t}:nan}]{servo.data};
    \addplot[name path=B] table [x expr={\thisrow{state}==1?-1:nan}, y expr={\thisrow{state}==1?\thisrow{t}:nan}]{servo.data};

    \addplot[pattern=north east lines]
  fill between[
    of=A and B,
  ];

\end{axis}
\end{tikzpicture}
\end{document}

The output of the above MWE:

MWE output

Questions

  1. Is it possible to achieve the intended output (top image) with using fillbetween?
  2. How can I make this more efficient? For example, instead of using fillbetween, can I retrieve the edges of the area in question and plot the background individually?
Marcus
  • 383
  • I am sorry, I do not understand some things here. Above the first screen shot you write "The reuslt should look simlar to this (without the grey background):" but there is no visible gray background, is there? And what should happen if there is only one row with a 1 in it? What should happen above and below the red stripes? –  Jan 19 '19 at 21:15
  • That was indeed a left over from before, where I used the MWE image for explaining what I want. I want only the rows with stage=1 to be marked, other rows should not have any special treatment. – Marcus Jan 19 '19 at 21:18
  • Sorry, this is still not entirely clear to me. In your example, there always two successive rows with 1 and you mark/shade the interval between them. Is that what you want, or do you want shade an interval around each of these points? –  Jan 19 '19 at 21:22
  • I haven't considered the "one row" case at all (it can happen though). I want to mark only the interval between rows of state=1 and I am fine if a one row case is ignored/doesn't show up. An optional area around the interval is nice too. I will clarify the question – Marcus Jan 19 '19 at 21:36

1 Answers1

2

Something like this? (I am not sure I read your question correctly because the screen shot you show and the instructions seem to not match perfectly, but this may only be me thinking that.)

\documentclass{article}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.16}
\usetikzlibrary{calc,patterns}
\usepackage{filecontents}

\begin{filecontents}{servo.data}
t     x0      x1    state
1    0.1     0.1    0
2    0.2     0.2    0
3    0.4    -0.2    1
4    0.5    -0.8    1
5      0     0.1    0
6      0     0.1    0
7      0     0.0    0
8      0    -0.1    0
9   -0.4     0.9    1
10  -0.4     0.8    1
11     0    -0.1    0
12   0.1    -0.1    0
13  -0.1    -0.1    0
\end{filecontents}
\xdef\lstColors{{"black","red"}}
\tikzset{set pattern color/.code={\pgfmathparse{\lstColors[#1]}
\pgfkeysalso{/tikz/pattern color=\pgfmathresult}
}}
\pgfdeclareplotmark{rect}
{%
\path let \p1=($(1,1)-(0,0)$) in 
node [minimum width={\x1*(\pgfkeysvalueof{/pgfplots/xmax}-\pgfkeysvalueof{/pgfplots/xmin})},
minimum height=1.02*\y1,pattern=north east lines,yshift=-0.51*\y1]{};
}%
\begin{document}
\begin{tikzpicture}
\begin{axis}[xmax=1, xmin=-1]
      \addplot [
        scatter,only marks,mark=rect,
        visualization depends on={\thisrow{state} \as \mystate},
        scatter/@pre marker code/.append style=
            {/tikz/set pattern color=\mystate},
    ]
        table [x expr={0}, y=t]{servo.data};
  \addplot table[x = x0, y = t]{servo.data};
  \addplot table[x = x1, y = t]{servo.data};

\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

I still have problems understanding what the desired output should look like. Perhaps like this?

\documentclass{article}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.16}
\usetikzlibrary{calc,patterns}
\usepackage{filecontents}

\begin{filecontents}{servo.data}
t     x0      x1    state
1    0.1     0.1    0
2    0.2     0.2    0
3    0.4    -0.2    1
4    0.5    -0.8    1
5      0     0.1    0
6      0     0.1    0
7      0     0.0    0
8      0    -0.1    0
9   -0.4     0.9    1
10  -0.4     0.8    1
11     0    -0.1    0
12   0.1    -0.1    0
13  -0.1    -0.1    0
\end{filecontents}
\tikzset{switch/.code={\xdef\myopa{#1}}}
\pgfdeclareplotmark{rect}
{%
\path let \p1=($(1,1)-(0,0)$) in 
node [minimum width={\x1*(\pgfkeysvalueof{/pgfplots/xmax}-\pgfkeysvalueof{/pgfplots/xmin})},
minimum height=\y1,pattern=north east lines,pattern color=red,opacity=\myopa]{};
}%
\begin{document}
\begin{tikzpicture}
\begin{axis}[xmax=1, xmin=-1]
      \addplot [
        scatter,only marks,mark=rect,
        visualization depends on={\thisrow{state} \as \mystate},
        scatter/@pre marker code/.append style=
            {/tikz/switch=\mystate},
    ]
        table [x expr={0}, y=t]{servo.data};
  \addplot table[x = x0, y = t]{servo.data};
  \addplot table[x = x1, y = t]{servo.data};

\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

  • thank you for your answer, I think that is the way to got for answering my second question. The background in your example is also "red" for t=5 and t=11 although state=0, but I think I get the idea is clear (I also tried to clearify my question). – Marcus Jan 19 '19 at 21:11
  • I think the last example a good answers for question 2. Personally I think using pgfdeclareplotmark smells a bit hacky, but I don't have much experience with pgf. One issue coming up though is that I cannot use addlegendentry. – Marcus Jan 19 '19 at 21:55
  • @Marcus I do not know if \pgfdeclareplotmark is hacky, at least here it is used by a very experienced user. And for instance the answers to this question provide ways to add legend entries with customized entries, so I do not think that's a problem either. –  Jan 19 '19 at 22:02