如何在表格边框处绘制单元格之间的箭头?更准确地说,我希望得到类似这样的效果:
如果能使用 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
,我使用\NewDocumentCommand
了xparse
包裹因为我更喜欢它的语法,但这可以在没有额外包的情况下完成,正如在定义带星号的命令版本(* 宏)如果需要的话。
进一步增强:
- 至少还有一件事需要改进:箭头的起点和终点应该偏离列的中间,不是从左点(加上偏移量)开始,就像当前解决方案中的情况一样。一种解决方案是标记每列文本的左侧和右侧,但一定有更简单的方法。最简单的方法是将文本放在节点中并使用锚点
.south
,但这会影响文本的定位。
参考:
\tikzmark
来自在正文旁边添加大括号。- 该
\DrawArrow
宏改编自我之前的解决方案如何在等式各部分之间画箭头来显示数学分配律(乘法)?。 - 来自
\globalTikzset
如何全局设置 tikzset 样式。
代码:
\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}
和nicematrix
TikZ 绘制箭头。
\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}