I'd like to create the following plot (illustrating a population and a random sample) with tikz where the dots are created/placed randomly; all dots inside the circle, however, are supposed to be coloured in red:

enter image description here

Using answers based on previous (somewhat similar) questions, I was able to create the following plot.

\documentclass[tikz]{standalone}
\begin{document}
  \begin{tikzpicture}
    \draw (0,0) -- (4,0) -- (4,4) -- (0,4) -- cycle;
    \foreach \x in {1,...,40}
    {
      \pgfmathrandominteger{\a}{10}{390}
      \pgfmathrandominteger{\b}{10}{390}
      \fill (\a*0.01,\b*0.01) circle (0.1);
    };
    \draw (2,2) circle (1cm);
  \end{tikzpicture}
\end{document}

enter image description here

However, I have no clue how to color the dots inside the circle in red (I have a vague idea that involves basic geometry and ifelse by checking every dot if it is placed inside the circle... does that make sense?).

  • a simpler way imho would be to draw some red dots inside a circle and some black ones outside, in two different loops... and maybe using polar coordinates would help! – Davide Jan 9 '16 at 7:52
  • What happens to the ones on the boundary? – percusse Jan 9 '16 at 8:56
up vote 12 down vote accepted

Mathematically, a circle with radius r with center at (a,b) is defined by the equation

(x-a)^2 + (y-b)^2 = r^2

So, to check if a point lies within this circle, you can check if the random points (x,y) satisfy

(x-a)^2 + (y-b)^2 <= r^2

i.e. they are less than r away from the center of the circle. If you use <=, then points on the border still count as "inside", if you use <, they won't.

To do that in TikZ, you can use the ifthenelse function provided by PGF Math. That is:

\pgfmathparse{ ifthenelse(condition, "value A", "value B")}

If the condition is satisfied, \pgfmathresult will contain "value A", if not it will contain "value B". We can use this to set the color either to "black" or "red":

\documentclass[tikz]{standalone}
\begin{document}
  \begin{tikzpicture}

    % Random seed for RNG
    \pgfmathsetseed{\number\pdfrandomseed}

    % Define circle parameters
    \newcommand{\cX}{2}
    \newcommand{\cY}{2}
    \newcommand{\cR}{1}

    \draw (0,0) -- (4,0) -- (4,4) -- (0,4) -- cycle;

    \foreach \x in {1,...,40}
    {
      % Find random numbers
      \pgfmathrandominteger{\a}{10}{390}
      \pgfmathrandominteger{\b}{10}{390}

      % Scale numbers nicely
      \pgfmathparse{0.01*\a}\let\a\pgfmathresult
      \pgfmathparse{0.01*\b}\let\b\pgfmathresult

      % Check if numbers are inside circle
      \pgfmathparse{ifthenelse((\a-\cX)^2 + (\b-\cY)^2 <= \cR^2,%
          "red",
          "black")}
        \fill[\pgfmathresult] (\a,\b) circle (0.1);
    };
    \draw (\cX,\cY) circle (\cR);
  \end{tikzpicture}
\end{document}

result

If you don't mind working in points, then the TikZ math library may be helpful. Here, points are rejected if they would lie on the border of the circle.

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{math}
\begin{document}
\begin{tikzpicture}[x=1pt,y=1pt]
\tikzmath{%
  coordinate \c, \p, \q;
  \q = (100, 100);
  \c = (30, 30);
  \R = 50;
  \r = 1;
  {
    \draw (-\qx, -\qy) rectangle (\qx, \qy);
    \draw [red] (\c) circle [radius=\R];
  };
  \x = \qx - \r; \y = \qy - \r;
  for \i in {0,...,100}{
    \p = (rand * \x, rand * \y);
    \v = veclen(\cx - \px, \cy - \py);
    if \v > (\R + \r) then {
      { \fill [black] (\p) circle [radius=\r]; };
    } else {
      if \v < (\R - \r) then {
        { \fill [red] (\p) circle [radius=\r]; };
      };
    };
  };
}
\end{tikzpicture}
\end{document}

enter image description here

Here is one "clipping mask" solution:

\documentclass[varwidth, border=7pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{fadings}

\begin{document}
  % define clip mask with random points
  \begin{tikzfadingfrompicture}[name=rndpts]
    \fill[transparent!0] foreach ~ in {1,...,100}{(rand,rand) circle (0.02)};
  \end{tikzfadingfrompicture}
  % use it to clip rectangle and circle
  \begin{tikzpicture}
    \begin{scope}
      \fill[scope fading=rndpts, fit fading=true] (0,0) rectangle (4,4);
      \fill[red] (2,2) circle (1cm);
    \end{scope}
    \draw (0,0) rectangle (4,4);
    \draw[red] (2,2) circle (1cm);
  \end{tikzpicture}
\end{document}

Metapost is also very good at this sort of diagram.

enter image description here

prologues := 3;
outputtemplate := "%j%c.eps";

beginfig(1);

numeric N, s, r;
N = 100; % population
s = 300; % size of square
r = 40; % radius of circle
z0 = (200,160); % center of circle;
color selected; selected = .73 red;

for i=1 upto N:
   z[i] = (uniformdeviate s, uniformdeviate s);
   drawdot z[i] withpen pencircle scaled 4 
     if r > length(z[i]-z0): withcolor selected fi;
endfor

draw fullcircle scaled 2r shifted z0 withcolor selected;
draw unitsquare scaled s;

endfig;
end.

Here's yet another solution that:

  1. Sets the circle whose center defines the coordinate center, with a radius \ra (expressed in pt).
  2. A \foreach loop that creates 200 random points, but you can change the number.
  3. A measurement is done between center and each dot point.
  4. Using an \if statement, if the length is above 50pt, dots will be standard black, otherwise, they'll be colored red.

Output

enter image description here

Code

\documentclass[margin=20pt]{standalone}
\usepackage{tikz,tkz-euclide}
\usetkzobj{all}

\usetikzlibrary{calc}
\newcommand\ra{50}

\begin{document}
\begin{tikzpicture}
\draw (1,2) coordinate (center) circle (\ra pt);

\foreach \point in {1,...,200}{%
    \pgfmathparse{rand}
    \pgfmathsetmacro\xdot{-7*\pgfmathresult}
    \pgfmathparse{rand}
    \pgfmathsetmacro\ydot{-5*\pgfmathresult}
%
    \coordinate (c\point) at (\xdot,\ydot);
    \tkzCalcLength(center,c\point) \tkzGetLength{myl}
    \pgfmathtruncatemacro\distance{\myl}
    \ifnum\distance>\ra
        \fill (c\point) circle (2pt);
    \else
        \fill[red] (c\point) circle (2pt);
    \fi
}%
\end{tikzpicture}
\end{document}

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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