# How can I automate the plotting of step functions?

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).

1. The vertical jump is sometimes plotted instead of just being a jump.
2. 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} {
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} {
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);
coordinates{(\s,\b)(\e,\val)};
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} {
}
\draw[dotted] (axis cs:0,0) -- (axis cs:0,1);
\draw[dotted] (axis cs:2,0) -- (axis cs:2,1);

% p_{j+1,6}
\foreach \xStart/\xEnd  in {3/3.5, 3.5/4} {
{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);

% p_{j,4}
\foreach \xStart/\xEnd  in {4/5, 5/6} {
{pj((x-4))*2};
}
\draw[dotted] (axis cs:4,0) -- (axis cs:4,2);
\draw[dotted] (axis cs:5,0) -- (axis cs:5,2);

\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!

• Have you looked at the jump mark left options for plot in TikZ? – Paul Stiverson Jun 24 '15 at 17:32
• Nice! I was not aware of that option! Indeed jump mark left solves the first problem. I'll add that to the question. – Lennart Jern Jun 24 '15 at 17:41

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:

\documentclass[border=3pt]{standalone}

\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.14}

\begin{document}
\def\lasty{}
\begin{tikzpicture}[
scale=1.5,
thick,
soldot/.style={color=blue,only marks,mark=*},
holdot/.style={color=blue,fill=white,only marks,mark=*}
]
\begin{axis}[xmin=-1, xmax=6, ymax=3.5]
\foreach \xStart/\xEnd/\yVal  in
{-1/0/0, 0/2/1, 2/3/0, 3/3.5/3, 3.5/4/0, 4/5/2, 5/6/0} {
\ifx\lasty\empty\else