[Tex/LaTex] Defining a new command for making functional lines / package

diagramsequationspackagestikz-pgf

As you have probably guessed from the title my mother tounge is not English.
Therefore I have no idea if "Functional lines" is the correct term for what I am looking for.

Basically I am looking to make a command similar to the one below

\functionalines{3x}{x-4}{F_x = (3x)(x-4)}

Then the output should be similar to the tikz code below.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}

\begin{document}
\begin{tikzpicture}[%
negativ/.style={blue,dashed},
positiv/.style={red},
vertlinje/.style={dotted,opacity=.7},
node distance=1.5ex,
nullpunkt/.style={fill=white,inner sep= 1pt}]
  \draw [->,>=stealth] (-5,0) node (linestart) {} -- (5,0) node (lineend) {};
  \node (null1) at (-2,0) [label=above:-2] {};
  \node (null2) at (1,0) [label=above:1] {};
  \node [matrix] (produktledd) [below left=of linestart]{
    \node [left] (f1) {$x+2$}; \\
    \node [left] (f2) {$x-1$}; \\
    \node [left] (f)  {$f(x)= x^2+ x - 2$}; \\
   };
  \draw [vertlinje] (null1)       -- (null1 |- f);
  \draw [vertlinje] (null2)       -- (null2 |- f);
  \draw [positiv]   (null1 |- f1) -- (lineend |- f1);
  \draw [negativ]   (f1)          -- (null1 |- f1) node[nullpunkt] {$0$};
  \draw [negativ]   (null1 |- f)  -- (null2 |- f);
  \draw [positiv]   (null2 |- f2) -- (lineend |- f2);
  \draw [negativ]   (f2)          -- (null2 |- f2) node[nullpunkt] {$0$};
  \draw [positiv]   (f)           -- (null1 |- f)  node[nullpunkt] {$0$}
                (null2 |- f) node[nullpunkt] {$0$} -- (lineend |- f);
\end{tikzpicture}
\end{document}

A very good friend showed me this code =) Although there are a few small edits that would have been nice.
The top vectorline should be lowered a tad, and go over the equations. Above the equations and the vector there should be an x, indicating we are looking at the x-axis.
Preferably there should be a line below the equations, same length as the line above. Images below.
Is this possible to accomplish?

How the code looks

http://www.diskusjon.no/index.php?app=core&module=attach&section=attach&attach_rel_module=post&attach_id=461590

If I could get the output any way I want, I would want it to be like the one below.

enter image description here

So yeah, any idea, how to make a command which gives the desired output?

Best Answer

You could use PGFplots for this. By plotting functions using

 \addplot [restrict y to domain=0.5:inf] {(x-2)>0};

all coordinates that do not fulfill the condition will be discarded.

I've defined an environment functionallines of the form

\begin{functionallines}[<pgfplots arguments>]{<zero positions>}{<lower>:<upper>}

The <zero positions> argument takes a comma-separated list of x-values where any of the functions are zero or not defined. At these positions, a vertical line will be drawn through the function plots, and the positions will be printed in black at the top of the diagram. If you want to change the labels for these positions, use the <pgfplots arguments> to supply extra x tick labels={<first label>,<second label>,...}.

The optional argument can also be used for things like switching off the regular tick labels by setting xtick=\empty, or changing the drawing style of the functions by, for example, setting negative/.style={orange,dashed}, positive/.style={green, ultra thick}.

The <lower> and <upper> arguments define the x-range of the plot.

You can then add new lines using

\functionalline[<LaTeX math code>]{<expression>}{<vertical position>}{<list of zeros>}

where the optional argument [<LaTeX math code>] can be used to specify the code used to print the equation.

If the function evaluates to a nonreal value (divide by zero) at one of the zero positions, an x is printed instead of a 0.

Here are a couple of examples:

\begin{functionallines}{-1,1}{-2:2}
    \functionalline{x-1}{1}{1}
    \functionalline{x+1}{2}{-1}
    \functionalline[f(x) = \dfrac{(x-1)}{(x+1)}]{(x-1)/(x+1)}{3.5}{-1,1}
\end{functionallines}


\begin{functionallines}[
    xtick=\empty,
    negative/.style={orange,dashed},
    positive/.style={green, ultra thick}
    ]{0,90,180,270,360}{-20:380}
    \functionalline[\cos(x)]{cos(x)}{1}{90,270}
    \functionalline[\sin(x)]{sin(x)}{2}{0,180,360}
    \functionalline[\cos(x) \cdot \sin(x)]{cos(x) * sin(x)}{3}{0,90,180,270,360}
\end{functionallines}


Setting the labels for precise zero positions using extra x ticks labels, specifying the normal ticks using xtick={<list>} to avoid overlaps.

\begin{functionallines}[
    extra x tick labels={$\sqrt{5}$,$\pi$,$2\pi$},
    xtick={0,1,4,5}]{2.23,3.14,6.3}{0:6.5}
    \functionalline[x-\sqrt{5}]{x-2.23}{1}{2.23}
    \functionalline[\sin(x)]{sin(x*180/3.14)}{2}{3.14,6.28}
    \functionalline[(x-\sqrt{5})\cdot \sin(x)]{(x-2.23)*sin(x*180/3.14)}{3}{2.23,3.14,6.28}
\end{functionallines}


And here's the complete code:

\documentclass{article}
\usepackage{pgfplots}
\usepackage{amsmath}

\begin{document}

\pgfplotsset{
    shift down/.style={
         y filter/.code={\pgfmathparse{\pgfmathresult*(#1)}}
    },
    shift down/.default=1,
    every axis plot post/.style={restrict y to domain=0.5:inf},
    positive/.style={
        no markers,
        red
    },
    negative/.style={
        no markers,
        blue
    },
    /tikz/function label/.style={
        anchor=east
    },
    step functionallinenumber/.code={
        \stepcounter{functionallinenumber}
    },
    title entries/.initial={}
}

\makeatletter
\newcommand\functionalline[4][\@empty]{
    \edef\plots{
        \noexpand\addplot [negative, shift down=#3, forget plot] {#2<0};
        \noexpand\addplot [positive, shift down=#3, forget plot] {#2>0};
    }
    \plots
    \node at (axis cs:\pgfkeysvalueof{/pgfplots/xmin},#3) [function label] {%
        \ifx#1\@empty%
            $#2$%
        \else%
            $#1$%
        \fi
    };

    \pgfplotsinvokeforeach {#4} {
       \node at (axis cs:##1,#3) [
        fill=white,
        inner sep=1pt,
        declare function={x=##1;} % Set 'x' to current position
    ] {%
    \pgfkeys{/pgf/fpu}% Use the fpu library, because it doesn't throw an error for divide by zero, but sets result to +/- inf
    \pgfmathparse{#2}%
    \pgfmathfloatifflags{\pgfmathresult}{0}{\hspace{-0.75ex}0}{x}% Check whether result is zero. The \hspace is necessary because of a bug in the fpu library. (Update 11 June 2012: Doesn't seem to be the case anymore, the \hspace can be removed)
    \pgfkeys{/pgf/fpu=false}%
    };
    }   
}

\newenvironment{functionallines}[3][]{
    \begin{tikzpicture}
    \begin{axis}[        
        extra x ticks = {#2},
        grid=none,
        xticklabel pos=right,
        hide y axis,
        x axis line style={draw=none},
        every tick label/.style={
            anchor=base,
            yshift=1ex,
            gray!50
        },
        every extra x tick/.style={
            every tick label/.style={
                anchor=base,
                yshift=1ex,
                inner xsep=0pt,
                fill=white,
                text=black
            }
        },
        extra x tick style={grid=major},
        xtick pos=right,
        major tick length=0pt,
        enlarge x limits=false,
        enlarge y limits={abs=0.75},
        domain=#3,
        samples=100,
        y dir=reverse, y = -0.5cm,
        clip=false,
        #1
    ]
}{
    \coordinate (bottom right) at (rel axis cs:1,0);
    \coordinate (top right) at (rel axis cs:1,1);
    \end{axis}
    \draw [-latex] (top right-|current bounding box.west) -- (top right) node [right] {$x$};
    \draw (bottom right) -- (bottom right-|current bounding box.west);
    \end{tikzpicture}
}



\begin{functionallines}{-1,1}{-2:2}
    \functionalline{x-1}{1}{1}
    \functionalline{x+1}{2}{-1}
    \functionalline[f(x) = \dfrac{(x-1)}{(x+1)}]{(x-1)/(x+1)}{3.5}{-1,1}
\end{functionallines}

\hspace{1cm}

\begin{functionallines}[xtick=\empty]{0,90,180,270,360}{-20:380}
    \functionalline[\cos(x)]{cos(x)}{1}{90,270}
    \functionalline[\sin(x)]{sin(x)}{2}{0,180,360}
    \functionalline[\cos(x) \cdot \sin(x)]{cos(x) * sin(x)}{3}{0,90,180,270,360}
\end{functionallines}

\hspace{1cm}

\begin{functionallines}[
    extra x tick labels={$\sqrt{5}$,$\pi$,$2\pi$},
    xtick={0,1,4,5}]{2.23,3.14,6.3}{0:6.5}
    \functionalline[x-\sqrt{5}]{x-2.23}{1}{2.23}
    \functionalline[\sin(x)]{sin(x*180/3.14)}{2}{3.14,6.28}
    \functionalline[(x-\sqrt{5})\cdot \sin(x)]{(x-2.23)*sin(x*180/3.14)}{3}{2.23,3.14,6.28}
\end{functionallines}

\end{document}