9

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?

6
  • 1
    So you want to give TeX the factors of a function, have it decide when those factors are positive and negative, and deduce when the product is positive or negative? I think to do that right would require implementing or embedding a computer algebra system within TeX... Oct 5, 2011 at 18:49
  • Ofcourse something simpler. For instance, I would have no problems at all manually typing in where each factor is zero, and wheter it is right or left centered. I thought that was the purpose of this site? To discuss and give solutions to problems, as optimal as possible. And as you say the ideal solution seems impossible, I am therefore interested seeing how close one could get. For an examplethe polynom package can factor equations. =) Oct 5, 2011 at 18:55
  • For start, you may want to look at ctan.org/pkg/tkz-tab and ctan.org/pkg/tableaux Oct 5, 2011 at 23:23
  • Are you sure you want the line to go over the equations? I was a bit confused by this at first, because it makes the diagram look very much like a table, especially with the alignment of the x above the equations. Also, am I right in assuming that the first and second equation are swapped in your example pictures?
    – Jake
    Oct 6, 2011 at 1:50
  • 1
    @Jake The first and second equation were swapped. (I took the liberty of fixing that, as I wrote the bloody thing in the first place.) Oct 6, 2011 at 2:18

2 Answers 2

17

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}
14
  • 2
    Nice! There is a problem though, if the zero value is smaller than -3 or larger than 3 then the xmin/xmax and domain has to be redefined. Oct 6, 2011 at 0:29
  • @TorbjornT.: You're right, that could become a problem. I've added an optional argument for specifying the range.
    – Jake
    Oct 6, 2011 at 1:00
  • 1
    @N3buchadnezzar: ...and to change the 0 symbols to x, just change the line \node at (axis cs:##1,#3) [fill=white, inner sep=1pt] {0}; to \node at (axis cs:##1,#3) [fill=white, inner sep=1pt] {x};.
    – Jake
    Oct 6, 2011 at 8:22
  • 1
    @N3buchadnezzar: Sorry for the misunderstanding. I've added a bit of code that checks whether the function really evaluates to zero, and if it doesn't (such as when we divide by zero) an x is printed.
    – Jake
    Oct 6, 2011 at 23:34
  • 2
    @N3buchadnezzar: Like that? Don't hesitate to ask for adjustments - we've come this far, might as well do it properly. I would be interested in knowing what this is for, if you don't mind me asking. Are you a maths teacher?
    – Jake
    Oct 7, 2011 at 12:24
2

Change \functionallines to the following (five input arguments) to input list of points for undefined function. Just an extension of Jake's code.

\makeatletter
\newcommand\functionalline[5][\@empty]{
    \ifx#1\@empty
        \edef\equation{#2}
    \else
        \edef\equation{#1}
    \fi
    \edef\plots{
        \noexpand\addplot [negative, shift down=#3] {#2<0};
        \noexpand\addplot [positive, shift down=#3] {#2>0};
        \noexpand\node at (axis cs:\noexpand\pgfkeysvalueof{/pgfplots/xmin},#3)     [function label] {$\equation$};
    }
    \plots
    \pgfplotsinvokeforeach {#4} {
        \node at (axis cs:##1,#3) [fill=white, inner sep=1pt] {0};
    }   
    \pgfplotsinvokeforeach {#5} {
        \node at (axis cs:##1,#3) [fill=white, inner sep=1pt] {x};
    }   
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .