如何在表格边框处绘制单元格之间的箭头

如何在表格边框处绘制单元格之间的箭头

如何在表格边框处绘制单元格之间的箭头?更准确地说,我希望得到类似这样的效果:

在此处输入图片描述

如果能使用 TikZ 来解决就好了。

编辑

由于我的文档中还有其他类似的表格(但没有箭头,使用具有自定义列分隔符的常规表格环境创建),因此对我来说,在所有表格中使用相同的行分隔符和列分隔符非常重要。因此,了解如何调整解决方案TikZ来实现这一点会很好。

\documentclass[a4paper,11pt]{article} 

\usepackage[T1]{fontenc} 
\usepackage{array}

\begin{document}
 \begin{tabular}{|m{1.3cm}|m{0.5cm}|m{0.5cm}|m{0.5cm}|m{0.5cm}|m{0.5cm}|m{0.1cm}}\cline{1-6}
  \footnotesize{ $x$ } & 0 & 1 & 2 & 3 &4 & \\\cline{1-6}
  \footnotesize{ $f(x)$} & 2 & 4&6 &8& 10& \\\cline{1-6}
 \end{tabular}
\end{document}

答案1

更新:自动化解决方案

这是一个可以自动完成之前解决方案繁琐步骤的解决方案。您可以使用:

  • 环境MyTabular
  • M{}类型(与 相对m{})用于放置箭头的列。m{}对于没有箭头的列,请使用 。
  • \StartTopRow[]{}指示顶行的开始,提供顶部箭头的样式,并提供要放在上方的文本,以及
  • \EndTopRow[]{}指示顶行的结束,提供底部箭头的样式,并提供底部箭头处的文本。

因此,代码如下:

\begin{MyTabular}{|m{1.3cm}|*5{M{0.5cm}|}M{0.1cm}|}\cline{1-6} \StartTopRow[red, thick]{\tiny$+1$}% specify top text
    \footnotesize{$x$}   & 0 & 1 & 2 & 3 & 4 \\\cline{1-6}     \EndTopRow[blue,thick]{\tiny$+2$}%   specify bottom text
    \footnotesize{$f(x)$}& 2 & 4 & 6 & 8 &10 \\\cline{1-6}
\end{MyTabular}

产量:

在此处输入图片描述

collcell包用于访问M{}列中的每个条目,并用适当的节点标记要绘制箭头的点\tikzmark

笔记:

  • 这确实需要两次运行。第一次确定位置,第二次进行绘图。
  • \XShift和的值\ArcDistance可能需要根据\renewcommand每个表进行调整,如表之前的注释代码所示。
  • 为了实现的两种变体\DrawArrow,我使用\NewDocumentCommandxparse包裹因为我更喜欢它的语法,但这可以在没有额外包的情况下完成,正如在定义带星号的命令版本(* 宏)如果需要的话。

进一步增强:

  • 至少还有一件事需要改进:箭头的起点和终点应该偏离列的中间,不是从左点(加上偏移量)开始,就像当前解决方案中的情况一样。一种解决方案是标记每列文本的左侧和右侧,但一定有更简单的方法。最简单的方法是将文本放在节点中并使用锚点.south,但这会影响文本的定位。

参考:

代码:

\documentclass[a4paper,11pt]{article} 

\usepackage[T1]{fontenc} 
\usepackage{collcell}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{calc}

% Adapted from https://tex.stackexchange.com/questions/47905/how-to-globally-tikzset-styles
\newcommand\globalTikzset[1]{%
    \begingroup%
        \globaldefs=1\relax%
        \tikzset{#1}%
    \endgroup%
}%
\tikzset{TopArrowStyle/.style={}}%
\tikzset{BottomArrowStyle/.style={}}%


\newcommand{\tikzmark}[2]{%
    \tikz[overlay,remember picture,baseline] \node [anchor=base] (#1) {\phantom{#2}};#2%
}

\newcounter{NumberOfTopColumns}%    Could just use one counter, but this handles case if we 
\newcounter{NumberOfBottomColumns}% ever have a different number of columns on top vs. bottom.

\newcommand*{\TopPrefix}{top}%
\newcommand*{\BottomPrefix}{bottom}%
\newcommand*{\CurrentTikzmarkPrefix}{}%  Gets redefined for top and bottom rows
\newcommand*{\IncrementColumnCounter}{}% Gets redefined for top and bottom rows
\newcommand*{\TopRowText}{}%
\newcommand*{\BottomRowText}{}%

\newcommand*{\StartTopRow}[2][]{%
    \globalTikzset{TopArrowStyle/.style={#1}}%
    \global\def\TopRowText{#2}%
    \setcounter{NumberOfTopColumns}{0}%
    \setcounter{NumberOfBottomColumns}{0}%
    \global\def\CurrentTikzmarkPrefix{\TopPrefix\arabic{NumberOfTopColumns}}%
    \global\def\IncrementColumnCounter{\stepcounter{NumberOfTopColumns}}%
}%
\newcommand*{\EndTopRow}[2][]{%
    \globalTikzset{BottomArrowStyle/.style={#1}}%
    \global\def\BottomRowText{#2}%
    \global\def\CurrentTikzmarkPrefix{\BottomPrefix\arabic{NumberOfBottomColumns}}%
    \global\def\IncrementColumnCounter{\stepcounter{NumberOfBottomColumns}}%
}%

\newcommand{\AddAppropriateTikzmark}[1]{%
    \tikzmark{\CurrentTikzmarkPrefix}{#1}%
    \IncrementColumnCounter%
}%

\newcolumntype{M}[1]{>{\collectcell\AddAppropriateTikzmark}m{#1}<{\endcollectcell}}%

\newenvironment{MyTabular}[1]{%
    \begin{tabular}{#1}%
}{%
    \end{tabular}%
    \addtocounter{NumberOfTopColumns}{-1}%
    \foreach \Column in {1,...,\arabic{NumberOfTopColumns}}{%
        \pgfmathtruncatemacro{\PreviousColumn}{\Column-1}%
        \DrawArrow[TopArrowStyle]{\TopPrefix\PreviousColumn}{\TopPrefix\Column}{\TopRowText}%
    }
    \addtocounter{NumberOfBottomColumns}{-1}%
    \foreach \Column in {1,...,\arabic{NumberOfBottomColumns}}{%
        \pgfmathtruncatemacro{\PreviousColumn}{\Column-1}%
        \DrawArrow*[BottomArrowStyle]{\BottomPrefix\PreviousColumn}{\BottomPrefix\Column}{\BottomRowText}%
    }
}%


\newcommand*{\XShift}{0.5ex}%
\newcommand*{\ArcDistance}{0.5cm}%
\NewDocumentCommand{\DrawArrow}{s O{} g g g g}{%
    \IfBooleanTF {#1} {% starred variant - draw arrows below
        \newcommand*{\OutAngle}{-60}%
        \newcommand*{\InAngle}{-120}%
        \newcommand*{\AnchorPoint}{south}%
        \newcommand*{\ShortenBegin}{2pt}%
        \newcommand*{\ShortenEnd}{1pt}%
        \newcommand*{\ArcVector}{-\ArcDistance}%
    }{% non-starred - draw arrows above
        \newcommand*{\OutAngle}{60}%
        \newcommand*{\InAngle}{120}%
        \newcommand*{\AnchorPoint}{north}%
        \newcommand*{\ShortenBegin}{0pt}%
        \newcommand*{\ShortenEnd}{0pt}%
        \newcommand*{\ArcVector}{\ArcDistance}%
    }%
    \begin{tikzpicture}[overlay,remember picture]
        \draw[
                ->, thick, distance=\ArcDistance,
                shorten <=\ShortenBegin, shorten >=\ShortenEnd,
                out=\OutAngle, in=\InAngle, #2
            ] 
                ($(#3.\AnchorPoint)+(2*\XShift,0)$) to 
                ($(#4.\AnchorPoint)+(\XShift,0)$);
        \node [] at ($(#3.\AnchorPoint)!0.5!(#4.\AnchorPoint) + (\XShift,\ArcVector)$) {#5};
    \end{tikzpicture}
}

\begin{document}
%\renewcommand*{\XShift}{0.5ex}%       Can be adjusted on a per table
%\renewcommand*{\ArcDistance}{0.5cm}%  basis as needed.

\begin{MyTabular}{|m{1.3cm}|*5{M{0.5cm}|}M{0.1cm}|}\cline{1-6}  \StartTopRow[red, thick]{\tiny$+1$}% specify top text
    \footnotesize{$x$}   & 0 & 1 & 2 & 3 & 4 \\\cline{1-6}      \EndTopRow[blue,thick]{\tiny$+2$}%   specify bottom text
    \footnotesize{$f(x)$}& 2 & 4 & 6 & 8 &10 \\\cline{1-6}
\end{MyTabular}

\bigskip\bigskip
\begin{tabular}{|m{1.3cm}|m{0.5cm}|m{0.5cm}|m{0.5cm}|m{0.5cm}|m{0.5cm}|m{0.1cm}}\cline{1-6}
    \footnotesize{$x$}    & 0 & 1 & 2 & 3 & 4 & \\\cline{1-6}
    \footnotesize{$f(x)$} & 2 & 4 & 6 & 8 & 10& \\\cline{1-6}
\end{tabular}
\end{document}

手动解决方案:

保留旧的手动解决方案,因为对于新用户来说它可能更容易遵循。

以下是使用给定的 MWE 并\tikzmark标记要绘制箭头的每个点的 TikZ 解决方案的说明。下面还显示了用于比较目的的表格,以显示间距相同:

在此处输入图片描述

进一步增强:

这些已在自动化解决方案以上规定:

  • 如果这是需要经常做的事情,那么其中的大部分可以进一步自动化,也许可以使用包裹collcell
  • 循环\foreach也可以简化为下一个箭头的起始节点是前一个箭头的结束节点,因此在后续迭代之间可以存储和重用它。

代码:

\documentclass[a4paper,11pt]{article} 

\usepackage[T1]{fontenc} 
\usepackage{array}

\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{calc}

\newdimen{\Offset}
\newcommand{\tikzmark}[2]{%
    \settowidth{\Offset}{#2}%
    \tikz[overlay,remember picture,baseline] \node [anchor=base] (#1#2) {\phantom{#2}};#2%
}

\newcommand*{\XShift}{0.5ex}%
\newcommand*{\ArcDistance}{0.5cm}%
\NewDocumentCommand{\DrawArrow}{s O{} g g g g}{%
    \IfBooleanTF {#1} {% starred variant - draw arrows below
        \newcommand*{\OutAngle}{-60}%
        \newcommand*{\InAngle}{-120}%
        \newcommand*{\AnchorPoint}{south}%
        \newcommand*{\ShortenBegin}{2pt}%
        \newcommand*{\ShortenEnd}{1pt}%
        \newcommand*{\ArcVector}{-\ArcDistance}%
    }{% non-starred - draw arrows above
        \newcommand*{\OutAngle}{60}%
        \newcommand*{\InAngle}{120}%
        \newcommand*{\AnchorPoint}{north}%
        \newcommand*{\ShortenBegin}{0pt}%
        \newcommand*{\ShortenEnd}{0pt}%
        \newcommand*{\ArcVector}{\ArcDistance}%
    }%
    \begin{tikzpicture}[overlay,remember picture]
        \draw[
                ->, thick, distance=\ArcDistance,
                shorten <=\ShortenBegin, shorten >=\ShortenEnd,
                out=\OutAngle, in=\InAngle, #2
            ] 
                ($(#3.\AnchorPoint)+(2*\XShift,0)$) to 
                ($(#4.\AnchorPoint)+(\XShift,0)$);
        \node [] at ($(#3.\AnchorPoint)!0.5!(#4.\AnchorPoint) + (0,\ArcVector)$) {#5};
    \end{tikzpicture}
}

\begin{document}
%\renewcommand*{\XShift}{0.5ex}%       Can be adjusted on a per table
%\renewcommand*{\ArcDistance}{0.5cm}%  basis as needed.
\begin{tabular}{|m{1.3cm}|*5{m{0.5cm}|}m{0.1cm}|}\cline{1-6}
\footnotesize{$x$}   & \tikzmark{MarkX}{0} & \tikzmark{MarkX}{1} & \tikzmark{MarkX}{2} & \tikzmark{MarkX}{3} & \tikzmark{MarkX}{4} \\\cline{1-6}
\footnotesize{$f(x)$}& \tikzmark{MarkF}{2} & \tikzmark{MarkF}{4} & \tikzmark{MarkF}{6} & \tikzmark{MarkF}{8} &\tikzmark{MarkF}{10} \\\cline{1-6}
\end{tabular}

\foreach \x/\y in {0/1, 1/2, 2/3, 3/4}{%
    \DrawArrow[red]{MarkX\x}{MarkX\y}{\tiny$+1$}%
}
\foreach \x/\y in {2/4, 4/6, 6/8, 8/10}{%
    \DrawArrow*[blue]{MarkF\x}{MarkF\y}{\tiny$+2$}%
}

\bigskip\bigskip
 \begin{tabular}{|m{1.3cm}|m{0.5cm}|m{0.5cm}|m{0.5cm}|m{0.5cm}|m{0.5cm}|m{0.1cm}}\cline{1-6}
  \footnotesize{$x$}    & 0 & 1 & 2 & 3 & 4 & \\\cline{1-6}
  \footnotesize{$f(x)$} & 2 & 4 & 6 & 8 & 10& \\\cline{1-6}
 \end{tabular}
\end{document}

答案2

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{mathabx}
\def\MCt{\multicolumn{2}{c}{$\stackrel{+1}{\curvearrowright}$}}
\def\MCb{\multicolumn{2}{c}{\rule{0pt}{4ex}$\stackrel{\displaystyle\curvearrowbotright}{\scriptstyle+2}$}}
\def\MC{\multicolumn{1}{c}{}}
\begin{document}

\begin{tabular}{|l|*5{r|}}
 \MC  & \MCt & \MCt\\[\dimexpr -\normalbaselineskip-2.6pt]
 \MC  & \MC  & \MCt & \MCt\\\hline
$x$   & 0 & 1 & 2 & 3 & 4 \\\hline
$f(x)$& 2 & 4 & 6 & 8 &10 \\\hline
\MC  & \MCb & \MCb\\[\dimexpr -\normalbaselineskip-2.1ex]
\MC  & \MC  & \MCb & \MCb
\end{tabular}

\end{document}

在此处输入图片描述

答案3

这是一个快捷的方法:

\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{matrix}
\begin{document}
\begin{tikzpicture}
  \matrix[matrix of math nodes,draw, column sep=1em,row sep=.5mm] (mx) {
      x & 0 & 1 & 2 & 3 & 4 \\
    f(x)& 2 & 4 & 6 & 8 & 10 \\
  };
  \path[->,shorten >=2pt]
    \foreach \from/\to in {2/3,3/4,4/5,5/6} {
      ([yshift=2mm]mx-1-\from.north) edge[bend left]
        node[above] {$\scriptstyle+1$} ([yshift=2mm]mx-1-\to.north)
      ([yshift=-2.5mm]mx-2-\from.south) edge[bend right]
        node[below] {$\scriptstyle+2$} ([yshift=-2.5mm]mx-2-\to.south)
    };
\foreach \x in {2,...,6}{
\draw ([xshift=-0.5em]mx.north west -| mx-1-\x.west) -- ([xshift=-0.5em]mx.south west -| mx-1-\x.west);
};
\draw (mx.west) -- (mx.east);
\end{tikzpicture}
\end{document}

虽然看起来并不完全符合你的要求:

percusse 编辑:我添加了一种绘制边框的简单方法。虽然不太优雅,但我仍然认为无边框的情况更清晰。

在此处输入图片描述

答案4

使用{NiceArray}nicematrixTikZ 绘制箭头。

\documentclass{article}
\usepackage{nicematrix,tikz}
\usetikzlibrary{bending}

\begin{document}

$\begin{NiceArray}{w{l}{15mm}*{6}{w{c}{5mm}}}[hvlines]
\CodeBefore
  \begin{tikzpicture} [red,->,shorten > = 3pt, shorten < = 3pt]
    \foreach \i in {3,...,\value{jCol}} 
      { \draw (1-|\inteval{\i-1}.5) to [bend left] node [above] {\tiny $+1$} (1-|\i.5) ;  
        \draw (3-|\inteval{\i-1}.5) to [bend right] node [below] {\tiny $+2$} (3-|\i.5) ; }
  \end{tikzpicture}
\Body
    x    & 0 & 1 & 2 & 3 & 4 & 5 \\
    f(x) & 2 & 4 & 6 & 8 & 10 & 12\\
\end{NiceArray}$

\end{document}

上述代码的输出

相关内容