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?
  • 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? – user121799 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? – user121799 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
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. – user121799 Jan 19 '19 at 22:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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