# Piecewise defined function in tikz or tkz-fct

How to define and plot a piecewise defined function in tikz or tkz-fct? For example consider the function

f(x) = 1 for x < 0, x for 0 <= x < 1, cos(x) for x >= 1

Edit:

After Torbjørn T.'s comment I tried the following. I should mention that I included three different versions of plotting the function because I want that all three versions should work.

\documentclass{article}
\usepackage{amsmath}
\usepackage{pgfplots}
\usepackage{tkz-fct}

\pgfmathdeclarefunction{p}{3}{%
\pgfmathparse{(and(#1>#2, #1<#3))}%
}

\pgfmathdeclarefunction{f}{1}{%
\pgfmathparse{p(#1,-100,0)*1 + p(#1,0,1)*#1 + p(#1,1,100)*cos(#1r)}
}

\begin{document}

\begin{tikzpicture}
\tkzInit[xmin=-1,xmax=5,ymax=4] %
\tkzGrid %
\tkzAxeXY %
\tkzFct{f(x)} %
\draw plot function{f(x)};%
\begin{scope}[xshift=4cm]
\begin{axis}
\end{axis}
\end{scope}
\end{tikzpicture}

\end{document}


Which gives the following output:

-
Does this help? tex.stackexchange.com/questions/19510/… – Torbjørn T. Nov 3 '11 at 18:50
Thanks, I tried something with it, see edit above, but it doesn't work... – student Nov 3 '11 at 19:38
I can't test here (windows), but I presume you would want your r inside of the cos. Also this does not cover the cases where x=0 and x=1, although that should not cause too much problems. – Roelof Spijker Nov 3 '11 at 20:28
@wh1t3: Thanks, I put the r inside of the cos now – student Nov 3 '11 at 21:40

There are a few problems with the code:

1. PGF uses degrees for trig functions
2. Seems that the r at the end of the function f was intended to convert from radians to degree, but I changed it so that it is more obvious.
3. Need to determine what happens at the end points of the piecewise domain, so note the slight tweaks for that.
4. Not sure what the tkz portion of the code has to do with the problem of defining a piecewise function, so have commented that out.
5. Be careful using single letter function names as documented in: Why do 2 identical function definitions with different names produce two different plots?

So, with slight modifications to your code I can produce the following. Note that there still is a problem around x=1 as pgf does not know what to do.

\documentclass[border=2pt]{standalone}
\usepackage{amsmath}
\usepackage{pgfplots}
\usepackage{tkz-fct}

\pgfmathdeclarefunction{p}{3}{%
\pgfmathparse{(and(#1>#2, #1<#3))}%
}

\pgfmathdeclarefunction{f}{1}{%
\pgfmathparse{p(#1,-100,-0.001)*1 + p(#1,0,1)*#1 + p(#1,1.01,100)*cos(deg(#1))}%
}

\begin{document}
\begin{tikzpicture}
%   \tkzInit[xmin=-1,xmax=5,ymax=4] %
%   \tkzGrid %
%   \tkzAxeXY %
%   \tkzFct{f(x)} %
%   \draw plot function{f(x)};%
\begin{scope}[xshift=6cm]
\begin{axis}
\end{axis}
\end{scope}
\end{tikzpicture}
\end{document}


What I would recommend is that you draw the three separate portions individually and avoid the problem areas via a fixed value of \Tolerance:

\documentclass[border=2pt]{standalone}
\usepackage{amsmath}
\usepackage{pgfplots}
\usepackage{tkz-fct}

\pgfmathdeclarefunction{p}{3}{%
\pgfmathparse{(and(#1>#2, #1<#3))}%
}

\newcommand{\Tolerance}{0.0001}%
\pgfmathdeclarefunction{f}{1}{%
\pgfmathparse{%
p(#1,-\maxdimen,-\Tolerance)*1.0 +%
p(#1,0,1-\Tolerance)*#1 +%
p(#1,1,\maxdimen)*cos(deg(#1))}%
}

\begin{document}
\begin{tikzpicture}
%   \tkzInit[xmin=-1,xmax=5,ymax=4] %
%   \tkzGrid %
%   \tkzAxeXY %
%   \tkzFct{f(x)} %
%   \draw plot function{f(x)};%
\begin{scope}[xshift=6cm]
\begin{axis}
\end{axis}
\end{scope}
\end{tikzpicture}
\end{document}


To clarify, the \addplot calls above are really just:

\addplot[ultra thick, blue, domain=-2.0000:-0.0001, samples=100]{f(x)};
\addplot[ultra thick, green,domain= 0.0001: 0.9999, samples=100]{f(x)};
\addplot[ultra thick, red,  domain= 1.0001: 4.0000, samples=100]{f(x)};

-
The tkz portion is because I want also be able to plot those functions using tkz-fct. – student Nov 3 '11 at 21:33
@Peter Grill Thanks, your second picture looks fine, however the source code looks pretty complicated. I want a solution where I have a simple syntax to plot much more complicated piecewise defined functions, too. – student Nov 3 '11 at 21:45
I too am looking for that since I posted the question you referred to in your posting. But I think the second one looks more complicated as I defined \Tolerance so it was easy to adjust. – Peter Grill Nov 3 '11 at 21:48

I would use the ifthenelse structure (available in tikz and in gnuplot).

\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\begin{document}

% plain tikz + ifthenelse:
\begin{tikzpicture}[scale=3]
\draw[blue,thick] plot[samples=200,domain=-2:4] (\x,{ifthenelse(\x <
0,1,ifthenelse(and(\x >= 0,\x < 1),\x, cos(deg(\x))))});
\draw[red,thick,semitransparent] plot[samples=200,domain=-2:4]
(\x,{cos(deg(\x))});
\end{tikzpicture}

% pgfplots + gnuplot:
\begin{tikzpicture}
\begin{axis}
\addplot+[samples=150,domain=-2:4] function {x < 0 ? 1 : ((x >=0)
&& (x<1)) ? x : cos(x)};
\end{axis}
\end{tikzpicture}

% plain tikz with '?' operator:
\begin{tikzpicture}[scale=3]
\draw plot[samples=200,domain=-2:4] (\x,{\x < 0 ? 1 : (((\x >=0)
&& (\x<1)) ? \x : cos(deg(\x)))});
\end{tikzpicture}

% pgfplots without gnuplot: (requires developer version of pgf or pgfplots):
\begin{tikzpicture}
\begin{axis}
\addplot[blue,samples=150,domain=-2:4] {x < 0 ? 1 : (((x >=0)
&& (x<1)) ? x : cos(deg(x)))};
\end{axis}
\end{tikzpicture}
\end{document}


-
This does not appear to be using the cos function for x>1. – Peter Grill Nov 3 '11 at 20:39
@PeterGrill It does (see my updated answer), but I did not believe it either! – cjorssen Nov 3 '11 at 20:53
The OP used domain=-2:4 so probably best to stick to that domain so that the results are easy to compare. – Peter Grill Nov 3 '11 at 21:20
@cjorssen I like your answer. I took the freedom to add variants using the ? operator as well. And by the way: I found that \usetikzlibrary{fpu} (which is used by pgfplots), did not properly support it. I have just comitted support for ==, !=, <=, >=, ? to pgf CVS. The last example will only compile with this commit. – Christian Feuersänger Nov 3 '11 at 21:24
@ChristianFeuersänger Thanks! I was investigating to understand why it didn't work for me. I changed the domain to stick to the OP one. – cjorssen Nov 3 '11 at 21:37

Run with xelatex

%f(x) = 1 for x < 0, x for 0 <= x < 1, cos(x) for x >= 1

\documentclass{article}
\pagestyle{empty}
\begin{document}
\begin{pspicture}(-1,-1)(7,1)
\psplot[algebraic,linecolor=red,plotpoints=1000,
linewidth=1pt]{-1}{7}{IfTE(x<0,1,IfTE(x<1,x,cos(x)))}
\end{pspicture}
\end{document}


-

I slightly modified @Herbert's code to make the graph of f (visually) "a graph of a function". It still has few quirks.

\documentclass{article}