I need a function that, given starting and ending point, some points that can be both included and excluded and a starting sign, it will draw a line, circles in place of those points (black filled if included, white filled if excluded) and the + or - sign. Basically I need something like

except with + signs before and after 0 and 3 and with the ability to choose whether or not those points are included in the domain of the function.

What I currently have is

\documentclass[a4paper]{article}

\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.11}
\usepgfplotslibrary{fillbetween}
\usetikzlibrary{
arrows,
decorations,
calc,
intersections,
matrix,
decorations.pathmorphing,
spy,
}

\newcommand\signplot[4]{ % start end points signStart
% Draws a line between #1 and #2
\draw[shorten <= -1cm, shorten >= -1cm] (#1) -- (#2);

% Checking whether the first sign is positive or not
\ifnum1=#4\relax % It starts positive
% Cycle between the list of points given at which the sign changes
\foreach \x in #3{
% Drawing circles with the text
\coordinate (A) at (#1);
\coordinate (B) at (\x,0);
\filldraw[fill=black,draw=black] (A-|B) circle(2pt)
node[below]{\x};
% Going through 0->\x (where \x = current coordinate) with a step of 0.3
\foreach \c in {0,0.3,0.6,...,\x}{
\coordinate (A1) at ($(A)+(-1cm,0)$);
% Drawing the + sign above the line
\coordinate (C) at ($(A1-|B)+(0,0.2)$);
\coordinate (D) at (\c,0);
\node at (C-|D) {+};
}
}
\else % Same as above
\foreach \x in #3{
\coordinate (A) at (#1);
\coordinate (B) at (\x,0);
\filldraw[fill=black,draw=black] (A-|B) circle(2pt)
node[below]{\x};
\foreach \c in {0.3,0.6,...,\x}{
% Just drawing the - sign below
\coordinate (C) at ($(A-|B)+(0,-0.2)$);
\coordinate (D) at (\c,0);
\node at (C-|D) {-};
}
}
\fi
}

\begin{document}
\begin{tikzpicture}
\coordinate (O) at (0,0);
\coordinate (A) at (5,0);
\signplot{O}{A}{{0,3}}{0}
\end{tikzpicture}
\end{document}


As you can see I'm not handling the cases where there is more than 2 points since this happens

and in reality the sign should + above the line.

So if by chance there is an automatic way of "inverting" the sign and its position each time a new point is given, how would I do it? Also as you can see I am not handling not-in-domain points and drawing all of them black. As a side note, is there an automatic way of getting the sign of a function, given the function? It could be useful to have another command just for that.

Sorry if my explanation is not the best but I can't find the right words. Here is in the end what it should look like

Thanks for any help creating this command. I'm still quite new to command creation and conditionals so please, explain so I can do other things on my own. Thanks for reading.

Edit: After some research and some help from @marmot , I created a function that does what I need, in the end. Here it is

\newcommand{\mysign}[1]{
\pgfmathtruncatemacro\tmpsign{sign(#1)}
\ifnum\tmpsign<0
-
\else
\ifnum\tmpsign>0
+
\else
\relax
\fi
\fi
}

\newcommand{\drawSign}[6][]{% f(x) xmin xmax delta exclpoints
\begin{scope}[#1,declare function={Test(\x) = #2;}]
\draw [->, thick] (#3,0) -- (#4,0)node[right] {$x$};
\pgfmathsetmacro{\NextI}{#3+#5}
\foreach \i in {#3,\NextI,...,#4}{
\node at (\i,{0.35*sign(max(min(Test(\i),1),-1))}) {$\mysign{Test(\i)}$};
\pgfmathtruncatemacro\signum{sign(Test(\i))}
\ifnum\signum=0
\filldraw[black] (\i,0) circle(2pt);
%\node[circle,fill,maximum size=2pt] at (\i,0){};
\node[below] at (\i,-0.2){$\i$};
\fi
}
\ifx&#6&%
\else
% Excluded points
\foreach \x in #6{
\filldraw[fill=white,draw=black] (\x,0) circle(2pt);
\node[below] at (\x,-0.2) {$\x$};
}
\fi
\end{scope}
}


And now the plot for the function \drawSign{(\x^2-5*\x+4)/(\x-5+0.001)}{-2}{7}{0.25}{5} is

which is the desired result.

If there is an automatic way of knowing the zeroes of the function, it would be fantastic you shared it! Thanks for reading.

\documentclass{article}
\usepackage{pgfplots}
\usepackage{amsmath}
\newcommand{\mysign}[1]{\pgfmathtruncatemacro\tmpsign{sign(#1)}
\ifnum\tmpsign<0
-
\else\ifnum\tmpsign>0
+
\else
\relax
\fi
\fi
}

\begin{document}
The basic idea is to define a function that changes its signs at some locations.
Call the locations $x_1,\dots x_n$, then a convenient choice of the function is
$T(x)~=~\pm\prod\limits_{i=1}^n(x_i-x_n)$
and this function is called \texttt{Test} in the snippet below. In addition, one
may want to introduce a function
$\backslash\texttt{mysign}(x)~=~\left\{\begin{array}{ll} + &\text{if}~x>0\;,\\ - &\text{if}~x<0\;,\\ \backslash\texttt{empty} & \text{if}~x=0\;. \end{array}\right.$
Then one can simply plot the combination of these functions.\\[1cm]
\begin{tikzpicture}[scale=1.5,
declare function={Test(\i) = \i*(3-\i)*(\i-4);}]
\draw [->, thick] (-2,0) -- (7.5,0)node[right] {$x$};
\foreach \i in {-2,-1.75,...,7}
{
\node at (\i,{0.35*sign(Test(\i))}) {$\mysign{Test(\i)}$};
\pgfmathtruncatemacro\signum{sign(Test(\i))}
\ifnum\signum=0
\node[circle,fill,minimum size=2pt] at (\i,0){};
\node[below] at (\i,-0.2){$\i$};
\fi
}
\end{tikzpicture}

One may also write a function for that,
$\backslash\texttt{DrawSign}\{f(\backslash x)\}\{x_\mathrm{min}\} \{x_\mathrm{max}\}\{\Delta x\}$, see below.\\[1cm]
\newcommand{\DrawSign}[5][]{\begin{scope}[#1,declare function={Test(\x) = #2;}]
\draw [->, thick] (#3,0) -- (#4,0)node[right] {$x$};
\pgfmathsetmacro{\NextI}{#3+#5}
\foreach \i in {#3,\NextI,...,#4}
{
\node at (\i,{0.35*sign(Test(\i))}) {$\mysign{Test(\i)}$};
\pgfmathtruncatemacro\signum{sign(Test(\i))}
\ifnum\signum=0
\node[circle,fill,minimum size=2pt] at (\i,0){};
\node[below] at (\i,-0.2){$\i$};
\fi
}
\end{scope}
}
\begin{tikzpicture}
\DrawSign[scale=1.5]{(\x-1)*(\x+3)}{-5}{3}{0.25}
\end{tikzpicture}
\end{document}


Based on this post.

• That looks great but I have a couple of more questions: if I wanted it to be a command I can run, how can I pass the function to the environment? Also, how can I distinguish in-domain points from the ones that are excluded? For example if your Test function became \i*(\i-3)/(\i-4) it would crash because 4 is not in the domain. I like then to change | to use filled/empty circles, as shown in the pictures. Thanks anyways for pointing me in the right direction! – gjkf Jan 22 '18 at 20:09
• You may try passing the function by passing a declare function to a scope. But personally I would just pass the zeros and construct the function from it. Why would you want to use a singular function? (I'm not aware of any way to teach TikZ to deal with singularities other than throwing errors.) And I will fix the bullet. – user121799 Jan 22 '18 at 20:13
• I'm just used to making a method the most general possible. My ideal situation would be something along the lines of \signplot{(3-x)/(1-x^2)+3x} and it does all the work but I gather not being the easiest thing. Of course I could just pass the zeroes and then constructing the function. That i will do if there is no other way. And for the bullets and not-in-domain points, I gather either I catch the errors, if possible or find other manual ways. – gjkf Jan 22 '18 at 20:20
• @gjkf OK, I added a function. (I also tried to avoid singularities by wrapping the function into min and max like max(min(Test(x),1),-1), but this didn't work, the function was, not surprisingly, evaluated first before getting cut. If you ever find a way, please let me know ;-) – user121799 Jan 22 '18 at 21:11
• That is just lovely! Many thanks! I will look deeper and try and find a way to detect singularities but I feel like it is not going to be easy. Thanks again for your awesome help! – gjkf Jan 23 '18 at 8:19