1

I am currently trying to create an image of randomly distributed points in a unit-square. I would like to draw these points in a given color if they are inside the inscribed circle, or in another, otherwise.

Here is what I have, without the condition set up.

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

\begin{document}
\begin{tikzpicture}
\fill[blue!10!white] (1,1) circle (1);
\draw[very thick] (0,0) -- (0,2) -- (2,2) -- (2,0) -- cycle;
\foreach \i in {1,...,50}{
    \tikzmath{\xa=rand;}
    \tikzmath{\ya=rand;}
    \tikzmath{\eval=int(\xa^2+\ya^2 - 1.0);}
    \fill[red!60!white](\xa+1, \ya+1) circle(1.5pt);
}
\end{tikzpicture}
\end{document}

I would like to have the fill/circle instruction have a color option that is dependent on the value of \eval, defined just above. For example: If \eval > 0 use [red!60!white], Otherwise, use [blue!60!white]

I tried using \ifthenelse, but am facing errors due (I think?) to the fact I am putting a condition on a float, and ifthenelse is limited to integers.

I also tried putting the fill/circle instruction inside a tikzmath environment, and having the condition set inside, but this did not work either, I believe because draw instructions cannot be called from inside that environment.

This would look like the following:

\foreach \i in {1,...,50}{
    \tikzmath{\xa=rand;}
    \tikzmath{\ya=rand;}
    \tikzmath{\eval=int(\xa^2+\ya^2 - 1.0);}
    \tikzmath{
        if \eval < 0 then {
            \fill[CERNblue!80!white](\xa+1, \ya+1) circle(1.5pt);
        } else {
            \fill[red!60!white](\xa+1, \ya+) circle(1.5pt);
        }
    }
}

Would anyone know how to go around these limitations?

1

2 Answers 2

2

The following code colors dots conditionally. Note that I had to brace \x and \y in (\x)^2+(\y)^2 because if they are negative (say, -0.5 and -0,5) then the initial expression expands into -0.5^2+-0.5^2 which is likely not what you expect. Also, the code uses let to assign strings to variable \c.

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

\begin{document}
\begin{tikzpicture}
\fill[blue!10!white] (1,1) circle (1);
\draw[very thick] (0,0) -- (0,2) -- (2,2) -- (2,0) -- cycle;
\foreach \i in {1,...,50}{
    \tikzmath{
      \xa = rand;
      \ya = rand;
      \eval = (\xa)^2+(\ya)^2 - 1.0;
      if \eval<0 then {
        let \c = blue!80!white;
      } else {
        let \c = red!60!white;
      };
    }
    \fill[\c](\xa+1, \ya+1) circle(1.5pt);
}
\end{tikzpicture}
\end{document}

The result: enter image description here

2

You were really close with your last code example, you just need to enclose the TikZ statements in another pair of {} and add another ;:

if \eval < 0 then {
   { \fill[blue!80!white](\xa+1, \ya+1) circle[radius=1.5pt]; };
} else {
   { \fill[red!60!white] (\xa+1, \ya+1) circle[radius=1.5pt]; };
};

You can just do math with text, say

\col = \eval ? "blue!60!white" : "red!60!white";
% or 
\col = ifthenelse(\eval, "blue!60!white", "red!60!white")

Of course, you can also do this with if:

if \eval < 0 then {
  \col = "blue!60!white";% or let \col = blue!60!white;
} else {
  \col = "red!60!white"; % or let \col = red!60!white;
};

Assignments in the form of \<var> = <stuff> are evaluating <stuff> but you can also do let \<var> = <stuff> which does not evaluate <stuff>, that way you can drop the ".

Either way, now you can say

\fill[\col](\xa+1, \ya+1) circle[radius=1.5pt];

Since \eval is a simple integer number, you could have also used TeX primitives, say

\fill[\ifnum\eval<0 blue\else red\fi !60!white](\xa+1, \ya+1) circle[radius=1.5pt];

but that's not very nice.


Since you have only two outcomes depending on \eval you could define my fill 0/.style=red!60!white

and then use

\fill[blue!60!white, my fill \eval/.try](\xa+1, \ya+1) circle[radius=1.5pt];

where blue!60!white acts as a default and the /.try will only try my fill \eval and won't complain when the style is not defined.


I always like to have an if key available that evaluates a statement and applies different styles depending on the value. That way, you can even say

\fill[/utils/if={ int(\xa^2+\ya^2 - 1.0)<0 }% conditional
                { blue!60!white }           % if true
                { red!60!white  }           % if false
  ] (\xa+1, \ya+1) circle[radius=1.5pt];

By the way, the \foreach macro allows to do math for every loop without the need for \tikzmath:

\foreach[
  evaluate={
    \xa=rand;
    \ya=rand;
    \eval=int(\xa^2+\ya^2 - 1.0);
  }] \i in {1,...,50}{

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{math}

\makeatletter
\pgfkeys{% always useful
  /utils/if/.code n args={3}{%
    \pgfmathparse{#1}\ifdim\pgfmathresult pt=0pt\relax
    \expandafter\pgfutil@firstoftwo
      \else\expandafter\pgfutil@secondoftwo\fi
    {\pgfkeysalso{#3}}{\pgfkeysalso{#2}}}}
\makeatother

\begin{document}
\begin{tikzpicture}
\fill[blue!10!white] (1,1) circle[radius=1];
\draw[very thick] (0,0) rectangle (2,2);
\foreach \i in {1,...,50}{
    \tikzmath{
      \xa=rand;
      \ya=rand;
      \eval=int(\xa^2+\ya^2 - 1.0);
      \col = \eval ? "blue!60!white" : "red!60!white";
    }
    \fill[\col](\xa+1, \ya+1) circle[radius=1.5pt];
}
\end{tikzpicture}

\begin{tikzpicture}
\fill[blue!10!white] (1,1) circle[radius=1];
\draw[very thick] (0,0) rectangle (2,2);
\foreach \i in {1,...,50}{
    \tikzmath{
      \xa=rand;
      \ya=rand;
      \eval=int(\xa^2+\ya^2 - 1.0);
      if \eval < 0 then {
        \col = "blue!60!white";% or let \col = blue!60!white;
      } else {
        \col = "red!60!white"; % or let \col = red!60!white;
      };
    }
    \fill[\col](\xa+1, \ya+1) circle[radius=1.5pt];
}
\end{tikzpicture}

\begin{tikzpicture}
\fill[blue!10!white] (1,1) circle[radius=1];
\draw[very thick] (0,0) rectangle (2,2);
\foreach \i in {1,...,50}{
    \tikzmath{
      \xa=rand;
      \ya=rand;
      \eval=int(\xa^2+\ya^2 - 1.0);
      if \eval < 0 then {
            {\fill[blue!80!white](\xa+1, \ya+1) circle[radius=1.5pt];};
        } else {
            {\fill[red!60!white](\xa+1, \ya+1) circle[radius=1.5pt];};
        };
    }
}
\end{tikzpicture}

\begin{tikzpicture}
\fill[blue!10!white] (1,1) circle[radius=1];
\draw[very thick] (0,0) rectangle (2,2);
\foreach \i in {1,...,50}{
    \tikzmath{
      \xa=rand;
      \ya=rand;
      \eval=int(\xa^2+\ya^2 - 1.0);
    }
    \fill[\ifnum\eval<0 blue\else red\fi !60!white](\xa+1, \ya+1) circle[radius=1.5pt];
}
\end{tikzpicture}

\begin{tikzpicture}[my fill 0/.style=red!60!white]
\fill[blue!10!white] (1,1) circle[radius=1];
\draw[very thick] (0,0) rectangle (2,2);
\foreach \i in {1,...,50}{
    \tikzmath{
      \xa=rand;
      \ya=rand;
      \eval=int(\xa^2+\ya^2 - 1.0);
    }
    \fill[blue!60!white, my fill \eval/.try](\xa+1, \ya+1) circle[radius=1.5pt];
}
\end{tikzpicture}

\begin{tikzpicture}
\fill[blue!10!white] (1,1) circle[radius=1];
\draw[very thick] (0,0) rectangle (2,2);
\foreach \i in {1,...,50}{
    \tikzmath{
      \xa=rand;
      \ya=rand;
      \eval=int(\xa^2+\ya^2 - 1.0);
    }
    \fill[/utils/if={ int(\xa^2+\ya^2 - 1.0)<0 }% conditional
                    { blue!60!white }           % if true
                    { red!60!white  }           % if false
      ] (\xa+1, \ya+1) circle[radius=1.5pt];
}
\end{tikzpicture}
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.