13

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?).

2
  • 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
    Commented Jan 9, 2016 at 7:52
  • What happens to the ones on the boundary?
    – percusse
    Commented Jan 9, 2016 at 8:56

5 Answers 5

14

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

13

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

7

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}

5

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.
5

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}

You must log in to answer this question.

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