6

I'm trying to use if in my TikZ picture. For example, I want to draw a point at the origin only if 1 < 2. I can do it, for example, like this:

\begin{tikzpicture}
    if 1 < 2 then
        \fill (0, 0) circle (1pt);
\end{tikzpicture}

And this code works. But if I try to use if in a loop, then everything stops working. For example, the following code will draw 5 dots instead of 1

\begin{tikzpicture}
    \foreach \i in {1, ..., 5}
        if \i < 2 then
            \fill (\i, 0) circle (1pt);
\end{tikzpicture}

What am I doing wrong and how do I make the code work correct?

The only thing I could find on the Internet is this answer, based on which the desired can be achieved as follows, but the code turns out to be too cumbersome.

\begin{tikzpicture}
    \foreach \i in {1, ..., 5} {
        \pgfmathparse{ifthenelse(\i<2, 1, 0)}
        \ifodd\pgfmathresult\relax
            \fill (\i, 0) circle (1pt);
        \fi
    }
\end{tikzpicture}
  • It's a bit surprising that you even come up with the first code snippet at all. In any case, if you know how to program in TeX (which is a... hard... task) you can make your interface as natural as you want. Knuth's interface of TeX is pretty natural but need special handling, most LaTeX interfaces are not necessarily as "unnatural" – user202729 May 27 '22 at 16:46
  • As it was noted in one of the answers to this question, the syntax was incorrect and TikZ simply ignored it. – Alexey Ismagilov May 27 '22 at 17:43

4 Answers4

8

I can offer a more flexible set of functions, see https://tex.stackexchange.com/a/467527/4427

\documentclass{article}
\usepackage{tikz}

\ExplSyntaxOn \NewExpandableDocumentCommand{\xifthenelse}{mmm} { \bool_if:nTF { #1 } { #2 } { #3 } }

\cs_new_eq:NN \numtest \int_compare_p:n \cs_new_eq:NN \oddtest \int_if_odd_p:n \cs_new_eq:NN \fptest \fp_compare_p:n \cs_new_eq:NN \dimtest \dim_compare_p:n \cs_new_eq:NN \deftest \cs_if_exist_p:N \cs_new_eq:NN \namedeftest \cs_if_exist_p:c \cs_new_eq:NN \eqdeftest \token_if_eq_meaning_p:NN \cs_new_eq:NN \streqtest \str_if_eq_p:ee \cs_new_eq:NN \emptytest \tl_if_empty_p:n \cs_new_eq:NN \blanktest \tl_if_blank_p:n \cs_new_eq:NN \boolean \legacy_if_p:n \cs_new:Npn \modetest #1 { \str_case:nnF { #1 } { {h}{\mode_if_horizontal_p:} {v}{\mode_if_vertical_p:} {m}{\mode_if_math_p:} {i}{\mode_if_inner_p:} } {\c_false_bool} } \cs_new:Npn \enginetest #1 { \str_case:nnF { #1 } { {luatex}{\sys_if_engine_luatex_p:} {pdftex}{\sys_if_engine_pdftex_p:} {ptex}{\sys_if_engine_ptex_p:} {uptex}{\sys_if_engine_uptex_p:} {xetex}{\sys_if_engine_xetex_p:} } {\c_false_bool} }

\ExplSyntaxOff

\begin{document}

\begin{tikzpicture} \foreach \i in {1,...,8}{ \xifthenelse{\numtest{ 2 <= \i < 5 }} { \fill (\i, 0) circle (1pt); } { \draw (\i, 0) circle (1pt); } } \foreach \i in {1,...,8}{ \xifthenelse{ \numtest{ 3 < \i < 6 } || \numtest{ \i>7 } } { \fill (\i, 1) circle (1pt); } { \draw (\i, 1) circle (1pt); } } \end{tikzpicture}

\end{document}

enter image description here

egreg
  • 1,121,712
6

The package ifthen has the most natural syntax (in my opinion).

\ifthenelse{<boolean>}{<do this if true>}{<do this if false>}

Note that to use \foreach, you must enclose the loop in braces unless it is a single tikz command (e.g., \draw).

enter image description here

\documentclass{article}

\usepackage{tikz,ifthen}

\begin{document}

\begin{tikzpicture} \foreach \i in {1, ..., 5}{ \ifthenelse{\i < 3}{\fill (\i, 0) circle (1pt);}{} } \end{tikzpicture}

\end{document}

Sandy G
  • 42,558
4

Try the following:

\documentclass[margin=3mm]{standalone}
\usepackage{tikz}

\begin{document} \begin{tikzpicture}
\foreach \i in {1, ..., 5} { % <--- \ifnum \i < 3 % <---
\fill (\i, 0) circle (1pt); \fi % <--- } % <--- \end{tikzpicture} \end{document}

enter image description here

or

\documentclass[margin=3mm]{standalone}
\usepackage{tikz}

\begin{document} \begin{tikzpicture}
\foreach \i in {1, ..., 5} {
\ifnum \i < 3
\fill (\i, 0) circle (1pt); \else \draw (\i, 0) circle (1pt); \fi } \end{tikzpicture} \end{document}

enter image description here

Zarko
  • 296,517
3

Note that TikZ in OP's code

\begin{tikzpicture}
    if 1 < 2 then
        \fill (0, 0) circle (1pt);
\end{tikzpicture}

TikZ ignores if 1 < 2 then since it is incorrect syntax; in fact if you write inverse inequality if 1 > 2 then, then the code still works with the same output. TikZ ignores some incorrect syntax error. It is not the case of Asymptote.

I see that the question is interesting. I am going to share some personal feeling about programming/drawing with TikZ, in comparison with Asymptote. Let's start with a code example in pgfmanual, Section 88 Repeating Things: The Foreach Statement.

enter image description here

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\foreach \x in {1,...,4}
\foreach \y in {1,...,4}
{
    \fill[red!50] (\x,\y) ellipse (3pt and 6pt);
    \ifnum \x<\y
    \breakforeach
    \fi
}
\end{tikzpicture}
\hspace*{5mm}
\begin{tikzpicture}
\foreach \x in {1,...,4}
\foreach \y in {1,...,4}
{
    \ifnum \x>\y
    \fill[blue!50] (\x,\y) ellipse (3pt and 6pt);
    \fi
    \ifnum \x=\y
    \fill[cyan!50] (\x,\y) ellipse (3pt and 6pt);
    \fi
    \pgfmathparse{\y-1}
    \ifnum \x=\pgfmathresult
    \fill[magenta!50] (\x,\y) ellipse (3pt and 6pt);
    \fi
}
\end{tikzpicture}
\hspace*{5mm}
\begin{tikzpicture}
\foreach \x in {1,...,4}
\foreach \y in {1,...,4}
{
\pgfmathparse{\x>=\y-1}
\ifnum \pgfmathresult=1
    \fill[violet!50] (\x,\y) ellipse (3pt and 6pt);
\fi
}
\end{tikzpicture}
\end{document}

Appendix

enter image description here

// http://asymptote.ualberta.ca/
unitsize(1cm);
int n=5;
for(int i=1;i<n;++i)
for(int j=1;j<n;++j)
if (i>=j-1) fill(ellipse((i,j),3pt/cm,6pt/cm),orange);

(to be continued)

Black Mild
  • 17,569