I'm using a lot of step functions in my master's thesis and would like to automate the plotting. I can get them to look just as I want by hand using this method, but when I try to automate it like this there are two problems (see picture).
- The vertical jump is sometimes plotted instead of just being a jump.
- The dotted lines to indicate vertical jumps are only drawn the last time I call the command.
How can I fix this?
In the \stepfunction
command I define the function to be plotted locally in the for-loop. Like this:
\foreach \xStart/\xEnd in {\minx/\s, \s/\e, \e/\maxx} {
\addplot[domain=\xStart:\xEnd, blue, ultra thick,
declare function={
pj(\x) = and(\x >= \s, \x < \e)*(\val) +
and(\x >= \e, 1)*(\b) +
and(1, \x < \s)*(\b);}]
{pj(x)};
Is this a good idea? I want to be able to draw many functions in a single picture so I can't put the whole axis environment in the newcommand, right?
Code
\documentclass[border=3pt]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.9}
\pgfkeys{
stepfunction/.is family,
stepfunction,
plotstart/.initial=0,
plotend/.initial=5,
start/.initial=1,
end/.initial=2,
value/.initial=1,
base/.initial=0
}
\newcommand\stepfunctionset[1]{\pgfkeys{stepfunction,#1}}
\newcommand\stepfunction[1][]{
\stepfunctionset{#1,
plotstart/.get=\minx,
plotend/.get=\maxx,
start/.get=\s,
end/.get=\e,
value/.get=\val,
base/.get=\b
}
% plot from \minx to \maxx
\foreach \xStart/\xEnd in {\minx/\s, \s/\e, \e/\maxx} {
\addplot[domain=\xStart:\xEnd, blue, ultra thick,
declare function={
pj(\x) = and(\x >= \s, \x < \e)*(\val) +
and(\x >= \e, 1)*(\b) +
and(1, \x < \s)*(\b);}]
{pj(x)};
};
\draw[dotted] (axis cs:\s,\b) -- (axis cs:\s,\val);
\draw[dotted] (axis cs:\e,\b) -- (axis cs:\e,\val);
\addplot[color=blue,fill=white,only marks,mark=*]
coordinates{(\s,\b)(\e,\val)};
\addplot[color=blue,only marks,mark=*]
coordinates{(\s,\val)(\e,\b)};
}
\begin{document}
\begin{tikzpicture}[scale=1.5, thick]
\begin{axis}[xmin=-1, xmax=6, ymax=3.5]
% p_{j-1,1}
\stepfunction[plotstart=-1, plotend=2.5,
start=0, end=2, value=1, base=0]
% p_{j+1,6}
\stepfunction[plotstart=2.5, plotend=3.75,
start=3, end=3.5, value=3, base=0]
% p_{j,4}
\stepfunction[plotstart=3.75, plotend=6, start=4, end=5, value=2]
\end{axis}
\end{tikzpicture}
% Plot by hand
\begin{tikzpicture}[
scale=1.5,
thick,
soldot/.style={color=blue,only marks,mark=*},
holdot/.style={color=blue,fill=white,only marks,mark=*},
declare function={
pj(\x)=and(\x >= 0, \x < 1)*(1) +
and(\x >= 1, 1)*(0) +
and(1, \x < 0)*(0);
}]
\begin{axis}[xmin=-1, xmax=6, ymax=3.5]
% p_{j-1,1}
\foreach \xStart/\xEnd in {-1/0, 0/2, 2/3} {
\addplot[domain=\xStart:\xEnd, blue, ultra thick] {pj(0.5*x)};
}
\draw[dotted] (axis cs:0,0) -- (axis cs:0,1);
\draw[dotted] (axis cs:2,0) -- (axis cs:2,1);
\addplot[holdot] coordinates{(0,0)(2,1)};
\addplot[soldot] coordinates{(0,1)(2,0)};
% p_{j+1,6}
\foreach \xStart/\xEnd in {3/3.5, 3.5/4} {
\addplot[domain=\xStart:\xEnd, blue, ultra thick]
{pj(2*(x-3))*3};
}
\draw[dotted] (axis cs:3,0) -- (axis cs:3,3);
\draw[dotted] (axis cs:3.5,0) -- (axis cs:3.5,3);
\addplot[holdot] coordinates{(3,0)(3.5,3)};
\addplot[soldot] coordinates{(3,3)(3.5,0)};
% p_{j,4}
\foreach \xStart/\xEnd in {4/5, 5/6} {
\addplot[domain=\xStart:\xEnd, blue, ultra thick]
{pj((x-4))*2};
}
\draw[dotted] (axis cs:4,0) -- (axis cs:4,2);
\draw[dotted] (axis cs:5,0) -- (axis cs:5,2);
\addplot[holdot] coordinates{(4,0)(5,2)};
\addplot[soldot] coordinates{(4,2)(5,0)};
\end{axis}
\end{tikzpicture}
\end{document}
Edit
Using the option jump mark left
for plotting solves the first problem and makes the foor-loop unnecessary:
% plot from \minx to \maxx
\addplot[domain=\minx:\maxx, blue, ultra thick, jump mark left,
declare function={
pj(\x) = and(\x >= \s, \x < \e)*(\val) +
and(\x >= \e, 1)*(\b) +
and(1, \x < \s)*(\b);}]
{pj(x)};
Thanks Paul Stiverson!
Best Answer
rather than specify the step function as a sum of booleans, seems easier to specify it as a list of start/end/value triplets and then just loop through: