
Quiero crear la siguiente imagen tikz:
Lo que tengo en este momento es esto:
\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}
Necesito ayuda con dos cosas:
¿Cómo puedo definir el ancho del nodo
n3
para que el ancho total den2
yn3
sea el den1
(que es.5\textwidth
)? Por el momento lo configuré en 5,1 cm porque se ve bien, pero si cambio el contenido del nodo 2, la dimensión del nodo 3 también debería cambiar. ¿Cómo puedo utilizar el cuadro delimitador que creé para el primer alcance?¿Cómo puedo insertar un separador entre los dos visores (como el dibujado en amarillo en la primera foto)? ¿Por qué el ancho de los dos ámbitos se extiende más allá
textwidth
? Aunque hay un margen gris a la izquierda y a la derechaouter sep=0pt
.
Respuesta1
El rectángulo de fondo tiene un relleno (que se llama ), por lo que se muestra más en gris que el contenido real. Usarinner frame [xy]sep
tight background
para cambiar esto.
Además, el ancho de la línea (de cualquier camino, no solo de los nodos, independientemente de los espacios exteriores) contribuirá al cuadro delimitador final de la imagen, lo que también altera un poco la ubicación final de la imagen (y conducirá a un hbox excesivo).
En su configuración original, puede sobrescribir la medida horizontal del cuadro delimitador usando trim left=0pt, trim right=\textwidth
. En mi código a continuación, lo estoy usando ±.5\textwidth
porque creo la imagen centrada en el origen.
Para crear nodos que tienen tamaños relacionados con otros nodos, son la fit
biblioteca que funciona estableciendo el ancho/alto/profundidad del texto, lo cual es malo si desea que los nodos realmente tengan texto.
Mi ext.positioning-plus
biblioteca hace cosas similares usando la fit
biblioteca, pero controla el tamaño del nuevo nodo usando minimum width
y minimum height
cuál es mejor para tener texto en el nodo, pero necesita un poco de trabajo para el texto que es más largo de lo que cabe en el nodo.
Estoy usando aquí una text width between
clave muy básica que usa la calc
biblioteca para medir la distancia entre dos puntos arbitrarios en elXdimensión y la utiliza para establecer la text width
del nodo. Necesitamos restar inner xsep
dos veces aquí (para que el nodo final realmente cubra el áreaconxsep interior). Esta es básicamente una manera de establecer unancho fijoen lugar de un ancho mínimo. (El factor 2 es diferente para otras formas).
Para sincronizar tamaños de nodos, puedo ofrecer elext.node-families
bibliotecade mitikz-ext
paquete.
Cada nodo que se ha node family={height=row1}
configurado comparte lo mismo minimum height
. Esto alineará los textos en cada nodo verticalmente centrados.
Tanto los nodos azules como el separador amarillo (también un nodo) abarcarán el mismo espacio vertical.
Código (familia de nodos)
\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}
Código (sin familia de nodos)
\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}
Producción
Respuesta2
Con un ráster tcbraster
(o tcbitemize) from
tcolorbox \texwidth` de forma predeterminada, cada columna ráster tiene el mismo ancho, pero también es posible ajustarlas manualmente., we can leave the package to do all the work for us. The
use
\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage[most]{tcolorbox}
\begin{document}
\begin{tcbitemize}[raster every box/.style={sharp corners,
fontupper=\sffamily, colupper=white, boxrule=0pt, halign=center},
raster left skip=0pt, raster right skip=0pt,
raster before skip=0pt, raster row skip=0pt,
raster after skip=0pt, raster valign=top]
\tcbitem[colback=blue!90!black] scope 1, node 1
\tcbitem[colback=blue!90!black] scope 2, node 1
\tcbitem[blankest, raster column skip=0pt]
\begin{tcbitemize}[raster force size=false]
\tcbitem[colback=red!90!black, width=.4\linewidth] scope 1, node 2
\tcbitem[colback=green!90!black, width=.6\linewidth] scope 1, node 3 that includes longer text to be broken into lines
\end{tcbitemize}
\tcbitem[blankest, raster column skip=0pt]
\begin{tcbitemize}[raster force size=false]
\tcbitem[colback=red!90!black, width=.4\linewidth] scope 2, node 2
\tcbitem[colback=green!90!black, width=.6\linewidth] scope 2, node 3 which also includes longer text to be broken into lines
\end{tcbitemize}
\end{tcbitemize}
\end{document}
Respuesta3
Intenté mantenerme cerca de tu código inicial. Sin embargo, hay una cuestión que no se considera: ¿qué sucede si la altura del nodo superior derecho es mayor que la altura del nodo superior izquierdo? Una solución podría ser revertir la construcción y que el nodo superior derecho sea la referencia.
El código
\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{lipsum}
\usepackage{tikz}
\usetikzlibrary{calc, positioning}
\begin{document}
\lipsum[1]
\bigskip
\tikzset{%
T/.style={blue!50!black, fill=blue!50!black, text=white,
minimum width=0.48\textwidth, text width=0.48\textwidth-1ex
},
BW/.style={green!50!black, fill=green!70!black, text=black,
minimum width=0.17\textwidth, text width=0.17\textwidth-1ex
},
BE/.style={red!75!black, fill=red!95!black, text=black,
minimum width=0.30\textwidth, text width=0.30\textwidth-1ex,
}
}
\noindent\begin{tikzpicture}[%
every node/.style={draw, inner sep=1ex, outer sep=0pt, align=center,
minimum height=7ex}
]
\node[T, anchor=north west] at (0, 0)
(nTW) {\bfseries \lipsum[2]};
\node[BW, below=0pt of nTW.south west, anchor=north west]
(n2) {scope 1, node 2};
\node[BE, below left=0pt and 0pt of n2.north east, anchor=north west]
(n3) {scope 1, node 3 that includes longer text to be broken into lines};
\path ($(nTW.south) -(nTW.north)$);
\pgfgetlastxy{\newW}{\newH}
\node[T, right=.02\textwidth of nTW.north east,
anchor=north west, minimum height={-\newH}]
(nTE) {\bfseries scope 2, node 1};
\node[BW, below=0pt of nTE.south west, anchor=north west]
(n2E) {scope 2, node 2};
\node[BE, below left=0pt and 0pt of n2E.north east, anchor=north west]
(n3E) {scope 2, node 3 that includes longer text to be broken
into lines; can be longer than the West corresponding node};
\fill[yellow!90!red] (nTW.north east) rectangle (nTE.south west);
\end{tikzpicture}
\end{document}
Respuesta4
Sugerencia alternativa. Mi código es menos técnico (¿pero quizás también menos elegante?).
Puede ajustar el ancho del separador amarillo ( \yellowGap
en mi código) y el porcentaje del ancho del nodo 1 ( percentAmount
, un número entero entre 0 y 100, pero es mejor no elegir un valor demasiado cercano a 0 o 100 para evitar columnas estrechas), para obtener el ancho del nodo 2.
Por último, puede ajustar la longitud del espacio interior en los nodos \innerXSep
.
\documentclass[a4paper,10pt]{article}
\usepackage[showframe]{geometry}
\usepackage[x11names]{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{calc}
\newlength{\yellowGap}
\setlength{\yellowGap}{3mm}
\newcounter{percentAmount}
\setcounter{percentAmount}{40}% =40% of the width of the first node. Value needs to be integer
\newlength{\innerXSep}
\setlength{\innerXSep}{.3333em}% default value
\newlength{\mainNodeWidth}
\setlength{\mainNodeWidth}{(\textwidth-\yellowGap)/2}
\newlength{\secondNodeWidth}
\setlength{\secondNodeWidth}{\mainNodeWidth*\value{percentAmount}/100}
\newlength{\thirdNodeWidth}
\setlength{\thirdNodeWidth}{\mainNodeWidth-\secondNodeWidth}
\begin{document}
\noindent\begin{tikzpicture}[outer sep=0pt,inner xsep=\innerXSep,text=white]
\node[text width=\mainNodeWidth-2\innerXSep,fill=DodgerBlue3,align=center] (mainLeft) {Scope 1, Node 1};
\node[text width=\secondNodeWidth-2\innerXSep,fill=Firebrick2,align=center,anchor=north west] (secondLeft) at (mainLeft.south west) {Scope 1,\\Node 2};
\node[text width=\thirdNodeWidth-2\innerXSep,fill=Green3,align=center,anchor=north west] (thirdLeft) at (secondLeft.north east) {Scope 1, Node 3\\ that includes longer text to be broken into lines};
\fill[DarkGoldenrod1] (mainLeft.north east) rectangle ($(mainLeft.south east)+(\yellowGap,0)$);
\node[text width=\mainNodeWidth-2\innerXSep,fill=DodgerBlue3,align=center,anchor=north west] (mainRight) at ($(mainLeft.north east)+(\yellowGap,0)$) {Scope 2, Node 1};
\node[text width=\secondNodeWidth-2\innerXSep,fill=Firebrick2,align=center,anchor=north west] (secondRight) at (mainRight.south west) {Scope 2,\\Node 2};
\node[text width=\thirdNodeWidth-2\innerXSep,fill=Green3,align=center,anchor=north west] at (secondRight.north east) {Scope 2, Node 3\\ which also includes longer text to be broken into lines};
\end{tikzpicture}
\end{document}