
У меня есть две диаграммы (обе должны быть одинаковыми), одна с явными командами 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}
Теперь этот код дает вам то, что, как я думаю, вы хотели получить.