6

I would like to draw concentric circles like these:

enter image description here

by means of TikZ and \foreach command. The way I achieved it is very elementary (and burdensome):

   \documentclass[standalone]
   \usepackage{tikz}
   \begin{document}
   \begin{tikzpicture}[scale=0.2]
   \coordinate (O) at (0,0);
   \fill[red!70] (O) circle (20);
   \fill[white] (O) circle (19);
   \fill[yellow!70] (O) circle (18);
   \fill[white] (O) circle (17);
   \fill[red!70] (O) circle (16);
   \fill[white] (O) circle (15);
   \fill[yellow!70] (O) circle (14);
   \fill[white] (O) circle (13);
   \fill[red!70] (O) circle (12);
   \fill[white] (O) circle (11);
   \fill[yellow!70] (O) circle (10);
   \fill[white] (O) circle (9);
   \fill[red!70] (O) circle (8);
   \fill[white] (O) circle (7);
   \fill[yellow!70] (O) circle (6);
   \fill[white] (O) circle (5); 
   \fill[red!70] (O) circle (4);
   \fill[white] (O) circle (3);
   \fill[yellow!70] (O) circle (2);
   \fill[white] (O) circle (1);
   \end{tikzpicture}
   \end{document}

To no avail did I try applying \foreach, but this is definitely due to my lack of fluency with TikZ (I always ended up with one color, or at most two nested circle with different color). Could you be so kind and help me with these? A suggestion how to do this would be even better than the full answer.

11

You mean something like this:

\documentclass{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[mystyle/.style={circle,draw,fill=none,minimum size=20, line width = 8pt}]
  \foreach \x in {1,3,5,7,9,11,13,15,17,19}
\node [mystyle,  minimum size = \x cm, color =red!70]  (2) at (0, 0) {};
  \foreach \x in {2,4,6,8,10,12,14,16,18, 20}
\node [mystyle,  minimum size = \x cm, color =yellow!50]  (2) at (0, 0) {};
\end{tikzpicture}
\end{document}  

which would give you:

enter image description here

I just made the yellow a bit lighter because, it was bleeding yellow too much :D

  • 1
    @MadHatter Also, this happens to be the first time I am using for loop in TeX. So, thanks to you ;) – Raaja Jan 23 at 12:36
  • 1
    +1, but iirc TikZ has an ifodd test which could make this a bit shorter… – TeXnician Jan 23 at 12:38
  • @TeXnician Could you enlighten me a bit in detail? I am not aware of those :D and what does iirc means? – Raaja Jan 23 at 12:39
  • @Raaja iirc is "if I recall correctly" and I have shown the test in my answer below (it's only to save the second loop, no real advantage). – TeXnician Jan 23 at 12:44
  • 1
    @Raaja You're welcome :) – Mad Hatter Jan 23 at 14:22
9

A slight generalization of Raaja's and TeXncian's answers in that I allow arbitrary color cycle lists, which is illustrated by an additional list of length 3.

\documentclass[tikz,border=3.14mm]{standalone}
\begin{document}
\begin{tikzpicture}
\def\lstColors{{"red!70","yellow!50"}}
\foreach \X [evaluate=\X as \Col using {\lstColors[int(mod(\X,2))]}] in {1,...,20}
{\draw[line width = 8pt,\Col] (0,0) circle (\X);}
\end{tikzpicture}
\begin{tikzpicture}
\def\lstColors{{"red!70","yellow!50","blue!70"}}
\foreach \X [evaluate=\X as \Col using {\lstColors[int(mod(\X,3))]}] in {1,...,20}
{\draw[line width = 8pt,\Col] (0,0) circle (\X);}
\end{tikzpicture}
\end{document}

enter image description here

  • 1
    Neat. I'd wondered how to do that... I'm certainly missing something basic, but for \X=1 (the innermost circle) shouldn't that be red? The fix is simple, just reverse the order of the colors in \lstColors, but just wondered... – sgmoye Jan 23 at 15:10
  • @sgmoye Good catch. The index of the first element of the list is 0, and the one of the second is 1. That's where the flip comes from. (I'll keep it to make the screenshots here more diverse. ;-) – marmot Jan 23 at 22:04
  • I saw that, and to counteract it I changed {\lstColors[int(mod(\X,2))]} to {\lstColors[int(mod(\X-1,2))]} in my copy -- that seemed to work for both 2 and 3 colors. Still, nice work! (Been a long day or I'd have posted earlier...) – sgmoye Jan 23 at 22:58
7

A PSTricks solution.

\documentclass[pstricks]{standalone}
\psset{runit=4pt,unit=\psrunit}
\begin{document}
\pspicture[linewidth=.5](-11,-11)(11,11)
    \foreach \i in {1,2,...,10}{%
        \ifodd\i\def\c{yellow}\else\def\c{red}\fi
        \pscircle[linecolor=\c]{\i}}
\endpspicture
\end{document}

enter image description here

Note: There is an unnecessary white spot after converting to PNG.

Animated version

\documentclass[pstricks]{standalone}
\psset{runit=4pt,unit=\psrunit}
\begin{document}    
\foreach \j in {1,...,10}{%
\pspicture[linewidth=.5](-11,-11)(11,11)
    \foreach \i in {1,...,\j}{%
        \ifodd\i\def\c{yellow}\else\def\c{red}\fi
        \pscircle[linecolor=\c]{\i}}%
\endpspicture}
\end{document}

enter image description here

  • 1
    You did not animate this. – AlexG Jan 23 at 13:13
6

This is Raaja's solution but without the second loop (test if the count variable is odd) and with a simple draw instead of nodes (change line width to make it thicker).

concentric circles

\documentclass{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[mystyle/.style={circle,draw,fill=none,minimum size=20, line width = 8pt}]
  \foreach \x in {1,...,20}{
    \pgfmathparse{isodd(\x)}\ifnum\pgfmathresult=1\def\currcol{red!70}\else\def\currcol{yellow!50}\fi
    \draw[line width=8pt,\currcol] (0,0) circle (\x cm);}
\end{tikzpicture}
\end{document}  
  • Next time, I will know how to apply this ifodd ;) [IMO, it is useful, if the loop counts grows]. – Raaja Jan 23 at 12:46
  • 1
    @Raaja Yes, it is :) – TeXnician Jan 23 at 12:46
  • Thank you very much. P.S. I think you mean thinner not thicker lines :). – Mad Hatter Jan 23 at 14:18
  • @MadHatter You can make it thicker by choosing a larger dimension than 8pt and thinner by choosing something smaller. So it's up to you to decide which way ;) – TeXnician Jan 23 at 14:31
  • @TeXnician Sorry, I misread your comment. – Mad Hatter Jan 23 at 15:01
5

A SkiaSharp solution only for comparison purposes.

using SkiaSharp; // needs skiasharp nuget
using System.Diagnostics;


class ConcentricCircle
{
    static readonly SKPaint yellowStroke = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Yellow,
        IsAntialias = true
    };


    static readonly SKPaint redStroke = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Red,
        IsAntialias = true
    };

    static readonly float scale = SKDocument.DefaultRasterDpi / 2.54f; // dots per cm
    static readonly float width = 6 * scale; // 6 cm
    static readonly float height = 6 * scale; // 6 cm

    static float PtToCm(float pt) => pt / scale;



    public static void Generate(string filename)
    {
        yellowStroke.StrokeWidth = PtToCm(4); // 4pt
        redStroke.StrokeWidth = PtToCm(4); // 4pt

        using (var stream = new SKFileWStream($"{filename}.pdf"))
        using (var document = SKDocument.CreatePdf(stream))
        using (var canvas = document.BeginPage(width, height))
        {

            // translate first and then scale, don't reverse!
            canvas.Translate(width / 2, height / 2);
            canvas.Scale(scale);

            // draw a red circle
            for (int i = 0; i < 5; i++)
            {
                canvas.DrawCircle(0, 0, PtToCm(8) * (2 * i + 1), yellowStroke);
                canvas.DrawCircle(0, 0, PtToCm(8) * (2 * i + 2), redStroke);
            }

            document.EndPage();
        }
    }

    private static void Main()
    {
        string filename = nameof(ConcentricCircle);
        Generate(filename);

        // convert to PNG with ImageMagick
        using (Process p = new Process())
        {
            p.StartInfo.FileName = "magick";
            p.StartInfo.Arguments = $"convert -compose copy -bordercolor red -border 2x2 -density 200 -alpha remove {filename}.pdf {filename}.png";
            p.Start();
        }
    }
}

enter image description here

  • 2
    Please don't radiate too much :) (+1) – Raaja Jan 23 at 12:46
  • 1
    I am a SkiaSharp evangelist. – Artificial Hairless Armpit Jan 23 at 12:47
  • 2
    Nice alternative indeed. – Raaja Jan 23 at 12:49
  • 1
    I really don't know the answer for that :/ – Raaja Jan 23 at 14:32
4

Just for fun. Another solution which draws a couple of red and yellow circles in each iteration:

\documentclass[tikz,border=3mm]{standalone}

\usetikzlibrary{positioning}

\begin{document}
\begin{tikzpicture}[
    mycircle/.style={circle, draw, fill=none, line width=8pt},
    twocircle/.style={
        mycircle,
        minimum size=#1cm,
        color=yellow!70,
        append after command={%
            \pgfextra
                \node[mycircle, minimum size=\the\numexpr#1-1\relax cm, color=red!70] at (\tikzlastnode.center) {};
            \endpgfextra}},
]

\foreach \i in {2,4,...,12}
    \node[twocircle=\i] {};
\end{tikzpicture}
\end{document}

enter image description here

2

A slightly different approach to the solution proposed @TeXnician (suggested by this: What is wrong with the use of `isodd` of `xifthen`?):

\documentclass{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[mystyle/.style={circle,draw,fill=none,minimum size=20, line width = 8pt}]
    \foreach \x in {1,2,...,19}{
        \pgfmathsetmacro\mycolor{isodd \x?"red!70":"yellow!50"}%
        \node [mystyle,  minimum size = \x cm, \mycolor]  (2) at (0, 0) {};
    }%
\end{tikzpicture}
\end{document}  
  • Why do you refer to the post about xifthen? Neither I do use it nor do you. And you do not even need the \numexpr because \x already is a number (the number you want to check). – TeXnician Jan 23 at 14:05
  • @TeXnician Had you checked, you would have seen that xifthen is in the title of the question from which I used some code, and which is substituted automatically for the URL. \numexpr is superfluous. Will remove. – sgmoye Jan 23 at 14:39

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.