TransWikia.com

How can label nodes be conditionally inserted into TikZ paths?

TeX - LaTeX Asked on July 22, 2021

MWE:

documentclass[border = 10pt]{standalone}

usepackage{ifthen}
usepackage{tikz}
usetikzlibrary{calc}

begin{document}
begin{tikzpicture}[every node/.style = {align = center}]
    newcounter {lfpnode}
    coordinate (LFP) at (0,0);
    newcommand {drawaline} [3] {
        ifthenelse{equal{#2}{}}
            {deftdsdabovespec{}}
            {deftdsdabovespec{node[above] unexpanded{{#2}}}}

        coordinate (LFPS) at ($(LFP) - (0,{#1})$);
        ifthenelse{equal{#3}{}} {
            deftdsdnewLFP{LFPS}
            deftdsdbelowspec{}
        }{
            edeftdsdlfpnode{LFPNarabic{lfpnode}}
            deftdsdnewLFP{0,0 |- tdsdlfpnode.south}
            deftdsdbelowspec{node[below] (tdsdlfpnode) unexpanded{{#3}}}
        }

            % this doesn't work
            deftdsddataflowspec{[blue] (0,0 |- LFPS) -> tdsdabovespec tdsdbelowspec (5,0 |- LFPS)}
            expandafterdrawtdsddataflowspec;

            % neither does this, although I didn't expect it to
            draw [blue] (0,0 |- LFPS) -> tdsdabovespec tdsdbelowspec (5,0 |- LFPS);

        coordinate (LFP) at (tdsdnewLFP);
        stepcounter{lfpnode}
    }

    newcommand {drawalineone} [1] {
        deftdsdnewLFP{LFPS}
        coordinate (LFPS) at ($(LFP) - (0,{#1})$);

            draw [blue] (0,0 |- LFPS) -> node[above] {ABOVE1-1ABOVE1-2} (5,0 |- LFPS);

        coordinate (LFP) at (tdsdnewLFP);
        stepcounter{lfpnode}
    }

    newcommand {drawalinetwo} [1] {
        coordinate (LFPS) at ($(LFP) - (0,{#1})$);
        edeftdsdlfpnode{LFPNarabic{lfpnode}}
        deftdsdnewLFP{0,0 |- tdsdlfpnode.south}

            draw [blue] (0,0 |- LFPS) -> node[above] {ABOVE2-1} node[below]
                (tdsdlfpnode) {BELOW2-1} (5,0 |- LFPS);

        coordinate (LFP) at (tdsdnewLFP);
        stepcounter{lfpnode}
    }

    newcommand {drawalinethree} [1] {
        coordinate (LFPS) at ($(LFP) - (0,{#1})$);
        edeftdsdlfpnode{LFPNarabic{lfpnode}}
        deftdsdnewLFP{0,0 |- tdsdlfpnode.south}

            draw [blue] (0,0 |- LFPS) -> node[below] (tdsdlfpnode) {BELOW3-1BELOW3-2} (5,0 |- LFPS);

        coordinate (LFP) at (tdsdnewLFP);
        stepcounter{lfpnode}
    }

    % The following causes errors aplenty:
    %    "Cannot parse this coordinate."
    %    "A node must have a (possibly empty) label text."
    %    "Giving up on this path. Did you forget a semicolon?"
    % drawaline{0}     {ABOVE1-1ABOVE1-2} {}
    % drawaline{1.3cm} {ABOVE2-1} {BELOW2-1}
    % drawaline{1cm}   {} {BELOW3-1BELOW3-2}

    % Works!
    drawalineone{0}
    drawalinetwo{1.3cm}
    drawalinethree{1cm}
end{tikzpicture}
end{document}

The general idea is simple: drawaline draws a line and accepts three arguments. If the second argument is nonempty, a label appears above the line. If the third argument is nonempty, a label appears below the line.

The vertical spacing of the lines is such that a space defined by the first argument appears between the line currently being rendered and the lowest point (including label, if present) of the previously-rendered line. This isn’t crucial for the MWE, but I’ve included it since it’s how the code is used in the original context, and it might conceivably affect which fixes are possible.

The drawalineone, drawalinetwo, and drawalinethree macros are hard-coded versions of drawaline. They function as expected. The actual drawaline macro does not. Note that neither of the approaches used in drawaline works when unexpanded{{#2}} (and likewise for #3) are replaced by simply {#2}, or by begingroup #2endgroup. In short, I don’t know how to get TikZ to recognize the content following draw as a parseable TikZ path spec.

Finally, please note that the drawaline macro must accept multi-line labels.

Any help would be appreciated.

2 Answers

I am not sure to understand your objective --- but if I understood correctly your description, I tried to simplify it.

documentclass[border=10pt]{standalone}
usepackage{tikz}
usepackage{ifthen}
newcommanddrawline[3]{
    % the position of the line is #1 below the previous line
    % it is not accounting for the (not typeset yet) above box
    path (lastline) ++(0,{-(#1)}) coordinate(thisline);
    % draw the line and mark midway
    draw (thisline) -- ++(5,0) coordinate[pos=0.5](midline);
    % if we have the box above, draw it
    ifthenelse{equal{#2}{}}{}{node[above, align=center] at (midline) {#2};}
    % if we have the box below, type it. Either case, re-set
    % the (lastline) position accordingly
    ifthenelse{equal{#3}{}}
        {coordinate(lastline) at (thisline);}
        {node[below, align=center](tmp) at (midline) {#3};
        coordinate(lastline) at (thisline|-tmp.south);}
}

begin{document}
begin{tikzpicture}[]
    coordinate (lastline) at (0,0);
    drawline{0}{Only  above}{}
    drawline{2}{Either  above}{Or  below}
    drawline{1}{}{Only  below}
end{tikzpicture}
end{document}

enter image description here

Taking into account the size of the text block above, in order to specify the distance between the texts instead of the lines, will be a bit more complex, but not impossible...

Correct answer by Rmano on July 22, 2021

Maybe not the complete solution, but perhaps a direction to go. I tried to use one of your code examples and enhanced it a bit:

    newcommand {drawalinetwo} [3] {
    coordinate (LFPS) at ($(LFP) - (0,{#1})$);
    edeftdsdlfpnode{LFPNarabic{lfpnode}}
    deftdsdnewLFP{0,0 |- tdsdlfpnode.south}

        draw [blue] (0,0 |- LFPS) -- node[above] {#2} node[below]
            (tdsdlfpnode) {#3} (5,0 |- LFPS);

    coordinate (LFP) at (tdsdnewLFP);
    stepcounter{lfpnode}
}

With the commands

drawalinetwo{1cm}{}{BELOW2-1}
drawalinetwo{1cm}{ABOVE2-1}{}
drawalinetwo{1cm}{ABOVE2-1}{BELOW2-1}

I get this:

enter image description here

Answered by Harald Lichtenstein on July 22, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP