Вторая версия

Вторая версия

У меня есть две диаграммы (обе должны быть одинаковыми), одна с явными командами draw и node, другая с foreachциклами. Очевидно, я не понимаю циклы foreach, так как могу заставить работать только одну. Я следовал руководству по tikz, но оно быстро вышло у меня из головы. Я пытаюсь понять логику tikz методом проб и ошибок, но я немного разочаровался, попробовав, казалось бы, простые вещи. Мне нужна помощь с другими. Я прошу подтолкнуть в правильном направлении, как мне это сделать. Как мне нужно спроектировать свои циклы, чтобы сократить код первой диаграммы. Вторая не работает, когда строки закомментированы.

\documentclass{article}
\usepackage[margin=20mm]{geometry}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\draw (0,0) rectangle +(10.5,8);
\draw (0.1,0.1) rectangle +(10.3,7.8);
\foreach \x in {1.5,4,6.5,9}
    \foreach \y in {1.5,4,6.5}
        \draw (\x,\y) circle (1);

\node at (1.5,1.5) {PreA30};
\node at (1.5,4) {PreB30};
\node at (1.5,6.5) {PreC30};

\node at (4,1.5) {PreA50};
\node at (4,4) {PreB50};
\node at (4,6.5) {PreC50};

\node at (6.5,1.5) {PreA70};
\node at (6.5,4) {PreB70};
\node at (6.5,6.5) {PreC70};

\node at (9,1.5) {PreA90};
\node at (9,4) {PreB90};
\node at (9,6.5) {PreC90};

\node at (1.5,-.5) {30\%};
\node at (4,-.5) {50\%};
\node at (6.5,-.5) {70\%};
\node at (9,-.5) {90\%};
\node at (-.5,1.5) {A};
\node at (-.5,4) {B};
\node at (-.5,6.5) {C};
\end{tikzpicture}

\begin{tikzpicture}
\draw (0,0) rectangle +(10.5,8);
\draw (0.1,0.1) rectangle +(10.3,7.8);

\foreach \x in {1.5,4,6.5,9}
    \foreach \y in {1.5,4,6.5}
        \draw (\x,\y) circle (1);

% the next block actually compiles, but the result is quite alarming
% I tried a different order, but that doesn't seem to matter at all
%\foreach \x in {1.5,4,6.5,9}
%   \foreach \y in {1.5,4,6.5}
%       \foreach \sam in {A,B,C}
%           \foreach \perc in {30,50,70,90}
%               \node at (\x,\y) {Pre\sam\perc};
%
%\foreach \x in {1.5,4,6.5,9}
%   \foreach \perc in {30,50,70,90}
%       \node at (\x,-.5) {\perc\%};
%
%\foreach \y in {1.5,4,6.5}
%   \foreach \sam in {A,B,C}
%       \node at {-.5,\y} {\sam};
\end{tikzpicture}

\end{document}

С ответом marmots мы получаем то, что показано на рисунке ниже. Первая диаграмма — это то, что нужно. Вторая диаграмма имеет суперпозиции текста во всех узлах. Я знаю, что это, вероятно, больше связано с логикой, чем с LaTeX, но все же я не могу полностью уложить в голове правильный дизайн циклов for. желаемый и нежелательный эффект

решение1

У вас есть четыре вложенных цикла, в то время как вы хотите только два, но вам нужно иметь больше одной переменной цикла. Это можно сделать, например, с помощью

\foreach \x/\perc in {1.5/30,4/50,6.5/70,9/90}

т.е. каждый элемент в списке переменных содержит два значения, разделенных знаком /.

Что касается вашего исходного кода, циклы работают нормально, единственная проблема в том, что вы использовали \node at {-.5,\y} {\sam};вместо \node at (-.5,\y) {\sam};в окончательном коде. (Фигурные скобки вместо круглых скобок в координатах.) Исправив это, вы получите проблему наложения, поскольку для каждой пары значений \x/ \yвы печатаете 12 узлов: три разные буквы (A, B, C) и четыре разных числа (30, 50, 70, 90), что дает 12 комбинаций.

\documentclass{article}
\usepackage[margin=20mm]{geometry}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\draw (0,0) rectangle +(10.5,8);
\draw (0.1,0.1) rectangle +(10.3,7.8);
\foreach \x in {1.5,4,6.5,9}
    \foreach \y in {1.5,4,6.5}
        \draw (\x,\y) circle (1);

\node at (1.5,1.5) {PreA30};
\node at (1.5,4) {PreB30};
\node at (1.5,6.5) {PreC30};

\node at (4,1.5) {PreA50};
\node at (4,4) {PreB50};
\node at (4,6.5) {PreC50};

\node at (6.5,1.5) {PreA70};
\node at (6.5,4) {PreB70};
\node at (6.5,6.5) {PreC70};

\node at (9,1.5) {PreA90};
\node at (9,4) {PreB90};
\node at (9,6.5) {PreC90};

\node at (1.5,-.5) {30\%};
\node at (4,-.5) {50\%};
\node at (6.5,-.5) {70\%};
\node at (9,-.5) {90\%};
\node at (-.5,1.5) {A};
\node at (-.5,4) {B};
\node at (-.5,6.5) {C};
\end{tikzpicture}

\begin{tikzpicture}
\draw (0,0) rectangle +(10.5,8);
\draw (0.1,0.1) rectangle +(10.3,7.8);

\foreach \x/\perc in {1.5/30,4/50,6.5/70,9/90}
   { % here you need to use braces, because there is more than one thing in the loop
   \node at (\x,-0.5) {\perc\%};
   \foreach \y/\sam in {1.5/A,4/B,6.5/C}
       {
       \draw (\x,\y) circle (1);
       \node at (\x,\y) {Pre\sam\perc};
       }
   }

% second loop for y-labels
\foreach \y/\sam in {1.5/A,4/B,6.5/C}
   \node at (-0.5,\y) {\sam};

\end{tikzpicture}
\end{document}

введите описание изображения здесь

Вторая версия

Есть и другие доступные варианты \foreach, как описано в главе 83 вруководство. Для такого случая с регулярно расположенными узлами может иметь смысл использовать опцию count, которая дает вам счетчик для переменной цикла. И далее, вы можете использовать evaluateдля выполнения вычислений.

Таким образом, вы можете иметь только одну переменную цикла для каждого из циклов и вычислять координаты на основе того, на какой итерации цикла вы находитесь. Вывод такой же, как и выше.

\documentclass{article}
\usepackage[margin=20mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{fit, backgrounds}
\begin{document}

\begin{tikzpicture}

\foreach [count=\i, evaluate={\x=\i*2.5}] \perc in {30,50,70,90}
   { % here you need to use braces, because there is more than one thing in the loop
   \foreach [count=\j, evaluate={\y=\j*2.5}] \sam in {A,B,C}
       {
       \node [circle,draw,minimum size=2cm] (\sam\perc) at (\x,\y) {Pre\sam\perc};
       \ifnum \i=1
         \node [left=5mm] at (\sam30.west) {\sam};
       \fi
       } % inner loop ends here
   % so this node is only in outer loop
   \node [below=5mm] at (A\perc.south) {\perc\%};
   }

\begin{scope}[on background layer]
  % fit both around same nodes, with different inner sep
  \node[draw,fit=(A30)(C90),inner sep=3mm, fill=blue!20] (frame) {}; % outer frame, larger inner sep
  \node[draw,fit=(A30)(C90),inner sep=2mm, fill=red!20] (frame) {}; % inner frame, smaller inner sep
\end{scope}
\end{tikzpicture}
\end{document}

как указано выше с заполненной фоновой рамкой

решение2

Я знаю, что этот вопрос касается foreach, но если у кого-то возникнут проблемы с пониманием foreachиспользования, эту диаграмму легко воспроизвести с matrixпомощью:

\documentclass[tikz,border=2mm]{standalone} 
\usetikzlibrary{positioning, matrix, fit}

\begin{document}
\begin{tikzpicture}

\matrix[matrix of nodes,
            nodes={anchor=center, 
                circle, draw, minimum size=2cm},
            column 1/.style={%
                nodes={rectangle, minimum size=0pt, draw=none}},
            row 4/.style={%
                nodes={rectangle, minimum size=0pt, draw=none}},
            column sep=5mm, row sep=5mm]
(top)
{
C & PreC30 & PreC50 & PreC70 & PreC90 \\
B & PreB30 & PreB50 & PreB70 & PreB90 \\
A & PreA30 & PreA50 & PreA70 & PreA90 \\
  & 30\% & 50\% & 70\% & 90\% \\
};
\node[draw, double, fit=(top-1-2) (top-3-5), inner sep=3mm] {};
\end{tikzpicture}
\end{document}

введите описание изображения здесь

решение3

Если вы используете \foreachциклы, вам нужно поместить все, что должно быть внутри цикла, в группу, т.е. окружить его {и }, если у вас нет только одной команды/группы в цикле. Применение этого к вашему коду дает

\documentclass{article}
\usepackage[margin=20mm]{geometry}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\draw (0,0) rectangle +(10.5,8);
\draw (0.1,0.1) rectangle +(10.3,7.8);
\foreach \x in {1.5,4,6.5,9}
    \foreach \y in {1.5,4,6.5}
        \draw (\x,\y) circle (1);

\node at (1.5,1.5) {PreA30};
\node at (1.5,4) {PreB30};
\node at (1.5,6.5) {PreC30};

\node at (4,1.5) {PreA50};
\node at (4,4) {PreB50};
\node at (4,6.5) {PreC50};

\node at (6.5,1.5) {PreA70};
\node at (6.5,4) {PreB70};
\node at (6.5,6.5) {PreC70};

\node at (9,1.5) {PreA90};
\node at (9,4) {PreB90};
\node at (9,6.5) {PreC90};

\node at (1.5,-.5) {30\%};
\node at (4,-.5) {50\%};
\node at (6.5,-.5) {70\%};
\node at (9,-.5) {90\%};
\node at (-.5,1.5) {A};
\node at (-.5,4) {B};
\node at (-.5,6.5) {C};
\end{tikzpicture}

\begin{tikzpicture}
\draw (0,0) rectangle +(10.5,8);
\draw (0.1,0.1) rectangle +(10.3,7.8);

\foreach \x in {1.5,4,6.5,9}
    {\foreach \y in {1.5,4,6.5}
        \draw (\x,\y) circle (1);}

% the next block actually compiles, but the result is quite alarming
% I tried a different order, but that doesn't seem to matter at all
\foreach \x in {1.5,4,6.5,9}
  {\foreach \y in {1.5,4,6.5}
      \foreach \sam in {A,B,C}
          {\foreach \perc in {30,50,70,90}
              \node at (\x,\y) {Pre\sam\perc};}}

\foreach \x in {1.5,4,6.5,9}
  {\foreach \perc in {30,50,70,90}
      \node at (\x,-.5) {\perc\%};}

\foreach \y in {1.5,4,6.5}
  {\foreach \sam in {A,B,C}
      \node at (-.5,\y) {\sam};}
\end{tikzpicture}

\end{document}

Теперь этот код дает вам то, что, как я думаю, вы хотели получить.

Связанный контент