Tikz 新命令

Tikz 新命令

我对 LaTeX 还很陌生,在我正在写的论文中,我需要绘制许多带有填充矩形的网格(网格中的一些单元格应保留为白色,其他单元格则为黑色)。由于我不喜欢一遍又一遍地编写相同的代码,所以我考虑定义一个新命令tikz(这可能吗?)。

\newcommand{\cell}[2]{
    \fill[black!](#1*0.5, (-#2)*0.5)rectangle(#1*0.5 + 0.5, (-#2)*0.5+0.5)
}

这应该在 (0.5*x, -0.5*y, 0.5*(x+1), -0.5(y+1)) 处绘制一个深色矩形,其用途如下:

  \begin{tikzpicture}
        \cell{1}{1};
        \draw[step=0.5cm,gray,very thin] (2.0,-2.0) grid (0.0, 0.0);
  \end{tikzpicture}

但是它似乎不起作用,因为我收到以下错误消息:

! Package tikz Error: Giving up on this path. Did you forget a semicolon?
See the tikz package documentation for explanation.
Type H <return> for immediate help.

它出现在我使用命令的那一行\cell。我做错了什么?

答案1

如果您有很多这样的图表,那么我建议您定义一个绘制整个网格的宏,而不是仅仅定义一个会为单个单元格着色的宏。宏使阅读 LaTeX 代码以及稍后编辑或更改代码变得更加容易。这样,

 \Blocks{2}{(1,1)}

将在适当位置绘制一个2x2带有阴影框的网格(1,1),并

 \Blocks{4}{(1,1),(2,2),(3,3),(4,4)}

将绘制一个4x4带有 SW-NE 对角线阴影的网格。

从力学角度来说,你不需要使用坐标计算,因为蒂克兹软件包中有这个内置内容:

\draw[fill=black](1,1) rectangle ++(1,1);

将绘制一个矩形,其左下角位于位置(1,1),右上角位于位置(2,2)

综合起来,我会像这样编写宏:

\documentclass[border=2mm]{standalone}
\usepackage{tikz}
\usepackage{xparse}

\NewDocumentCommand\Blocks{ omm }
{% usage \Blocks[cols]{rows}{list of shaded cells}
   \begin{tikzpicture}
     \def\rowsForBlocks{#2}
     \IfNoValueTF{#1}{\def\colsForBlocks{\rowsForBlocks}}
                     {\def\colsForBlocks{#1}}
     % draw the grid
     \foreach \row in {0,...,\colsForBlocks} {
        \draw[gray](\row,0)-- ++(0,\rowsForBlocks);
     }
     \foreach \col in {0,...,\rowsForBlocks} {
        \draw[gray](0,\col)-- ++(\colsForBlocks,0);
     }
     % shade the specified boxes
     \foreach \cell in {#3} {
         \draw[fill=black!50] \cell rectangle ++ (-1,-1);
     }
   \end{tikzpicture}
}

\begin{document}

\Blocks{2}{(1,1)}

\Blocks[3]{2}{(1,1),(2,2),(3,1)}

\Blocks{4}{(1,1),(2,2),(3,3),(4,4)}

\end{document}

得出的结果为:

在此处输入图片描述

请注意,我给出了\Blocks一个可选参数(使用\NewDocumentCommand来自解析)。默认情况下,\Block将绘制一个正方形指定大小的网格,但是,可选参数允许您绘制矩形的网格。例如,在上面的代码中

\Blocks[3]{2}{(1,1),(2,2),(3,1)}

绘制一个有 2 行 3 列的网格。

编辑

根据要求,以下是有关其工作原理的更多详细信息。该\Blocks宏采用三个参数:

  • 网格中的列数(可选:默认为#行)
  • 网格中的行数
  • 要着色的单元格的逗号分隔列表

{ omm }这些参数由

\NewDocumentCommand\Blocks{ omm }{...} 

这里,表示可选参数,当给出时,o用括起来,表示强制参数,即使只有(因此会绘制一个“空”网格) ,也必须始终指定。请参阅[...]m{}\Blocks{3}{}3x3解析手册了解更多详细信息。

如果有r行和c列,则网格使用笛卡尔坐标从原点(0,0)到绘制(r,c),标记为的单元格(x,y)具有顶点(x-1,y-1)(x-1,y)和。这是最简单、最自然的标记,因为 tikz 使用笛卡尔坐标。如果您想使用半整数格,最干净的方法是添加到环境选项中(x,y-1)(见下文)。(x,y)scale=0.5tikzpicture

宏顶部的内容如下\Blocks

     \def\rowsForBlocks{#2}
     \IfNoValueTF{#1}{\def\colsForBlocks{\rowsForBlocks}}
                     {\def\colsForBlocks{#1}}

将参数中的行数和列数设置为\Blocks,然后使用这些参数绘制网格。\IfNoValueTF{#1}检查是否给出了可选的第一个参数—— 代表TFTrueFalse表示在未给出\def\colsForBlocks{\rowsForBlocks}可选参数时执行,在给出可选参数时执行(再次参见#1\def\colsForBlocks{#1}解析手册中的详细信息)。 之后,

     % draw the grid
     \foreach \row in {0,...,\colsForBlocks} {
        \draw[gray](\row,0)-- ++(0,\rowsForBlocks);
     }
     \foreach \col in {0,...,\rowsForBlocks} {
        \draw[gray](0,\col)-- ++(\colsForBlocks,0);
     }

只需绘制构成行和列的线条即可绘制相应的网格。最后,

     % shade the specified boxes
     \foreach \cell in {#3} {
         \draw[fill=black!50] \cell rectangle ++ (-1,-1);
     }

循环遍历第三个参数,它是阴影单元格的#3逗号分隔坐标列表。表示对应于的单元格等于具有对应于笛卡尔坐标和的“外角”的矩形。(x,y)++ (-1,-1)(x,y)(x,y)(x,y)+(-1,-1)=(x-1,y-1)

在 OP 中,对应于的正方形(x,y)具有“外角”,其笛卡尔坐标为(x,-y)(x,-y-1)。要实现这一点有点麻烦,使用蒂克兹但有一种方法可以做到这一点,那就是改变语法,让坐标用括号分隔。例如,

\Blocks[3]{2}{{0,0},{1,0},{2,0}}

使用括号的优点是,它允许我们通过将其视为pgf 数组来从中提取x和,我们可以使用以下命令进行操作:y\cell{x,y}

\pgfmathsetmacro\x{{\cell}[0]}% extract x coordinate
\pgfmathsetmacro\y{{\cell}[1]}% extract y coordinate

(请注意,pgf 数组是基于 0 的。)一旦我们有了\x\y我们就可以使用以下方法绘制 OP 的单元格:

\draw[fill=black!50] (\x,-\y) rectangle ++ (1,-1);

严格来说,我们应该使用

\draw[fill=black!50] (0.5*\x,-0.5*\y) rectangle ++ (0.5,-0.5);

但是,如下所示,通过重新缩放环境来做到这一点“更好”(如果这些图表中有文字,这可能不是最好的方法,但正如目前所述,情况并非如此)。

在评论中,OP 说如果宏也可以改变单元格的高度就好了。我们可以通过向 中添加第二个可选参数来实现这一点\Blocks。为了能够独立使用这两个可选参数,我们应该用 以外的其他东西来分隔第二个可选参数[...]。我通常<...>在需要两个可选参数时使用 ,因此 的定义\Blocks现在看起来像:

 \NewDocumentCommand\Blocks{ D<>{0.5} o m m }{...}

表示D<>{0.5}有第二个可选参数,<...>默认值0.5——这将成为环境scale=#1中的一部分tikzpicture。因此,默认情况下,比例将为 50%,这将提供 OP 使用的半整数格点。综合起来,这是使用 OP 的单元格坐标的新版本代码:

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}

\NewDocumentCommand\Blocks{ D<>{0.5} o m m }
{% usage \Blocks<scale>[cols]{rows}{list of shaded cells}
   \begin{tikzpicture}[scale=#1]
     \def\rowsForBlocks{#3}
     \IfNoValueTF{#2}{\def\colsForBlocks{\rowsForBlocks}}
                     {\def\colsForBlocks{#2}}
     % draw the grid
     \foreach \row in {0,...,\colsForBlocks} {
        \draw[gray](\row,0)-- ++(0,-\rowsForBlocks);
     }
     \foreach \col in {0,...,\rowsForBlocks} {
        \draw[gray](0,-\col)-- ++(\colsForBlocks,0);
     }
     % shade the specified boxes
     \foreach \cell in {#4} {
       \pgfmathsetmacro\x{{\cell}[0]}% extract x coordinate from cell
       \pgfmathsetmacro\y{{\cell}[1]}% extract y coordinate from cell
       \draw[fill=black!50] (\x,-\y) rectangle ++ (1,-1);
     }
   \end{tikzpicture}
}

\begin{document}

\Blocks<1>{2}{{0,0}}                     % scale = 1 = 1.0 = 100%
\Blocks[3]{2}{{0,0},{1,0},{2,0}}         % default scale = 0.5 = 50%
\Blocks<0.3>[3]{2}{{0,0},{1,1},{2,0}}    % scale = 0.3 = 30%
\Blocks<0.1>{4}{{0,0},{1,1},{2,2},{3,3}} % scale = 0.1 = 10 %

\end{document}

这是新的输出:

在此处输入图片描述

答案2

您必须启用坐标计算:参见 TikZ/PGF 手册第 13.5 节。

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\newcommand{\cell}[2]{%
  \fill [black!50] ($0.5*(#1,-#2)$) rectangle ($0.5*(#1,-#2)+(0.5,0.5)$)%
}

\begin{document}

\begin{tikzpicture}
  \cell{1}{1};
  \cell{3}{2};
  \cell{0}{3};
  \draw[step=0.5cm,gray,very thin] (2.0,-2.0) grid (0.0, 0.0);
\end{tikzpicture}

\end{document}

在此处输入图片描述

答案3

如果您要绘制许多这样的网格,则仅指定两个参数可能会很方便:网格大小(\N见下文)和填充单元格(col,row)。以下代码仅使用这两个参数来绘制两个大小为和的网格410填充一些选定的单元格。为此,进一步定义新命令可能会更方便。

笔记:

众所周知,TikZ 网格不太准确,(请参阅我对 TikZ 网格问题的回答),因此,将网格与绝对坐标混合使用可能会导致错误。这就是我使用循环手动绘制网格的原因。

\documentclass{article}
\usepackage{tikz}
\begin{document}

\def\N{4}                            % (1) grid size
\begin{tikzpicture}[very thin]
  \foreach \n in {0,...,\N}
    \draw (0,.5*\n)--(.5*\N,.5*\n) (.5*\n,0)--(.5*\n,.5*\N);
  \foreach \c in {(1,2),(2,4),(4,3)} % (2) fill cells (col,row)
    \draw[fill=black!50,scale=.5] \c rectangle ++(-1,-1);
\end{tikzpicture}

\bigskip

\def\N{10}
\begin{tikzpicture}[very thin]
  \foreach \n in {0,...,\N}
    \draw (0,.5*\n)--(.5*\N,.5*\n) (.5*\n,0)--(.5*\n,.5*\N);
  \foreach \c in {(2,5),(4,2),(8,6)}
    \draw[fill=black,scale=.5] \c rectangle ++(-1,-1);
\end{tikzpicture}

\end{document}

在此处输入图片描述

相关内容