2

This question is an extension of this one.

That question is about drawing a path in the background of nodes. There are three nodes equally separated on a line, and there is a straight line connecting all three in the background such that the middle one is not crossed visually. The nodes are filled, so the part of the path underneath the middle node is not visible (because it is behind the filling so to speak).

I want to achieve the same with transparent nodes (without filling) so that I can reuse the figure in different contexts (posters/slides) without the need to recolor the filling.

Here's my MWE (mostly borrowed from the same question)

\documentclass[border=20pt]{standalone}
\usepackage{tikz}
\pgfdeclarelayer{bg}
\pgfsetlayers{bg,main}
\begin{document}
\begin{tikzpicture}
  \node [draw] (foo) at (0,0) { foo };
  \node [draw] (bar) at (2,0) { bar };
  \node [draw] (baz) at (4,0) { baz };

  \begin{pgfonlayer}{bg}
    \draw [pink] (foo) -- (baz) ;
    \draw [cyan] (foo.25) -- (bar.155) (bar.25) -- (baz.155) ;
  \end{pgfonlayer}
\end{tikzpicture}
\end{document}

Which compiles to

enter image description here

The desired behavior can be achieved similarly to how the cyan line is drawn, but that notation is very long when there are more nodes and even longer when the line goes not through the vertical center, as here. Moreover, if I decide to add more nodes, I will have to correct all that code over and over again.

Is there any trick to produce a line like the cyan one by specifying its coordinates only at the outermost nodes?

6
  • 1
    I don't have time to check how they do exactdy, but tcolorbox seems to use clip and scope to do something along that line p194 mirror.ibcp.fr/pub/CTAN/macros/latex/contrib/tcolorbox/…
    – tobiasBora
    May 4, 2023 at 21:17
  • Just to make sure, but I take it that \draw [pink] (foo) -- (bar) -- (baz); is not a solution for you? May 4, 2023 at 22:10
  • @JasperHabicht it is, but unfortunately only for the lines that connect centers of nodes. If I want to connect different parts of nodes (like the cyan line does), I have to specify each middle node twice. It should be possible though to use your syntax and yshift a line like here. That won't work with non-rectangular nodes, but that's not my case currently, so thanks for the suggestion!
    – And R
    May 5, 2023 at 6:50
  • The main problem is that transparent nodes are just that: transparent. If you place a line behind them, it will be visible. A simple workaround could be to define the color of the background separately using something like \colorlet{bgcolor}{yellow} and fill all nodes with this color. This way it would be easy to change the background color (and that of the nodes). Another way to go would be to inversely clip the nodes from the line (see my answer), but this is admittedly a bit tricky. May 5, 2023 at 6:54
  • 1
    If you load the cd library (or the tikz-cd package), you can use \draw [cyan, commutative diagrams/shift left=5pt] (foo) to (bar); \draw [cyan, commutative diagrams/shift left=5pt] (bar) to (baz); (There is room for improvement to have a neater input syntax.) I believe this to be the best solution because you don't have to play around with clips or transform canvas which can have other side effects. May 5, 2023 at 9:13

2 Answers 2

2

Lines between nodes in ordered in line you can simpli draw, by use of join macro defined in the chains library. Also code is very simple, special if distances between nodes are equal:

\documentclass[border=20pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{chains,
                positioning}

\begin{document}
    \begin{tikzpicture}[
node distance = 10mm,
  start chain = going right,
   arr/.style = {draw=red, semithick},
N/.style = {draw, fill=gray, text opacity=1,
            on chain, join=by arr}
                        ]
  \node [N] (foo)   { foo };
  \node [N, fill opacity=0] (bar)   { bar };
  \node [N] (baz)   { baz };
  \node [N] (foo)   { foo };
  \node [N, fill opacity=0] (bar)   { bar };
  \node [N] (baz)   { baz };
    \end{tikzpicture}
\end{document}

enter image description here

2
  • Thanks for the answer, very simple syntax indeed. Is there a way to shift the red line a bit closer to the north of each node, like the cyan line in my question?
    – And R
    May 5, 2023 at 7:15
  • @AndR, unfortunately no (at least so simple).
    – Zarko
    May 5, 2023 at 7:54
1

Let me try with a combination of different other solutions (but mainly this one). It would only work with rectangular nodes though:

\documentclass[border=10pt]{standalone}
\usepackage{tikz}

\tikzset{
    clip even odd rule/.code={\pgfseteorule}, % Credit to Andrew Stacey 
    inverse clip/.style={
        clip,
        insert path={
            [clip even odd rule] {
               [reset cm] (-\maxdimen,-\maxdimen) rectangle (\maxdimen,\maxdimen)
            }
        }
    },
    cut out/.code={
        \begin{pgfinterruptboundingbox}
            \clip[inverse clip]
                (#1.north east) -- (#1.north west) -- (#1.south west) -- (#1.south east) -- cycle;
        \end{pgfinterruptboundingbox}
    }
}

\begin{document}
\begin{tikzpicture}

    \fill[yellow!50] (-1,-1) rectangle (7,3);

    \node[draw] (foo) at (0,0) { foo };
    \node[draw] (bar) at (2,0) { bar };
    \node[draw] (baz) at (4,0) { baz };
    
    \begin{scope}
        \draw[red, cut out={bar}] (foo) -- (baz);
    \end{scope}

    \node[draw] (Foo) at (0,2) { foo };
    \node[draw] (Bar) at (2,2) { bar };
    \node[draw] (Baz) at (4,2) { baz };
    \node[draw] (Qux) at (6,2) { qux };

    \begin{scope}
        \draw[red, cut out={Bar}, cut out={Baz}] (Foo.25) -- (Qux.155);
    \end{scope}

    % to show that scoping works
    \draw[cyan] (bar.south) -- (Bar.north);

\end{tikzpicture}
\end{document}

enter image description here

I hope that this does not break too many things. And maybe someone has an idea how to avoid the necessary scoping even ...

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .