7

enter image description here

I would like to bend the ``commutative rings'' around the circle. I would appreciate any help.

\documentclass[a4paper, 12pt, openany]{book}

\usepackage{tikz}
\usetikzlibrary{calc}

\colorlet{euler1}{red}
\colorlet{euler2}{blue}
\colorlet{euler3}{yellow}
\colorlet{euler4}{green}

\newcommand{\draweuler}[1]{
    \foreach \xname [count=\i] in {#1} {\xdef\n{\i}}
    \foreach \xname [count=\i] in {#1} {
        \draw[fill=euler\i!20] (0,0) circle ({(\n-\i+2)*10mm});
        \node[euler\i!30!black] (g\i) at (0, {ifthenelse(\i==\n, 0, (\n-\i+1.4)*10mm)}) {\xname};
    }
}

\begin{document}

\begin{tikzpicture}
 \draweuler{FIELDS, COMMUTATIVE RINGS, RINGS, GROUPS}
\end{tikzpicture}

\end{document}
1
  • 2
    See chapter 50.7 Text Decorations, pp 654 -- 664, TikZ & PGF manual.
    – Zarko
    Feb 13 at 7:38

2 Answers 2

16

You could do something like the following with decorations.text TikZ library. I find it more simple to remove your macro, but it could be used with another \ifthenelse or \ifnum exception.

Update: Better vertical align in the curved text, using the suggestion form quark67 (see the comments).

My code:

\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{decorations.text}

\colorlet{euler1}{red}
\colorlet{euler2}{blue}
\colorlet{euler3}{yellow}
\colorlet{euler4}{green}

% Added, from the comments and this post:
% https://tex.stackexchange.com/questions/185790/is-there-an-ex-unit-equivalent-for-the-capital-x-in-latex/185792#185792
\newcommand{\eX}{\dimexpr\fontcharht\font`X\relax}\newlength{\halfeX}
\setlength{\halfeX}{0.5\eX}

\begin{document}
\begin{tikzpicture}
\foreach\i in {1,...,4}
  \draw[fill=euler\i!20] (0,0) circle (6-\i);
\node[euler1!30!black] at (0,4.5) {FIELDS};
\path[euler2!30!black,decorate,
      decoration={text along path,text=COMMUTATIVE RINGS,text align=center,raise=-\halfeX}]
     (155:3.5) arc (155:25:3.5);
\node[euler3!30!black] at (0,2.5) {RINGS};
\node[euler4!30!black] at (0,0)   {GROUPS};
\end{tikzpicture}
\end{document}

And the output: enter image description here

3
  • 1
    Thanks so much. Feb 13 at 9:37
  • 1
    With the help of this from egreg, we could center a little better the (capital) text in the concentric ring. Add \newcommand{\eX}{\dimexpr\fontcharht\font`X\relax}\newlength{\halfeX}\setlength{\halfeX}{0.5\eX} in the preamble, and replace raise=-0.5ex by raise=-\halfeX in the tikzpicture. Because the height of the capitals are a little bigger than the height of the "x" (provided by the ex unit).
    – quark67
    Feb 13 at 21:43
  • @quark67, thanks for the suggestion!!! I have edited my code. Feb 14 at 7:16
11

The decorations.text library with its text along path is the absolutely the right approach. (You could try to manually place each letter along a curve but that's no fun.)

However, you can simply keep using one loop and a few smart styles to to this more manually.

But first, you can use the /utils/count list key to simply count the number of elements in a PGFFor list. There's no need to \xdef (and overwrite globally) a macro.

The euler node key creates a circular node with the needed diameter and colors. For the last (and smallest) node, the euler node/1 style will be executed which simply places a label at the center of the node. For all other nodes, the euler node/not 1 will be used. (The euler node/1 key disables it.)

This adds a “circular label”, i.e. another circle as a label that's euler margin smaller than the parent node. This label is rotated so that the start of the circle is at the bottom.

This circle will be decorated. The value euler margin is set up so that the text is somewhat centered between the areas. (5mm is half the space between the areas and 0.3em is needed to adjust the baseline of the text further.)

In the second example you can see by just disabling the euler node/1 key that all labels are placed along an arc.

Code

\documentclass[tikz, 12pt]{standalone}
\usetikzlibrary{through, decorations.text}
\pgfkeys{
  /utils/count list/.style 2 args={
    /utils/exec=\def#2{0},
    /utils/temp/.code=\edef#2{\pgfinteval{#2+1}},
    /utils/temp/.list={#1}}}
\colorlet{euler1}{red}
\colorlet{euler2}{blue}
\colorlet{euler3}{yellow}
\colorlet{euler4}{green}
\tikzset{
  circular label/.style n args={4}{label={[% works best with a circle
      rotate={-(#1)},
      circle through={([xshift={#2}]\tikzlastnode.west)},
      decorate, decoration={text along path, text align=center,
        reverse path, text color={#3}, text={#4}}]center:}},
  euler margin/.initial=.3em+5mm,
  euler radius/.initial=10mm,
  euler node/1/.style 2 args={
    label={[euler#1!30!black]center:{#2}},
    euler node/not 1/.code=},
  euler node/not 1/.style 2 args={
    circular label={90}{\pgfkeysvalueof{/tikz/euler margin}}
                   {euler#1!30!black}{#2}},
  euler node/.style n args={3}{
    shape = circle, draw = black, fill = euler#1!20,
    minimum size = {(#3-#1+2)*2*(\pgfkeysvalueof{/tikz/euler radius})},
    euler node/\pgfinteval{#3-#1+1}/.try = {#1}{#2},
    euler node/not 1                     = {#1}{#2}}}
\newcommand*\draweuler[2][]{
  \foreach[
    count=\eulerCnt, /utils/count list={#2}{\eulerTotal},
    /tikz/.cd, #1] \eulerTitle in {#2}
    \node[euler node={\eulerCnt}{\eulerTitle}{\eulerTotal}]{};}
\begin{document}
\tikz
\matrix[column sep=5mm]{
  \draweuler{FIELDS, COMMUTATIVE RINGS, RINGS, GROUPS}
&
  \draweuler[euler node/1/.code=]{FIELDS, COMMUTATIVE RINGS, RINGS, GROUPS}
\\};
\end{document}

Output

enter image description here

4
  • +1. Awesome!! I learn a lot with your answers Feb 13 at 19:44
  • Is there a way to better center the text on the path? I don't find a trick like for the Juan Castaño answer (see my comment). If you add \draw[red] (0,0) circle[radius=3.5]; at the end of the definition for \draweuler, you will see that the text is vertically centered a bit above the red circle (zoom on the PDF).
    – quark67
    Feb 13 at 23:31
  • 1
    @quark67 Instead of .3em you could try with .5*height("X") (height is a PGFmath function). Or indeed .5*\fontcharht\fontX\relax` should do, too. Maybe using the perfect middle for the circle and then using raise lead to better results but that will place the letters closer together. Feb 13 at 23:41
  • Thanks. Works great with .5*height("X"). You can edit your own answer, so it would be perfect! (it is already very good, however).
    – quark67
    Feb 13 at 23:59

You must log in to answer this question.

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