Wie kann ich einen Knoten auf einer anderen Ebene als der Linie festlegen?

Wie kann ich einen Knoten auf einer anderen Ebene als der Linie festlegen?

Ist es möglich, festzulegen, dass sich Knoten in Zeilen auf der Hauptebene befinden, unabhängig davon, ob sich Zeilen auf der Hintergrundebene befinden? Beispiel: Bildbeschreibung hier eingeben

Mit folgendem MWE:

\documentclass[12pt,tikz,border=3mm]{standalone}
    \usetikzlibrary{arrows,arrows.meta,%
        backgrounds,positioning}
\pgfdeclarelayer{foreground} 
\pgfdeclarelayer{background}
   \pgfsetlayers{background,main,foreground}

    \usepackage{amsmath}
\begin{document}
    \begin{tikzpicture}[
    node distance = 0mm,
        LC/.style = {draw=#1,
            line width=1mm,
            arrows={-Stealth[fill=#1,inset=0pt,length=0pt 1.6,angle'=90]},
            },
         X/.style = {draw, very thin, fill=white, fill opacity=0.75,
            font=\scriptsize,
            text=black, text opacity=1, align=left,
            inner sep=2pt, sloped, anchor=west,pos=0.07},
                        ]\sffamily
%---
\linespread{0.8}
%-------
\coordinate                     (a0)    at (0,0);
\coordinate[right=77mm of a0]   (b0);
    \foreach \i [count=\xi from 0] in {1,2,...,4}
{
    \coordinate[below=7mm of a\xi]  (a\i);
    \coordinate[below=7mm of b\xi]  (b\i);
}
\draw[|->]  (a0) -- (a3) node[above left]   {$t$};
\draw[|->]  (b0) -- (b3) node[above right]  {$t$};
\draw[LC=gray]  (a1)
    to node[X] {data\\
                $(\text{SeqNum}=0,\ell=1000)$}
                (b2);
%-------
    \begin{scope}[ X/.append style={anchor=east},
                  LC/.append style={transform canvas={yshift=-2mm}},
                  on background layer]
\draw[LC=teal]  (b1)
    to node[X] {ACK(AckNum$=$1000)}
                (a2);
   \end{scope}
%----------------
    \end{tikzpicture}
        \end{document}

Ich bekomme:

Bildbeschreibung hier eingeben

Das erste Bild erhalte ich, indem ich die zweiten Linien zweimal zeichne: zuerst als Linie und darüber noch einmal eine unsichtbare mit Knoten. Da meine aktuellen Diagramme bis zu einem Dutzend solcher Linien haben, suche ich nach bequemeren Lösungen, um zu deklarieren, dass die Knoten in der Hauptebene liegen, auch wenn die Linie im Hintergrund ist.

Antwort1

Lass uns mit Kisten spielen.

Irgendwann führt TikZ die Schlüssel einbehind pathund in front of path(zum Zurückschalten), was im Grunde das eine oder andere Pfadfeld angibt, auf dem die Knoten platziert werden. Wenn der Pfad schließlich gezeichnet wird (innerhalb des ;Pfadendes), werden diese Felder „verwendet“:

  1. der Hintergrund ( \tikz@figbox@bg)
  2. der eigentliche Pfad wird gezeichnet
  3. der Vordergrund ( \tikz@figbox, der Standard für Knoten)

Wenn TikZ einen Knoten auf dem Pfad findet,ziehtes zeichnet den Knoten auf einem dieser beiden Kästchen.

Diese Boxen werden am Anfang des Pfads zurückgesetzt. Diese Boxen sind der Grund dafür, dass Knoten über ihren Pfaden platziert werden (obwohl sie ursprünglich ihre eigenen Pfade sind).


Mit demPGF-Schichten, passiert etwas sehr Ähnliches, aber statt nur einem Knoten wird alles zwischen \begin{pgfonlayer}und \end{pgfonlayer}in dieser Box platziert.

Am Ende des Bildes werden diese Kästchen „verwendet“. (Es gibt noch ein paar zusätzliche Dinge, die ich für das Verschachteln von Bildern halte.)

Anstatt den Knoten nun auf der Box zu platzieren, die von TikZ verwendet wird, ;können wirversuchenum es direkt auf einer der Ebenen zu platzieren.

Da dies irgendwo tief in einigen wenigen Gruppen geschieht, muss dies global sein (und \pgfonlayerist es tatsächlich auch global, da es irgendwo innerhalb eines Bereichs verwendet werden kann – und das wird es tatsächlich, wenn Sie verwenden on background layer).


Um dies zu implementieren, tausche ich eines \setbox(glücklicherweise das erste) gegen ein benutzerdefiniertes aus \tikz@setbox@which– das so belassen wird, \setboxdass es wie gewohnt funktioniert – innerhalb des Makros, das den Knoten für den Pfad auf dieser Box platziert.

Der node on layerSchlüssel bewirkt lediglich, dass \tikz@setbox@whicheine globale Aktion ausgeführt wird \setboxund dass die Box eine der Ebenen und nicht eine der Pfadboxen ist.

Nun können Sie sagen:

\begin{scope}[
  X/.append style={anchor=east},
  LC'/.style={yshift=-2mm}, % no transform canvas
  on background layer]
\draw[LC=teal] ([LC'] b1) % ........ ←
  to node[X, node on layer=foreground] {ACK(AckNum$=$1000)} ([LC'] a2);
\end{scope}

Und hier zeigt sich schon, was hier nicht funktioniert:

  • Die mainEbene kann nicht ausgewählt werden (es handelt sich um eine spezielle Ebene, die mit beiden nicht ausgewählt werden kann \pgfonlayer).

  • transform canvasfunktioniert nicht (aber auch nicht mit behind path). Es gibt vielleicht Möglichkeiten, das Problem zu umgehen, aber das Handbuch empfiehlt:

    Kurz gesagt: Sie sollten keine Canvas-Transformationen verwenden, es sei denn, Sie wissen wirklich, was Sie tun.

    Und ich füge hinzu… es sei denn, Sie brauchen es wirklich.

    Ich habe Ihre Ergänzung LCdurch eine normale Transformation innerhalb des LC'Schlüssels ersetzt, die manuell zu jeder Koordinate hinzugefügt wird. (Ich wünschte, es gäbe eine Möglichkeit, Koordinaten/Knoten zu „entfixieren“, sodass sie als normale Koordinaten fungieren und die Transformationen auch auf sie angewendet werden, aber selbst das Handbuch bietet nurein @-lastiger Workaround.)

Verwenden Sie es außerdem nicht mit etwas anderem als Knoten. Das „Decider“-Makro \tikz@whichboxwird nicht nur für Knoten, sondern auch für Kanten, Plotmarkierungen, Matrizen, untergeordnete Knoten (nicht dasselbe wie einfache Knoten) und Bilder verwendet. Die Verwendung \node on layerdort funktioniert nicht, im besten Fall werden Ihre Kanten, Plotmarkierungen, Matrizen, untergeordneten Knoten und Bilder einfach nicht angezeigt. (Weil die Ergänzung zur Box nach dem aktuellen Pfad sowieso vergessen wird.) Dafür müssen weitere Patches durchgeführt werden.


Sie können jedoch auch einfach einen leeren Knoten/eine leere Koordinate entlang des Pfads platzieren (um die Position und die Drehung zu speichern) und diesen dann referenzieren, indem Sie den eigentlichen Knoten am Ende der gesamten Linienzeichnung platzieren. Allerdings ist dafür einiges an Organisation erforderlich, um die Verwendung zu vereinfachen.

Und dann ist da noch das GanzeVerzögerte Knotenpositionierungwo Sie zuerst einen Knoten „erstellen“, ihn aber später platzieren (wird von forestder Graphenzeichnungsbibliothek verwendet). Das ist allerdings auch nicht sehr einfach. (Mehr Kästchen!)

Code

\documentclass[12pt, tikz, border=3mm]{standalone}
\usetikzlibrary{arrows, arrows.meta, backgrounds, positioning}
\pgfdeclarelayer{foreground}\pgfdeclarelayer{background}
\pgfsetlayers{background,main,foreground}
\makeatletter\ExplSyntaxOn % replace only first one
\tl_replace_once:Nnn \tikz@fig@continue { \setbox } { \tikz@setbox@which }
\ExplSyntaxOff
\let\tikz@setbox@which\setbox
\tikzset{node on layer/.code={%
  \expandafter\def\expandafter\tikz@whichbox\expandafter
    {\csname pgf@layerbox@#1\endcsname}%
  \def\tikz@setbox@which{\global\setbox}}}
\makeatother
\usepackage{amsmath}
\begin{document}
\begin{tikzpicture}[
  node distance = 0mm,
  LC/.style = {draw=#1, line width=1mm,
    arrows={-Stealth[fill=#1,inset=0pt,length=0pt 1.6,angle'=90]}},
  X/.style = {draw, very thin, fill=white, fill opacity=0.75,
    font=\scriptsize, text=black, text opacity=1, align=left,
   inner sep=2pt, sloped, anchor=west,pos=0.07}]
\sffamily\linespread{0.8}

\coordinate                     (a0)    at (0,0);
\coordinate[right=77mm of a0]   (b0);
\foreach \i [count=\xi from 0] in {1,2,...,4}
  \coordinate[below=7mm of a\xi]  (a\i)
   coordinate[below=7mm of b\xi]  (b\i);
\draw[|->] (a0) -- (a3) node[above left]   {$t$};
\draw[|->] (b0) -- (b3) node[above right]  {$t$};
\draw[LC=gray] (a1) to node[X] {data\\$(\text{SeqNum}=0,\ell=1000)$} (b2);

\begin{scope}[
  X/.append style={anchor=east},
  LC'/.style={yshift=-2mm}, % no transform canvas
  on background layer]
\draw[LC=teal] ([LC'] b1)
  to node[X, node on layer=foreground] {ACK(AckNum$=$1000)} ([LC'] a2);
\end{scope}
\end{tikzpicture}
\end{document}

Ausgabe

Bildbeschreibung hier eingeben

Antwort2

Wie wäre es, den Knoten mit einem nachfolgenden Pfadbefehl auf der vorderen Ebene zu platzieren:

\path (b1) to node[X,anchor=east,yshift=-2mm] {ACK(AckNum$=$1000)} (a2);

Hier ist das vollständige Dokument:

\documentclass[12pt,tikz,border=3mm]{standalone}
\usetikzlibrary{arrows,arrows.meta,backgrounds,positioning}
\pgfdeclarelayer{foreground} 
\pgfdeclarelayer{background}
\pgfsetlayers{background,main,foreground}
\usepackage{amsmath}

\begin{document}

\begin{tikzpicture}
  [
    node distance = 0mm,
    LC/.style = {draw=#1,
                 line width=1mm,
                 arrows={-Stealth[fill=#1,inset=0pt,length=0pt 1.6,angle'=90]},
                },
    X/.style = {draw, 
                very thin, 
                fill=white, 
                fill opacity=0.75,
                font=\scriptsize,
                text=black, 
                text opacity=1, 
                align=left,
                inner sep=2pt, 
                sloped, 
                anchor=west,
                pos=0.07},
  ]
 \sffamily
%---
  \linespread{0.8}
%-------
  \coordinate                     (a0)    at (0,0);
  \coordinate[right=77mm of a0]   (b0);
  \foreach \i [count=\xi from 0] in {1,2,...,4}
    {
      \coordinate[below=7mm of a\xi]  (a\i);
      \coordinate[below=7mm of b\xi]  (b\i);
    } 
  \draw[|->]  (a0) -- (a3) node[above left]   {$t$};
  \draw[|->]  (b0) -- (b3) node[above right]  {$t$};
  \draw[LC=gray]  (a1)
                  to 
                  node[X] {data\\
                  $(\text{SeqNum}=0,\ell=1000)$}
                  (b2);
%-------
  \begin{scope}[X/.append style={anchor=east},
                LC/.append style={transform canvas={yshift=-2mm}},
                on background layer]
    \draw[LC=teal]  (b1)
                    to 
                    (a2);
 \end{scope}
%----------------
  \path (b1) to node[X,anchor=east,yshift=-2mm] {ACK(AckNum$=$1000)} (a2);
\end{tikzpicture}
\end{document}

Bildbeschreibung hier eingeben

verwandte Informationen