Set width of tikz node based on a node in the same line

positioningtikz-pgf

I want to create the following tikzpicture:

enter image description here

What I have at the moment is this:

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{tikz}
\usetikzlibrary{positioning,backgrounds}
\begin{document}
\noindent\begin{tikzpicture}[background rectangle/.style={fill=gray!25}, show background rectangle,every node/.style={inner sep=0pt,outer sep=0pt,draw}]

\begin{scope}[local bounding box=scope1]
\path[use as bounding box] (0,0) rectangle (.5\textwidth,0);
\filldraw (0,0) circle (2pt); 
\node [text width=0.5\textwidth, align=left,anchor=north west](n1) {scope 1, node 1};
\node [below = 0pt of n1.south west,anchor=north west] (n2) {scope 1, node 2};
\node [below left = 0pt and 0pt of n2.north east,anchor=north west,align=left,text width=5.1cm] (n3) {scope 1, node 3 that includes longer text to be broken into lines};
\end{scope}

\begin{scope}[shift={(scope1.north east)},anchor=north west]
\node [text width=0.5\textwidth, align=left](n1) {scope 2, node 1};
\node [below = 0pt of n1.south west,anchor=north west] (n2) {scope 2, node 2};
\node [below left = 0pt and 0pt of n2.north east,anchor=north west,align=left,text width=5.1cm] (n3) {scope 2, node 3 which also includes longer text to be broken into lines};
\end{scope}

\end{tikzpicture}
\end{document}

enter image description here

I need help with two things:

  1. How can I define the width of node n3 so the total width of n2 and n3 is that of n1 (which is .5\textwidth)? At the moment I set it to 5.1cm because it looks ok but if I change the content of node 2 then node 3's dimension should change as well. How can I make use of the bounding box I created for the first scope?

  2. How can I insert a separator between the two scopes (such as the one drawn in yellow in the first pic)? Why the width of the two scopes extends beyond textwidth? There is a gray margin on the left and right although outer sep=0pt.

Best Answer

The background rectangle has a padding (whch is called inner frame [xy]sep), thus it shows more in gray than your actual content. Use tight background to change this.
Furthermore, the line width (of any path, not only nodes, irregardles of any outer seps) will contribute to the picture's final bounding box which also throws off the final placement of the picture a bit (and will lead to an overful hbox).
In your original setup, you can overwrite the bounding box's horizontal measurement by using trim left=0pt, trim right=\textwidth. In my code below, I'm using ±.5\textwidth because I create the picture centered about the origin.

For creating nodes that have sizes that are relating to other nodes, they are the fit library which works by setting text width/height/depth which is bad if you want the nodes to actually have text.

My ext.positioning-plus library does similar things using the fit library but controls the size of the new node by using minimum width and minimum height which is better for having text in the node but needs a bit work for text that is longer than what would fit in the node.

I'm using here a very basic text width between key that uses the calc library to measure the distance between two arbitrary points in the x dimension and uses that to set the text width of the node. We need to subtract inner xsep twice here (so that the final node actually covers the area with inner xsep). This is basically a way to set a fixed width instead of a minimum width. (The factor 2 is different for other shapes.)

For syncing up sizes of nodes, I can offer the ext.node-families library of my tikz-ext package.

Every node that has node family={height=row1} set shares the same minimum height. This will align the texts in each node vertically centered.

Both blue nodes as well as the yellow separater (also a node) will span the same vertical space.

Code (Node Family)

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{tikz, amsmath}
\makeatletter % https://tex.stackexchange.com/a/656319/16595
\tikzset{parse let/.code={\def\tikz@cc@stop@let in{}\tikz@let@command et #1in}}
\makeatother
\usetikzlibrary{calc, positioning, backgrounds, ext.node-families}
\tikzset{
  text width between/.style args={#1 and #2}{
    parse let={\p@=($(#2)-(#1)$)},
    text width/.expanded={abs(\x@)-2*(\noexpand\pgfkeysvalueof{/pgf/inner xsep}}}}
\begin{document}
\noindent
\begin{tikzpicture}[
  background rectangle/.style={fill=gray!25},
  show background rectangle, tight background,
  trim left=-.5\textwidth, trim right=.5\textwidth,
  every node/.style={outer sep=+0pt},
  Yellow/.style={fill=yellow, node family={height=row1}},
  Blue/.style  ={fill=blue,   node family={height=row1}, text=white},
  Red/.style   ={fill=red,   align=center},
  Green/.style ={fill=green, align=center},
  node distance=+0pt
]
\node[Yellow] (sep) {};
\node[Blue, left=of sep,  text width between={-.5\textwidth,0 and sep.west}]
  (Blue-left) {scope 1, node 1 $\displaystyle e^x = \cfrac{1}{1 - \cfrac{x}{1 + x -
                               \cfrac{\frac{1}{2}x}{1 + \frac{1}{2}x - \ddots}}}$};
\node[Blue, right=of sep, text width between={ .5\textwidth,0 and sep.east}]
  (Blue-right) {scope 1, node 1};

\node[Red, below right=of Blue-left.south  west] (Red-left)  {scope 1,\\ node 2};
\node[Red, below right=of Blue-right.south west] (Red-right) {scope 1,\\ node 2};

\node[Green, below left=of Blue-left.south east,
     text width between=Red-left.east and Blue-left.east]
  (Red-left) {scope 1, node 3 that includes longer text to be broken into lines};

\node[Green, below left=of Blue-right.south east,
     text width between=Red-right.east and Blue-right.east]
  (Red-left) {scope 2, node 3 which also includes longer text to be broken into lines
    \dots\ and here's an extra linre};
\end{tikzpicture}
\end{document}

Code (w/o Node Family)

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{tikz, amsmath}
\makeatletter % https://tex.stackexchange.com/a/656319/16595
\tikzset{parse let/.code={\def\tikz@cc@stop@let in{}\tikz@let@command et #1in}}
\makeatother
\usetikzlibrary{calc, positioning, backgrounds}
\tikzset{
  text width between/.style args={#1 and #2}{
    parse let={\p@=($(#2)-(#1)$)},
    text width/.expanded={abs(\x@)-2*(\noexpand\pgfkeysvalueof{/pgf/inner xsep}}},
  minimum height of three nodes/.style n args={3}{
    parse let={\p1=($(#1.north)-(#1.south)$),
               \p2=($(#2.north)-(#2.south)$),
               \p3=($(#3.north)-(#3.south)$),
               \n@={max(\y1,\y2,\y3)}},
    minimum height/.expanded={\n@}}}
\DeclareDocumentCommand{\tikzthreenodessameheight}{O{} m O{} m O{} m}{
  \node[#1,alias=@1,overlay,path only,outer ysep=+0pt]{\phantom{#2}};
  \node[#3,alias=@2,overlay,path only,outer ysep=+0pt]{\phantom{#4}};
  \node[#5,alias=@3,overlay,path only,outer ysep=+0pt]{\phantom{#6}};
  \node[#1,minimum height of three nodes={@1}{@2}{@3}] {#2};
  \node[#3,minimum height of three nodes={@1}{@2}{@3}] {#4};
  \node[#5,minimum height of three nodes={@1}{@2}{@3}] {#6};}
\begin{document}
\noindent
\begin{tikzpicture}[
  background rectangle/.style={fill=gray!25},
  show background rectangle, tight background,
  trim left=-.5\textwidth, trim right=.5\textwidth,
  every node/.style={outer sep=+0pt},
  Yellow/.style={fill=yellow},
  Blue/.style  ={fill=blue,   text=white},
  Red/.style   ={fill=red,   align=center},
  Green/.style ={fill=green, align=center},
  node distance=+0pt
]
\tikzthreenodessameheight
  [Yellow, name=sep]{}
  [Blue, left=of sep, name=Blue-left,
   text width between={-.5\textwidth,0 and sep.west}]
  {scope 1, node 1 $\displaystyle e^x = \cfrac{1}{1 - \cfrac{x}{1 + x -
                          \cfrac{\frac{1}{2}x}{1 + \frac{1}{2}x - \ddots}}}$}
  [Blue, right=of sep, text width between={ .5\textwidth,0 and sep.east}, name=Blue-right]
  {scope 1, node 1};

\node[Red, below right=of Blue-left.south  west] (Red-left)  {scope 1,\\ node 2};
\node[Red, below right=of Blue-right.south west] (Red-right) {scope 1,\\ node 2};

\node[Green, below left=of Blue-left.south east,
     text width between=Red-left.east and Blue-left.east]
  (Red-left) {scope 1, node 3 that includes longer text to be broken into lines};

\node[Green, below left=of Blue-right.south east,
     text width between=Red-right.east and Blue-right.east]
  (Red-left) {scope 2, node 3 which also includes longer text to be broken into lines
    \dots\ and here's an extra linre};
\end{tikzpicture}
\end{document}

Output

enter image description here

Related Question