我怎样才能在 TikZ 中绘制这样的图画?

我怎样才能在 TikZ 中绘制这样的图画?

这些线不应该是虚线。我正在使用unicode 方框绘制字符,但显然该网站使用的字体使绘图看起来是虚线。

┌──────┐ ┌────┐ ┌───────┐ ┌───┐ ┌────┐ ┌───────┐
│ some ├─┤ or ├─┤ a lot ├─┤   ├─┤ of ├─┤ words │
├──────┤ ├────┤ ├───────┤ ├───┤ ├────┤ ├───────┤
│      │ │    │ │       │ │   │ │    │ │       │
│      │ │    │ │ even  │ │   │ │    │ │       │
│ foo  │ │ x  │ │ multi │ │   │ │    │ │       │
│      │ │    │ │ line  │ │   │ │    │ │       │
│      │ │    │ │       │ │   │ │    │ │       │
└──────┘ └────┘ └───────┘ └───┘ └────┘ └───────┘

称其为图表似乎有点过分。

我想我仍然记得定位是如何工作的但是我对 TikZ 总体上有点生疏,目前我不知道如何根据以下要求绘制此图:

  • 上方框中的文本不是多行,因此上方框都具有相同的固定高度。
  • 下面框中的文本可以是多行;我可以手动输入\\,但最好有自动换行符。
  • 根据内容的不同,下方的框具有其中最需要的框的高度。
  • 每个下部框具有与对应的上部框相同的宽度;从某种意义上说,它只是一个分成两个的框。
  • 连接各个框的线长度均相同,并且垂直位于上部框的中间。
  • 盒子的宽度由上部盒子的内容决定。
  • 整个绘图跨越整个文本宽度。

(假设页面足够宽。)


笔记:不幸的是,在发布问题之前,我没有给我的大脑足够的时间去思考,所以我错误地设计了其中一个要求。以下 2 点

  • 盒子的宽度由上部盒子的内容决定。
  • 下面框中的文本可以是多行;我可以手动输入\\,但最好有自动换行符。

应该

  • 盒子的宽度由上部的内容决定 降低盒子。
  • 下面框中的文本可以手工制作多行,例如通过明确\\或类似方式我可以手动输入\\,但是最好有自动换行符。

所以我误导了答案,顺便说一句,这些答案都很棒。

因此,我已对所有这些方案投了赞成票,但我会接受能根据我想要实现的目标提供最佳结果的方案。我为我的错误道歉。

答案1

有点不靠谱,但可以使用这个tabularray包。这个想法是绘制一条简单的规则和一个表格,表格前面的列之间有间隙。

这里有两个例子,一个是等宽框,另一个是相对大小的框:

\documentclass{article}

\usepackage{xcolor}
\usepackage{tabularray}

\begin{document}

\noindent\rule{\linewidth}{0.7pt}\vskip-.8\baselineskip
\noindent\begin{tblr}{
  colspec={|X||X||X||X||X||X|},
  hlines = {1}{-}{leftpos = 0, rightpos = 0},
  cells={bg=white,valign=m,halign=c},
  row{2}={rowsep+=10pt},
  rulesep=10pt,
}
some & or & a lot & & of & words\\
foo & x & even multi line & & &\\
\end{tblr}

\bigskip

\noindent\rule{\linewidth}{0.7pt}\vskip-.8\baselineskip
\noindent\begin{tblr}{
  colspec={|X[-1]||X[-1]||X[-1]||X[-1]||X[-1]||X[-1]|},
  hlines = {1}{-}{leftpos = 0, rightpos = 0},
  cells={bg=white,valign=m,halign=c},
  row{2}={rowsep+=10pt},
  rulesep=10pt,
}
some & or & a lot & & of & words\\
foo & x & even multi line even multi line even multi line even multi line even multi line & & &\\
\end{tblr}

\end{document}

在此处输入图片描述

答案2

nicematrix带有包和的解决方案tikz

\documentclass{article}
%\usepackage[showframe]{geometry}
\usepackage{tikz}
\usetikzlibrary{decorations}
\usepackage{nicematrix}
\setlength{\parindent}{0pt}
\begin{document}
    \begin{NiceTabular}[width=\textwidth]{cXcXcXcXcXc}[cell-space-limits=5pt]
        some && or && a lot &&&& of && words \\
        foo && x && \begin{tabular}{@{}>{\centering}p{1cm}@{}}
            even multi line
        \end{tabular} &&&&&& \\
        \CodeAfter
        \begin{tikzpicture}[mydash/.style={dash pattern=on 5pt off 2pt,dash expand off}]
            \def\myex{5pt}
            \foreach \x in {2,4,6,8,10} \draw (1.5 -| \x) -- (1.5 -| \inteval{1+\x});
            \foreach \x in {1,3,5,7,9,11} {
                \draw ([yshift=-\myex]1 -| \x) -- (1 -| \x) -- (1 -| \inteval{1+\x}) -- ([yshift=-\myex]1 -| \inteval{1+\x});
                \draw (2 -| \x) -- (2 -| \inteval{1+\x});
                \draw ([yshift=-\myex]2 -| \x) -- ++(0,2*\myex);
                \draw ([yshift=-\myex]2 -| \inteval{1+\x}) -- ++(0,2*\myex);
                \draw ([yshift=\myex]last -| \x) -- (last -| \x) -- (last -| \inteval{1+\x}) -- ([yshift=\myex]last -| \inteval{1+\x});
                \draw[mydash] ([yshift=-\myex]1 -| \x) -- ([yshift=\myex]2 -| \x);
                \draw[mydash] ([yshift=-\myex]1 -| \inteval{1+\x}) -- ([yshift=\myex]2 -| \inteval{1+\x});
                \draw[mydash] ([yshift=-\myex]2 -| \x) -- ([yshift=\myex]last -| \x);
                \draw[mydash] ([yshift=-\myex]2 -| \inteval{1+\x}) -- ([yshift=\myex]last -| \inteval{1+\x});
            }
        \end{tikzpicture}
    \end{NiceTabular}
\end{document}

在此处输入图片描述

编辑(无虚线)

\documentclass{article}
%\usepackage[showframe]{geometry}
\usepackage{tikz}
\usepackage{nicematrix}
\setlength{\parindent}{0pt}
\begin{document}
    \begin{NiceTabular}[width=\textwidth]{cXcXcXcXcXc}[cell-space-limits=5pt]
        some && or && a lot &&&& of && words \\
        foo && x && \begin{tabular}{@{}>{\centering}p{1cm}@{}}
            even multi line
        \end{tabular} &&&&&& \\
        \CodeAfter
        \begin{tikzpicture}
            \foreach \x in {2,4,...,10} \draw (1.5 -| \x) -- (1.5 -| \inteval{1+\x});
            \foreach \x in {1,3,...,11} {
                \draw (2 -| \x) -- (2 -| \inteval{1+\x});
                \draw (1 -| \x) rectangle (last -| \inteval{1+\x});
            }
        \end{tikzpicture}
    \end{NiceTabular}
\end{document}

在此处输入图片描述

答案3

以下不使用 TiZ,而是利用原始的\valign

不过绘制水平连接规则相当棘手。为了做到这一点,代码需要测量并记住每列的宽度和每行的最大高度。

使用这个输入应该相当容易,唯一违反直觉的是输入是按行进行的而输出是按列进行的(例如转置tabular)。

strangethingy环境中\\,跳转到下一列并插入垂直规则以及\hfill。水平线是在\valign运出后绘制的,并通过在幕后对每个&和进行的所有测量进行对齐\\。最后一行一定不结束\\(它会引发错误)。

代码可能需要一些清理(特别是名称)但应该是可行的。

在您的示例中,该列a lot & even multi line是有问题的,因为单词的multi长度超过了a lot导致水平盒子过满的长度。

\documentclass{article}

\usepackage{showframe}

\newlength\mycolwd
\newlength\mytotalwd
\newlength\mycolht
\newlength\mymaxhtupper
\newlength\mymaxhtlower
\newcommand*\mywdlist{}
\newlength\strangethingywd

\ExplSyntaxOn
\cs_new_eq:NN \mymap \tl_map_tokens:Nn
\cs_new_eq:NN \mycount \tl_count:N
\ExplSyntaxOff

\newenvironment{strangethingy}[1]
  {%
    \def\\%
      {%
        \endlowerbox
        \noalign
          {%
            \vrule
            \hfill
            \vrule
          }%
      }%
    \def\endlowerbox
      {%
        \ifhmode\unskip\strut\fi\par\egroup\egroup % setbox0=vbox
        \htmeasurehelper\mymaxhtlower
        \hbox{\hskip\tabcolsep\box0\hskip\tabcolsep}%
        \cr
      }%
    \def\htmeasurehelper##1%
      {%
        \mycolht=\dimexpr\ht0+\dp0\relax
        \global##1=\ifdim\mycolht>##1\mycolht\else##1\fi
      }%
    \global\mytotalwd=0pt
    \global\mymaxhtlower=0pt
    \global\mymaxhtupper=0pt
    \global\let\mywdlist\empty
    \strangethingywd=\dimexpr#1\relax
    \leavevmode
    \hbox to\strangethingywd\bgroup
    \valign\bgroup
        \hrule
        \setbox0=\hbox{{\strut\ignorespaces##\unskip}}%
        % measure the box and keep a record of some dimensions
        \global\mycolwd=\wd0
        \ifx\mywdlist\empty
          % still empty, but `\long` hence the above test will yield false now
          \long\gdef\mywdlist{}%
        \else
          \xdef\mywdlist{\mywdlist{\the\dimexpr\mycolwd+2\tabcolsep+.8pt}}%
        \fi
        \global\advance\mytotalwd\dimexpr\mycolwd+2\tabcolsep+.8pt\relax
        \htmeasurehelper\mymaxhtupper
        \vfil
        \hbox{\hskip\tabcolsep\box0\hskip\tabcolsep}%
        \vfil
        \hrule
        &
        \vfil
        \setbox0=\vbox\bgroup\bgroup
          \hsize=\mycolwd\sloppy
          \noindent\strut\ignorespaces##%
        \vfil
        \hrule
      \cr
      \noalign{\vrule}%
  }
  {%
    \endlowerbox
    \noalign{\vrule}%
    \egroup
    \llap
      {%
        \edef\myhorizontalrule
          {%
            \vrule
              width\dimexpr(\strangethingywd-\mytotalwd)/\mycount\mywdlist\relax
              height\dimexpr\mymaxhtlower+.5\mymaxhtupper+.8pt+.2pt\relax
              depth-\dimexpr\mymaxhtlower+.5\mymaxhtupper+.8pt-.2pt\relax
          }%
        \mymap\mywdlist
          {%
            \myhorizontalrule
            \hspace
          }%
      }%
    \egroup
  }

\begin{document}
\noindent
\begin{strangethingy}{\linewidth}% width the strangethingy should take
    some & foo \\
    or & x \\
    a lot & even multi line \\
          & \\
    of & \\
    words & % last block must not end in \\
\end{strangethingy}
\end{document}

在此处输入图片描述

答案4

我喜欢这个tabularray解决方案,但无论如何这里只有一个 TikZ 解决方案。

代码

\documentclass{article}
\usepackage{tikz}
\usepackage{showframe}
\usetikzlibrary{matrix, ext.node-families}
\tikzset{
  upper lower/.style={
    /utils/row1/.initial/.expand once=\csname @gobble\endcsname,
    /utils/row2/.initial/.expand once=\csname @gobble\endcsname,
    /utils/exec=%
      \def\tikzUpperWidth{0pt}%
      \def\tikzLowerHeight{0pt}%
      \def\tikzNumberOfBoxes{0},
    /utils/temp/.code args={##1/##2}{%
      \pgfkeysaddvalue{/utils/row1}{}{\pgfmatrixnextcell ##1}%
      \pgfkeysaddvalue{/utils/row2}{}{\pgfmatrixnextcell ##2\nolinebreak\strut}%
      \edef\tikzNumberOfBoxes{\pgfinteval{\tikzNumberOfBoxes+1}}%
      \pgfmathsetlengthmacro\tikzupperwidth{width("##1")}%
      \tikzset{column \tikzNumberOfBoxes/.append style/.expanded=
        {text width=\tikzupperwidth}}%
      \pgfmathsetlengthmacro\tikzUpperWidth{%
        \tikzUpperWidth+\tikzupperwidth
        +2*(\pgfkeysvalueof{/pgf/inner xsep})+\pgflinewidth}},
    /utils/temp/.list={#1},
    column sep/.evaluated={(\linewidth-\tikzUpperWidth)/(\tikzNumberOfBoxes-1)},
    row sep=-\pgflinewidth,
    every outer matrix/.append style={inner sep=+0pt, outer sep=+0pt}}}
\newcommand\tikzUpperLower[2][]{%
\par\noindent\noindent\begin{tikzpicture}[%
  #1, % all values like inner sep and line width needs to be before upper lower
  upper lower={#2}]
\matrix (m) [
  nodes={draw, anchor=center, align=center, font=\strut},
  matrix of nodes, nodes in empty cells,
  row 2/.append style={node family/height=row2},
  node contents/.expanded={%
    \unexpanded\expandafter\expandafter\expandafter
      {\pgfkeysvalueof{/utils/row1}}%
    \noexpand\pgfmatrixendrow
    \unexpanded\expandafter\expandafter\expandafter
      {\pgfkeysvalueof{/utils/row2}}%
    \noexpand\pgfmatrixendrow
  }];
\foreach \target in {2, ..., \tikzNumberOfBoxes} % line width not important
  \draw[upper lower/lines/.try] (m-1-\pgfinteval{\target-1}) -- (m-1-\target);
\end{tikzpicture}\par}
\begin{document}
\tikzUpperLower[
  ultra thick,% can't be individual
  upper lower/lines/.style=thick,
]{
    some/foo,
    or/x,
    a lot/even multiline,
    /,
    of/,
    words/%
}
\end{document}

输出

在此处输入图片描述

相关内容