tikzpicture 中的相对位置和绝对位置

tikzpicture 中的相对位置和绝对位置

我想在页面上定位“网格”。我将它们放在一个范围内,命名为本地边界框,并尝试使用它进行相对定位,例如shift={($(myscope.center)+(1cm,1cm)$)}。我也尝试过在页面上定位,例如($(page.south west)$),但对结果不太满意。

具体来说,在下面的屏幕截图中,我希望能够将三个网格的左侧相对于左边距对齐:目前第二个网格对齐得很好,但第一个和第三个网格离左边距有点太远了。我可以继续尝试调整偏移,但我觉得有比这更好的方法。

为了提供我的问题的背景,网格是“多项选择”表的一部分。我改编了expl3在接受的答案中找到的一些代码这里\vgrid\hgrid命令产生垂直/水平网格:整数是问题编号;字母是答案选项;问题的起始数字可以更改;正确答案以蓝色显示(0 表示问题未回答)。请参阅下面的详细信息:

% ARGUMENTS of \vgrid and \hgrid
% [starting question number] [total number of questions] [total number of answer choices] [scaling factor] {list of zeros or list of the correct answer numbers, separated by semi-colons}
  % #1 : question sequence starting number, default 1
  % #2 : total number of questions in sequence, default 20
  % #3 : total number of choices for each question, default 5
  % #4 : scaling factor, default 1.0
  % #5 : semi-colon separated list of numbers corresponding to correct answers, e.g. 1 for A, 2 for B, and 0 for not-answered

\documentclass[12pt]{article}
\usepackage[papersize={8.5in,11in},left=0.5in,right=0.5in,nohead,top=0.5in,nofoot,bottom=0.5in,marginparsep=0pt,showframe]{geometry}
\setlength{\parindent}{0pt}
\usepackage{tikz}
\usetikzlibrary{calc,positioning}

% HORIZONTAL GRID
\ExplSyntaxOn
\NewDocumentCommand{\hgrid}{ O{1} O{20} O{5} O{0.9} m}{%
    \seq_set_split:Nnn \l_tmpa_seq{;}{#5}
    % print question key (A, B, C...)
    \int_step_inline:nnnn {1} {1} {#3} {%
        \node at (0*#4, #3*#4-##1*#4) {\int_to_Alph:n{##1}};}
    % print question number (1, 2, 3...)
    \int_step_inline:nnnn {#1} {1} {#1+#2-1} {%
        \node at (##1*#4-#1*#4+1*#4, #3*#4) {##1};
        \int_step_inline:nnnn {1} {1} {#3} {%
            % draw an empty box for each question number/key
            \node[draw,line~width=1*#4pt,minimum~width=0.8*#4cm,minimum~height=0.8*#4cm] at (##1*#4-#1*#4+1*#4, #3*#4-####1*#4) {};
            % fill the correct box (0 to leave it empty)
            \int_compare:nNnTF {####1} = {\seq_item:Nn \l_tmpa_seq {#1+#2-##1}} {\node[fill=blue,minimum~width=0.8*#4cm,minimum~height=0.8*#4cm] at (#1*#4+#2*#4-##1*#4, #3*#4-####1*#4) {};}{}
        }
  }
}
\ExplSyntaxOff


% VERTICAL GRID
\ExplSyntaxOn
\NewDocumentCommand{\vgrid}{ O{1} O{20} O{5} O{0.9} m}{%
    \seq_set_split:Nnn \l_tmpa_seq{;}{#5}
    % print question key (A, B, C...)
    \int_step_inline:nnnn {1} {1} {#3} {%
        \node at (##1*#4, #2*#4) {\int_to_Alph:n{##1}};}
    % print question number (1, 2, 3...)
    \int_step_inline:nnnn {#1} {1} {#1+#2-1} {%
        \node at (0*#4, #1*#4+#2*#4-1*#4-##1*#4) {##1};
        \int_step_inline:nnnn {1} {1} {#3} {%
            % draw an empty box for each question number/key
            \node[draw,line~width=1*#4pt,minimum~width=0.8*#4cm,minimum~height=0.8*#4cm] at (####1*#4, ##1*#4-#1*#4) {};
            % fill the correct box (0 to leave it empty)
            \int_compare:nNnTF {####1} = {\seq_item:Nn \l_tmpa_seq {#1+#2-##1}} {\node[fill=blue,minimum~width=0.8*#4cm,minimum~height=0.8*#4cm] at (####1*#4, ##1*#4-#1*#4) {};}{}
        }
  }
}
\ExplSyntaxOff



\begin{document}\pagestyle{empty}

\begin{tikzpicture}[x=1cm, y=1cm, font=\scriptsize\bfseries]

% short horizontal grid
  \begin{scope}[anchor=south east, 
                local bounding box=bb1]
  \hgrid{0;2;3;4;5;4;3;2;1;2;3;4;5;4;3;2;1;2;3;4}
  \end{scope}

% long horizontal grid
  \begin{scope}[anchor=south east, 
                shift={($(bb1.south west)+(0cm,-5cm)$)}, 
                local bounding box=bb2]
  \hgrid[21][30][6][0.6]{0;2;3;4;5;6;5;4;3;2;1;2;3;4;5;6;5;4;3;2;1;2;3;4;5;6;5;4;3;2}
  \end{scope}

% short vertical grid
  \begin{scope}[anchor=south east, 
                shift={($(bb2.south west)+(1cm,-12cm)$)}, 
                local bounding box=bb3]
  \vgrid[51][10][4][1.1]{0;2;3;4;5;4;3;2;1;2}
  \end{scope}

\end{tikzpicture}

\end{document}

在此处输入图片描述

笔记:我对我的问题进行了重大修改,并在此过程中修复了一些错误。如果仍有错误,那不是故意的!

答案1

我尝试将你的网格重新设想为pics,这意味着固定 TiKZ 图片可以使用。显然,我推荐使用 tikzmark 解决方案。

\documentclass[12pt]{article}
%\url{https://tex.stackexchange.com/q/619620/86}
\usepackage[papersize={8.5in,11in},left=0.5in,right=0.5in,nohead,top=0.5in,nofoot,bottom=0.5in,marginparsep=0pt,showframe]{geometry}
\setlength{\parindent}{0pt}
\usepackage{tikz}
\usetikzlibrary{calc,positioning,fit}

% HORIZONTAL AND VERTICAL GRIDS
\ExplSyntaxOn
\cs_new_nopar:Npn \grid_val:n #1
{
  \pgfkeysvalueof{/tikz/grid/#1}
}
\tikzset{
    grid/.is~ family,
    grid/start/.initial=1,
    grid/total/.initial=20,
    grid/choices/.initial=5,
    horizontal~ grid/.pic={
      \seq_set_split:Nnn \l_tmpa_seq{;}{#1}
      % print question key (A, B, C...)
      \int_step_inline:nnnn {1} {1} {\grid_val:n {choices}
      } {%
        \node at (0, \grid_val:n {choices}-##1) {\int_to_Alph:n{##1}};
      }
      % print question number (1, 2, 3...)
      \int_step_inline:nnnn {\grid_val:n {start} } {1} {\grid_val:n {start} + \grid_val:n {total} - 1} {%
        \node at (##1-\grid_val:n {start} +1, \grid_val:n {choices} ) {##1};
        \int_step_inline:nnnn {1} {1} {\grid_val:n {choices}} {%
          % fill the correct box (0 to leave it empty)
          \int_compare:nNnT {####1} = {\seq_item:Nn \l_tmpa_seq {\grid_val:n {start} + \grid_val:n {total} - ##1} } {
            \fill[gray]
            (\grid_val:n {start} + \grid_val:n {total} -##1, \grid_val:n {choices} - ####1)
            +(-.4,-.4) rectangle +(.4,.4);
          }
          % draw an empty box for each question number/key
          \draw
          (##1-\grid_val:n {start}+1, \grid_val:n {choices} -####1)
          +(-.4,-.4) rectangle +(.4,.4);
        }
      }
      \node[
        draw=red,
        line~width=2pt,
        dashed,
        overlay,
        fit={
          (1, \grid_val:n {choices}-1)
          (\grid_val:n {total}, 0)
        }
      ] (-grid) {}; 
      \node[
        draw=blue,
        line~width=2pt,
        dashed,
        overlay,
        fit={
          (0, \grid_val:n {choices})
          (\grid_val:n {total}, 0)
        }
      ] (-picture) {}; 
    },
    vertical~ grid/.pic={
      \seq_set_split:Nnn \l_tmpa_seq{;}{#1}
      % print question key (A, B, C...)
      \int_step_inline:nnnn {1} {1} {\grid_val:n {choices}
      } {%
        \node at (##1, \grid_val:n {total}) {\int_to_Alph:n{##1}};
      }
      % print question number (1, 2, 3...)
      \int_step_inline:nnnn {\grid_val:n {start} } {1} {\grid_val:n {start} + \grid_val:n {total} - 1} {%
        \node at (0,\grid_val:n {start} + \grid_val:n {total} -1 - ##1 ) {##1};
        \int_step_inline:nnnn {1} {1} {\grid_val:n {choices}} {%
          % fill the correct box (0 to leave it empty)
          \int_compare:nNnT {####1} = {\seq_item:Nn \l_tmpa_seq {\grid_val:n {start} + \grid_val:n {total} - ##1} } {
            \fill[gray]
            (####1, ##1 -  \grid_val:n {start})
            +(-.4,-.4) rectangle +(.4,.4);
          }
          % draw an empty box for each question number/key
          \draw
            (####1, ##1 -  \grid_val:n {start})
          +(-.4,-.4) rectangle +(.4,.4);
        }
      }
      \node[
        draw=red,
        line~width=2pt,
        dashed,
        overlay,
        fit={
          (\grid_val:n {choices}, 0)
          (1, \grid_val:n {total}-1)
        }
      ] (-grid) {}; 
      \node[
        draw=blue,
        line~width=2pt,
        dotted,
        overlay,
        fit={
          (\grid_val:n {choices}, 0)
          (0, \grid_val:n {total})
        }
      ] (-picture) {}; 
    }
}
\ExplSyntaxOff

\begin{document}\pagestyle{empty}

\begin{tikzpicture}[font=\scriptsize\bfseries]
\pic [scale=.9] [grid/start=44] [grid/choices=8] [grid/total=10] {vertical grid={0;2;3;4;5;4;3;2;1;2}};
\end{tikzpicture}

\begin{tikzpicture}[font=\scriptsize\bfseries]
\pic [scale=.9] [grid/start=21] [grid/choices=4] [grid/total=10] {horizontal grid={0;2;3;4;5;4;3;2;1;2}};
\end{tikzpicture}

\begin{tikzpicture}[font=\scriptsize\bfseries]
\pic [scale=.9]  [grid/start=1] [grid/choices=5] [grid/total=20] {horizontal grid={0;2;3;4;5;4;3;2;1;2;3;4;5;4;3;2;1;2;3;4}};
\end{tikzpicture}

\end{document}

网格重新绘制为图片


更新 2021-10-23tikzmark以下是使用图片锚定方法的示例。请注意,该方法目前仅在开发tikzmark版本中可用github并且我还没有完全确定语法(因此非常欢迎改进建议)。

\documentclass[12pt]{article}
%\url{https://tex.stackexchange.com/q/619620/86}
\usepackage[papersize={8.5in,11in},left=0.5in,right=0.5in,nohead,top=0.5in,nofoot,bottom=0.5in,marginparsep=0pt,showframe]{geometry}
\setlength{\parindent}{0pt}
\usepackage{tikz}
\usetikzlibrary{calc,positioning,fit,tikzmark}

% HORIZONTAL GRID
\ExplSyntaxOn

\cs_new_nopar:Npn \grid_val:n #1
{
  \pgfkeysvalueof{/tikz/grid/#1}
}

\seq_new:N \l__grid_answers_seq

% #1 - ;-separated list of correct answers
% #2 - choices per question
% #3 - start number of questions
% #4 - total number of questions
\cs_new_nopar:Npn \grid_horizontal:nnnn #1#2#3#4
{
  % Split the answers into a sequence
  \seq_set_split:Nnn  \l__grid_answers_seq {;} {#1}
  % Print the choice labels
  \int_step_inline:nnnn {1} {1} {#2}
  {
    \node at (0, -##1) {\int_to_Alph:n{##1}};
  }
  % Print question numbers
  \int_step_inline:nnnn {1} {1} {#4}
  {
    \node at (##1, 0) {\int_eval:n{##1 + #3 - 1}};
  }
  % Set out the grid
  \int_step_inline:nnnn {1} {1} {#2}
  {
    \int_step_inline:nnnn {1} {1} {#4}
    {
      \int_compare:nNnTF {##1} = {\seq_item:Nn \l__grid_answers_seq {####1}}
      {
        \filldraw[fill=blue,draw=black]
      }
      {
        \draw
      }
      (####1,-##1) +(-.4,-.4) rectangle +(.4,+.4);
    }
  }
  \node[
    draw=green,
    overlay,
    fit={
      (.5,-.5) (#4+.5,-#2-.5)
    }
  ] (-grid) {}; 
  \node[
    draw=orange,
    overlay,
    fit={
      (-.5,.5) (#4+.5,-#2-.5)
    }
  ] (-picture) {}; 
}

% #1 - ;-separated list of correct answers
% #2 - choices per question
% #3 - start number of questions
% #4 - total number of questions
\cs_new_nopar:Npn \grid_vertical:nnnn #1#2#3#4
{
  % Split the answers into a sequence
  \seq_set_split:Nnn  \l__grid_answers_seq {;} {#1}
  % Print the choice labels
  \int_step_inline:nnnn {1} {1} {#2}
  {
    \node at (##1,0) {\int_to_Alph:n{##1}};
  }
  % Print question numbers
  \int_step_inline:nnnn {1} {1} {#4}
  {
    \node at (0,-##1) {\int_eval:n{##1 + #3 - 1}};
  }
  % Set out the grid
  \int_step_inline:nnnn {1} {1} {#2}
  {
    \int_step_inline:nnnn {1} {1} {#4}
    {
      \int_compare:nNnTF {##1} = {\seq_item:Nn \l__grid_answers_seq {####1}}
      {
        \filldraw[fill=blue,draw=black]
      }
      {
        \draw
      }
      (##1,-####1) +(-.4,-.4) rectangle +(.4,+.4);
    }
  }
  \node[
    draw=green,
    overlay,
    fit={
      (.5,-.5) (#2+.5,-#4-.5)
    }
  ] (-grid) {}; 
  \node[
    draw=orange,
    overlay,
    fit={
      (-.5,.5) (#2+.5,-#4-.5)
    }
  ] (-picture) {}; 
}

\cs_generate_variant:Nn  \grid_horizontal:nnnn {nvvv}
\cs_generate_variant:Nn  \grid_vertical:nnnn {nvvv}

\cs_new_nopar:Npn \grid_horizontal_from_keys:nnnn #1#2#3#4
{
  \grid_horizontal:nvvv {#1} {pgfk@/tikz/grid/#2} {pgfk@/tikz/grid/#3} {pgfk@/tikz/grid/#4}
}

\cs_new_nopar:Npn \grid_vertical_from_keys:nnnn #1#2#3#4
{
  \grid_vertical:nvvv {#1} {pgfk@/tikz/grid/#2} {pgfk@/tikz/grid/#3} {pgfk@/tikz/grid/#4}
}

\tikzset{
    grid/.is~ family,
    grid/start/.initial=1,
    grid/total/.initial=20,
    grid/choices/.initial=5,
    horizontal~ grid/.pic={
      \grid_horizontal_from_keys:nnnn {#1} {choices} {start} {total}
    },
    vertical~ grid/.pic={
      \grid_vertical_from_keys:nnnn {#1} {choices} {start} {total}
    }
}

\ExplSyntaxOff

\begin{document}\pagestyle{empty}

\begin{tikzpicture}[x=1cm, y=1cm, font=\scriptsize\bfseries]
\fill[red] (0,0) circle[radius=5pt];
\pic[
  scale=.7,
  pic anchor=(-grid.east),
  grid/.cd,
  start=3,
  total=15
]
{horizontal grid={0;2;3;4;5;4;3;2;1;2;3;4;5;4;3;2;1;2;3;4}};

\pic[
  scale=.7,
  pic anchor=(-picture.west),
  grid/.cd,
  start=3,
  total=15
]
{vertical grid={0;2;3;4;5;4;3;2;1;2;3;4;5;4;3;2;1;2;3;4}};
\end{tikzpicture}
\end{document}

我重新调整了 pic 代码,将 L3 代码分解为单独的命令,然后从 pic 代码中调用这些命令。这还允许插入一个层来整理从 pgf 键获取的值,这样就不会弄乱主代码。我做的另一个调整是从顶部向下布局网格,而不是从底部向上布局。

我保留了网格和图片节点的轮廓,以便定位更加明显。显然,在最终版本中,这些将被删除(只是轮廓 - 而不是节点本身!)。

定位网格

相关内容