# xparse optional arguments lead to error in tikz

I am trying to create a few simple macros for B-Trees and one of these macros is supposed to create a multipart node tikz based on the number of arguments it gets. Therefore I used the g argument specifier from xparse though tikz always shows the following error:

Package tikz Error: Giving up on this path. Did you forget a semicolon?. ;
Package tikz Error: Giving up on this path. Did you forget a semicolon?. ;
Undefined control sequence. ;


The macro works flawlessly when replacing the gs with ms though then it becomes impossible to differentiate between a multipart node with e.g. 4 segments two of which are empty and an 2 segment node which are all filled.

A kinda minimal working example:

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\usetikzlibrary{trees,shapes.multipart}

\NewDocumentCommand\test{m g}{
{#1 \IfValueT{#2}{B}}
}
\NewDocumentCommand\leaf{m m}{
node[leaf]{#1 \nodepart{two} #2}
}
\NewDocumentCommand\leafOptional{m g}{
node[leaf]{#1 \IfValueT{#2}{\nodepart{two} #2}}
}

\tikzset{
btree/.style={
nodes={rectangle split,rectangle split horizontal=true,draw},
leaf/.style={
rectangle split allocate boxes=2,
rectangle split parts=2,
rectangle split part fill=white}
},
}

\begin{document}
\test{a}\\ % this works
\test{a}{something}\\ % as does this
\begin{tikzpicture}[btree]
\node (root) {test}
child {\leaf{5}{}}
child {\leafOptional{5}} % however this fails
child {\leafOptional{5}{}} % and so does this
child {node[leaf]{1}}
;
\end{tikzpicture}
\end{document}


I already found this question TikZ path doesn't work with xparse generated macro which seems to be a similar problem though I am unable to use \DeclareDocumentCommand as it does not allow one to use the g/G argument specifier

Following @PhelypeOleinik's comment I changed the code to use \NewExpandableDocumentCommand and the argument specifier o o o m however when passing more than one optional argument this leads to tikz not determining the correct node bounding box and tikz draws the edge into the actual node shape.

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\usetikzlibrary{trees,shapes.multipart}

\NewExpandableDocumentCommand\leaf{o o o m}{
node[leaf]{
6\nodepart{two}8\nodepart{three}2\nodepart{four}#4
}
}

\tikzset{
btree/.style={
nodes={rectangle split,rectangle split horizontal=true,draw},
level 1/.style={sibling distance=\textwidth/4},
leaf/.style={rectangle split allocate boxes=4}
},
}

\begin{document}
\begin{tikzpicture}[btree]
\node (root) {test}
child {\leaf{5}}
child {\leaf[a]{5}}
child {\leaf[a][b]{5}}
child {\leaf[a][b][c]{5}}
;
\end{tikzpicture}
\end{document}


Adding leaf/.style={..., rectangle split part fill=white} seems to fix the symptoms though not the root cause - any possibile solution to use this with transparent nodes?

• really best to avoid g – David Carlisle Jun 5 at 16:58
• Don't use g: it's deprecated and it's bad practice. Apparently commands there need to be expandable, so you can use \NewExpandableDocumentCommand\leafOptional{o m}{node[leaf]{#2 \IfValueT{#1}{\nodepart{two} #1}}} and then use \leafOptional{5} or \leafOptional[opt]{5} – Phelype Oleinik Jun 5 at 17:00
• @PhelypeOleinik okay it just seemed convenient to use only curly bracket. I tried using o m and it worked for one and two part nodes though o o m and more optional arguments seemed to lead to tikz not correctly recognizing the resulting box in drawing the edge into the center of the node overlaying it. – Septatrix Jun 6 at 7:11

I find using node[leaf] {\leaf ...} works:

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\usetikzlibrary{trees,shapes.multipart}

\NewExpandableDocumentCommand\leaf{o o o m}{
6\nodepart{two}8\nodepart{three}2\nodepart{four}#4
}

\tikzset{
btree/.style={
nodes={rectangle split,rectangle split horizontal=true,draw},
level 1/.style={sibling distance=\textwidth/4},
leaf/.style={rectangle split allocate boxes=4}
}
}

\begin{document}
\begin{tikzpicture}[btree]
\node (root) {test}
child { node[leaf]{\leaf{5}} }
child { node[leaf]{\leaf[a]{5}} }
child { node[leaf]{\leaf[a][b]{5}} }
child { node[leaf]{\leaf[a][b][c]{5}} }
;
\end{tikzpicture}

\end{document}


• Yes that is also what my second code snippet does though I want to avoid filling the leafs as my plan is to superimpose this over another graphic/background – Septatrix Jun 17 at 17:51
• @Septatrix I guess it is the not-fully-expandable command \nodepart that causes the original problem. – muzimuzhi Z Jun 17 at 21:49
• It do not think so. All four rows calling my \leaf macro should expand to the same thing (a node with four parts) and the first two rows work as expected and only the later two do not. My guess it that it has to do with the additional optional arguments passed to the macro... – Septatrix Jun 18 at 8:13