4

Using the combo of tikz extension libraries positioning-plus and node-families by qrrbrbirlbel to draw a flowchart. Using node-families to equally size 2 parallel nodes. This issue is that if a custom fill color is used for a node the fill comes in front of the text. Identified that the issue comes from the node-families library. Tried using both texlive and MiKTeX 2019 without any difference in the result.

Is this due to update in tikz/pgf causing the library to fail? In this example by the library author, it seems to compile correctly without any modification.

Example with node-families and text being covered by the nodes fill:

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{shapes.geometric,backgrounds,fit,calc,positioning-plus,node-families}

\tikzset{
  basic box/.style = {
    shape = rectangle,
    align = center,
    draw  = #1,
    fill  = #1!25,
    rounded corners},
  header node/.style = {
    Minimum Width = header nodes,
    font          = \strut\Large\ttfamily,
    text depth    = +0pt,
    fill          = white,
    draw},
  header/.style = {%
    inner ysep = +1.5em,
    append after command = {
      \pgfextra{\let\TikZlastnode\tikzlastnode}
      node [header node] (header-\TikZlastnode) at (\TikZlastnode.north) {#1}
      node [span = (\TikZlastnode)(header-\TikZlastnode)]
        at (fit bounding box) (h-\TikZlastnode) {}
    }
  },
  hv/.style = {to path = {-|(\tikztotarget)\tikztonodes}},
  vh/.style = {to path = {|-(\tikztotarget)\tikztonodes}},
  fat blue line/.style = {ultra thick, blue}
}

\begin{document}

\begin{tikzpicture}[node distance = 1.2cm, thick, nodes = {align = center},>=latex]
  \node[Minimum Width = loop, shape = ellipse, fill = red] (imp-sol) {ellipsoid box};
  \node[Minimum Width = loop, fill = yellow, below = of imp-sol] (rec-box)
    {rectangular box, and very wiiiiiiiiiiiiiiide\\2nd line};
  \node[shift = (left:.5*x_node_dist)] at
    ($(imp-sol.west|-imp-sol.south)!.5!(rec-box.north west)$) (for-1)
    {formula 1};
  \node[shift = (right:.5*x_node_dist)] at
    ($(imp-sol.east|-imp-sol.south)!.5!(rec-box.north east)$) (for-2)
    {formula 2};
  \begin{scope}[on background layer]
    \node[fit = (for-1)(for-2)(imp-sol)(rec-box), basic box = blue,
      header = DMFT loop] (dmft-l) {};
  \end{scope}
  \path[very thick, blue, hv] (rec-box) edge[->] (for-1) edge[<-] (for-2)
                              (imp-sol) edge[->] (for-2) edge[<-] (for-1);
\end{tikzpicture}

\end{document}

enter image description here

Example without node-families:

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{shapes.geometric,backgrounds,fit,calc,positioning-plus}

\tikzset{
  basic box/.style = {
    shape = rectangle,
    align = center,
    draw  = #1,
    fill  = #1!25,
    rounded corners},
  header node/.style = {
    font          = \strut\Large\ttfamily,
    text depth    = +0pt,
    fill          = white,
    draw},
  header/.style = {%
    inner ysep = +1.5em,
    append after command = {
      \pgfextra{\let\TikZlastnode\tikzlastnode}
      node [header node] (header-\TikZlastnode) at (\TikZlastnode.north) {#1}
      node [span = (\TikZlastnode)(header-\TikZlastnode)]
        at (fit bounding box) (h-\TikZlastnode) {}
    }
  },
  hv/.style = {to path = {-|(\tikztotarget)\tikztonodes}},
  vh/.style = {to path = {|-(\tikztotarget)\tikztonodes}},
  fat blue line/.style = {ultra thick, blue}
}

\begin{document}

\begin{tikzpicture}[node distance = 1.2cm, thick, nodes = {align = center},>=latex]
  \node[shape = ellipse, fill = red] (imp-sol) {ellipsoid box};
  \node[fill = yellow, below = of imp-sol] (rec-box)
    {rectangular box, and very wiiiiiiiiiiiiiiide\\2nd line};
  \node[shift = (left:.5*x_node_dist)] at
    ($(imp-sol.west|-imp-sol.south)!.5!(rec-box.north west)$) (for-1)
    {formula 1};
  \node[shift = (right:.5*x_node_dist)] at
    ($(imp-sol.east|-imp-sol.south)!.5!(rec-box.north east)$) (for-2)
    {formula 2};
  \begin{scope}[on background layer]
    \node[fit = (for-1)(for-2)(imp-sol)(rec-box), basic box = blue,
      header = DMFT loop] (dmft-l) {};
  \end{scope}
  \path[very thick, blue, hv] (rec-box) edge[->] (for-1) edge[<-] (for-2)
                              (imp-sol) edge[->] (for-2) edge[<-] (for-1);
\end{tikzpicture}

\end{document}

enter image description here

2 Answers 2

4

Welcome to TeX-SE! I can offer you a workaround/fix that addresses the question raised in the title: "How to prevent tikz custom node fill from covering the text when using node-families library?". However, I won't address the question "Is this due to update in tikz/pgf causing the library to fail?". The fix is to use path pictures for the fills.

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{shapes.geometric,backgrounds,fit,calc,positioning-plus,node-families}

\tikzset{
  basic box/.style = {
    shape = rectangle,
    align = center,
    draw  = #1,
    fill  = #1!25,
    rounded corners},
  header node/.style = {
    Minimum Width = header nodes,
    font          = \strut\Large\ttfamily,
    text depth    = +0pt,
    Fill          = white, %<- !!!
    draw},
  header/.style = {%
    inner ysep = +1.5em,
    append after command = {
      \pgfextra{\let\TikZlastnode\tikzlastnode}
      node [header node] (header-\TikZlastnode) at (\TikZlastnode.north) {#1}
      node [span = (\TikZlastnode)(header-\TikZlastnode)]
        at (fit bounding box) (h-\TikZlastnode) {}
    }
  },
  hv/.style = {to path = {-|(\tikztotarget)\tikztonodes}},
  vh/.style = {to path = {|-(\tikztotarget)\tikztonodes}},
  fat blue line/.style = {ultra thick, blue}
}
\tikzset{Node Options/.style={path picture={
   \path[#1] (path picture bounding box.south west)
   rectangle (path picture bounding box.north east);
  }},Fill/.style={Node Options={fill=#1}}}
\begin{document}

\begin{tikzpicture}[node distance = 1.2cm, thick, nodes = {align = center},>=latex]
  \node[Minimum Width = loop, shape = ellipse,Fill=red] (imp-sol) {ellipsoid box};
  \node[Minimum Width = loop,Fill = yellow, below = of imp-sol] (rec-box)
    {rectangular box, and very wiiiiiiiiiiiiiiide\\2nd line};
  \node[shift = (left:.5*x_node_dist)] at
    ($(imp-sol.west|-imp-sol.south)!.5!(rec-box.north west)$) (for-1)
    {formula 1};
  \node[shift = (right:.5*x_node_dist)] at
    ($(imp-sol.east|-imp-sol.south)!.5!(rec-box.north east)$) (for-2)
    {formula 2};
  \begin{scope}[on background layer]
    \node[fit = (for-1)(for-2)(imp-sol)(rec-box), basic box = blue,
      header = DMFT loop] (dmft-l) {};
  \end{scope}
  \path[very thick, blue, hv] (rec-box) edge[->] (for-1) edge[<-] (for-2)
                              (imp-sol) edge[->] (for-2) edge[<-] (for-1);
\end{tikzpicture}

\end{document}

enter image description here

Just for completeness: in this particular case a very similar output can be obtained with the standard libraries and without adding explicit distances by hand. But of course I do understand that there are examples in which Qrrbrbirlbel nice libraries are instrumental to do things automatically.

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{calc,fit,shapes.geometric,positioning,backgrounds}
\begin{document}

\begin{tikzpicture}[node distance=1.2cm, thick,nodes={align=center},>=latex,
    basic box/.style={shape=rectangle,align=center,draw=#1,fill=#1!25,rounded corners},
    hv/.style={to path={-|(\tikztotarget)\tikztonodes}}]
 \node[fill=yellow] (rec-box) {rectangular box, and very wiiiiiiiiiiiiiiide\\2nd line};
 \path let \p1=($(rec-box.east)-(rec-box.west)$) in 
 node[ellipse,fill=red,above=of rec-box,minimum width=\x1](imp-sol) {ellipsoid box};
 \path (rec-box.west) |-(imp-sol) node[pos=0.25,left](for-1) {formula 1}
 (rec-box.east) |-(imp-sol) node[pos=0.25,right](for-2) {formula 2};
  \begin{scope}[on background layer]
    \node[fit = (for-1)(for-2)(imp-sol)(rec-box),basic box=blue,
     inner ysep=1.5em,
      label={[anchor=center,fill=white,draw]above:DMFT loop}] (dmft-l) {};
  \end{scope}
  \path[very thick, blue, hv] (rec-box) edge[->] (for-1) edge[<-] (for-2)
                              (imp-sol) edge[->] (for-2) edge[<-] (for-1);
\end{tikzpicture}

\end{document}

enter image description here

3
  • Thanks, can confirm the fix works. Could you please clarify how does the workaround exactly work? If I understand correctly replace the normal fill with the newly defined one (Fill) which uses path picture. So what does the normal fill use?
    – user190623
    Jun 8, 2019 at 19:38
  • @nkk This answer is to some extent a gamble. I was looking for something that doesn't get "hacked" in Qrrbrbirlbel's libraries, and saw that path picture is such a thing. (Please do not get me wrong, these "hacks" are great!) A path picture allows you to put something on the background of a given path that gets clipped by the path, so it can be used in particular (but not only) for filling node paths. BTW, in this particular case you do not necessarily need these "hacks", you could go with a matrix, too.
    – user121799
    Jun 8, 2019 at 19:44
  • Great, this now makes sense. Started with tikz very recently and I'm loving it so far. For now, I'm using it for any diagrams that I need to get up to speed.
    – user190623
    Jun 8, 2019 at 19:53
0

Is this due to update in tikz/pgf causing the library to fail?

Yes it was. The inner workings of the node operation changed a lot between 2013 and 2019/2022. I have fixed this.

However, I've also created a new ext.node-families library as part of my tikz-ext package that works very differently and has two modes:

  1. One mode only compared the text box sizes (which doesn't help you here at all) and ignores the shape and the inner [xy]seps.

  2. The other mode uses the minimum width and minimum height again, however it doesn't make the node always wider, even if the nodes should be smaller.

    Since an ellipse uses somewhat different values to calculate its size in relation to the text and the inner seps, you'll need the ext.node-families.shapes.geometric library (which loads both ext.node-families and shapes.geometric) which contains the needed adjustments.

The header nodes will get the key node family/text width = header nodes and both the ellipse and the very wiiiide rectangle get node family/width = loop.

I have also replaced the positioning-plus with the ext.positioning-plus library (only needed for the math function x_node_dist).

Code

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{
  backgrounds, calc,
  ext.positioning-plus,
  ext.node-families.shapes.geometric% loads ext.node-families
                                    %   and shapes.geometric
}
\tikzset{
  basic box/.style = {
    shape = rectangle,
    align = center,
    draw  = #1,
    fill  = #1!25,
    rounded corners},
  header node/.style = {
    node family/text width = header nodes,
    font          = \strut\Large\ttfamily,
    text depth    = +0pt,
    fill          = white,
    draw},
  header/.style = {%
    inner ysep = +1.5em,
    append after command = {
      \pgfextra{\let\TikZlastnode\tikzlastnode}
      node [header node] (header-\TikZlastnode) at (\TikZlastnode.north) {#1}
      node [span = (\TikZlastnode)(header-\TikZlastnode)]
        at (fit bounding box) (h-\TikZlastnode) {}
    }
  },
  hv/.style = {to path = {-|(\tikztotarget)\tikztonodes}},
  vh/.style = {to path = {|-(\tikztotarget)\tikztonodes}},
  fat blue line/.style = {ultra thick, blue}
}

\begin{document}
\begin{tikzpicture}[
  node distance = 1.2cm, thick, nodes = {align = center}, >=latex]
\node[shape = ellipse, node family/width = loop, fill = red]
  (imp-sol) {ellipsoid box};
\node[fill = yellow, node family/width = loop, below = of imp-sol]
  (rec-box) {rectangular box, and very wiiiiiiiiiiiiiiide\\2nd line};
\node[shift = (left:.5*x_node_dist)] at
  ($(imp-sol.west|-imp-sol.south)!.5!(rec-box.north west)$) (for-1)
  {formula 1};
\node[shift = (right:.5*x_node_dist)] at
  ($(imp-sol.east|-imp-sol.south)!.5!(rec-box.north east)$) (for-2)
  {formula 2};
\begin{scope}[on background layer]
  \node[fit = (for-1)(for-2)(imp-sol)(rec-box), basic box = blue,
    header = DMFT loop] (dmft-l) {};
\end{scope}
\path[very thick, blue, hv] (rec-box) edge[->] (for-1) edge[<-] (for-2)
                            (imp-sol) edge[->] (for-2) edge[<-] (for-1);
\end{tikzpicture}
\end{document}

Output

enter image description here

You must log in to answer this question.