2

I am using the solution form Obstacles to simulating an amsmath matrix by a TiKZ matrix of math nodes to create a tikz matrix in the style of a bmatrix. This works pretty well, with the default specification of

every delimiter/.style={yshift=-1pt}.

But, sometimes I want to manually tweak the top of the left/right delimiter separately form the bottom of the left/right delimiter so trying to find a tikz way of doing that. I could hack it by placing a phantom vertical rule, but would be much nicer to have a tikz style for that. Ideally, the solution would have style such as the following:

left delimiter top y shift=
left delimiter bottom y shift=
right delimiter top y shift=
right delimiter bottom y shift=

and similarly for the associated ones for the top and bottom delimiters (which are not used here)

top delimiter left x shift=
top delimiter right x shift=
bottom delimiter left x shift=
bottom delimiter right x shift=

Just to be clear, I am not expecting an automated solutions, but a manual tweaking of the delimiters as needed.

Below is a contrived example (and much to my surprise bmatrix produces the desired results by default, but don't understand how) where the first line of the matrix for both cases is

\smash{1} &  \smash{4} \\ 

enter image description here

Code:

\documentclass{article}
\usepackage{mathtools}% for amsmath {bmatrix}
\usepackage{tikz}
\usetikzlibrary{matrix}

%% https://tex.stackexchange.com/questions/26866/obstacles-to-simulating-an-amsmath-matrix-by-a-tikz-matrix-of-math-nodes \newlength\mtxrowsep \setlength\mtxrowsep{1.5ex} \newlength\mtxcolsep \setlength\mtxcolsep{2\arraycolsep}

\tikzset{ ams/.style={ baseline=-.7ex, every delimiter/.style={yshift=-1pt}, every left delimiter/.style={xshift=2pt}, every right delimiter/.style={xshift=-2pt}, every node/.style={inner sep=0pt}, }, ams matrix/.style={ inner sep=1pt, column sep=\mtxcolsep, row sep=\mtxrowsep, % Following is also commented at https://tex.stackexchange.com/questions/26866 %ampersand replacement=&, matrix of math nodes, }, bmatrix/.style={ ams, every matrix/.style={ ams matrix, left delimiter={[}, right delimiter={]}, } }, Bmatrix/.style={ ams, every matrix/.style={ ams matrix, left delimiter={\lbrace}, right delimiter={\rbrace}, } }, pmatrix/.style={ ams, every matrix/.style={ ams matrix, left delimiter={(}, right delimiter={)}, } }, vmatrix/.style={ ams, every matrix/.style={ ams matrix, left delimiter={|}, right delimiter={|}, } }, Vmatrix/.style={ ams, every matrix/.style={ ams matrix, left delimiter={|}, right delimiter={|}, } }, }

%% This does not seem to be necessary %\let\matamp=& % %\catcode`&=13 %\makeatletter %\def&{\iftikz@is@matrix % \pgfmatrixnextcell % \else % \matamp % \fi} %\makeatother

\begin{document} \hspace{0.2em} \begin{tikzpicture}[bmatrix] \matrix (m) { \smash{1} & \smash{4} \ 7 & 10 \ 13 & 16 \ }; \end{tikzpicture} %% ---------------- \hspace{0.3em} $\begin{bmatrix} \smash{1} & \smash{4} \ 7 & 10 \ 13 & 16 \ \end{bmatrix}$

tikz matrix \hspace*{0.6em} bmatrix

\end{document}

Peter Grill
  • 223,288
  • Doesn't nicematrix replace a lot of TikZ matrices? You're talking about top and bottom delimiters but don't use them. Do you mean the top and bottom end of the left and right delimiters? The \smash reduces the TikZ nodes and therefore the whole row to zero height while bmatrix probably still counts the row as a row. There might be a better way than \smash. Why do you need it? – Qrrbrbirlbel Dec 22 '23 at 14:47
  • The delimiters measure a node (doesn't need to be a matrix) and use its measurement for a \left[ <zero width box of measured height/depth> \right. that placed at one of the four sides of the node (And we could adopt this to measure anything and place that anyway.) How should the delimiter be drawn without any knowledge of some vertical dimension of the first row? At least a \(math)strut somewhere? If you use \smash{\dfrac{1}{2}} with the bmatrix it won't look good anymore as well. – Qrrbrbirlbel Dec 22 '23 at 14:57
  • @Qrrbrbirlbel: Thanks for point out the confusing wording. Have attempted to clarify that I want to manually tweak the top of the left delimiter and the bottom of the left delimeter (and similarly for the right delimeter). The default behavior is what is expected. The reason I need it is the yshift=-1pt seems to be fine in most cases, but not all cases. Thus, the desire to manually tweak the top and bottom separately. – Peter Grill Dec 22 '23 at 18:15

1 Answers1

4

I can only provide a re-implementation of the delimiters with two extra keys: delim' top and delim' bot.

Don't know if the asymmetrical approach (having different values for left and right as well as above and below) is a good idea or just overcomplicates it a bit …

Code

\documentclass{article}
\usepackage{mathtools}% for amsmath {bmatrix}
\usepackage{tikz}
\usetikzlibrary{matrix}
\tikzset{% similar to axis_height of TikZ-CD
  vcenter/.code=\begingroup$\relax$\pgfmathreturn
                  \the\fontdimen22\textfont2\endgroup
                \pgfsetbaseline{-\pgfmathresult pt}}
\tikzset{
  delimiter' top/.code=\pgfmathparse{#1}% self-evaluating
    \pgfkeyssetevalue{/tikz/delimiter' top}{\pgfmathresult pt},
  delimiter' bot/.code=\pgfmathparse{#1}% self-evaluating
    \pgfkeyssetevalue{/tikz/delimiter' bot}{\pgfmathresult pt},
  delimiter' top=0pt, delimiter' bot=0pt}
\makeatletter
\tikzset{
  left delimiter'/.style={delimiter'={south east}{south west}
    {every delimiter,every left delimiter,every left delimiter'}
    {south}{north}{#1}{.}{\pgf@y}},
  right delimiter'/.style={delimiter'={south west}{south east}
    {every delimiter,every right delimiter,every right delimiter'}
    {south}{north}{.}{#1}{\pgf@y}},
  above delimiter'/.style={delimiter'={south east}{north west}
    {every delimiter,every above delimiter,every above delimiter',rotate=-90}
    {west}{east}{#1}{.}{\pgf@x}},
  below delimiter'/.style={delimiter'={south west}{south west}
    {every delimiter,every below delimiter,every below delimiter',rotate=-90}
    {west}{east}{.}{#1}{\pgf@x}},
  every delimiter'/.style={outer sep=+0pt,inner sep=+0pt,path only},
  delimiter'/.style n args={8}{append after command={
    \bgroup% similar to original delims
      \pgfextra{\let\tikz@save@last@fig@name\tikz@last@fig@name
                \tikz@node@is@a@labelfalse}
      node[every delimiter',anchor=#1,at=(\tikz@last@fig@name.#2),#3,%
        yshift=-\pgfkeysvalueof{/tikz/delimiter' bot}]{%
        {\nullfont\pgf@process{%
          \pgfpointdiff{\pgfpointanchor{\tikz@last@fig@name}{#4}}
                       {\pgfpointanchor{\tikz@last@fig@name}{#5}}}}%
        $\left#6\vcenter{%
          \hrule height\dimexpr.5#8+\pgfkeysvalueof{/tikz/delimiter' top}\relax
                  depth\dimexpr.5#8+\pgfkeysvalueof{/tikz/delimiter' bot}\relax
                  width0pt}\right#7$}
      \pgfextra{\global\let\tikz@last@fig@name\tikz@save@last@fig@name}
    \egroup}}}
\makeatother
\tikzset{
  every left delimiter'/.style={
    delimiter' top=  \pgfkeysvalueof{/tikz/left  delimiter top    yshift},
    delimiter' bot=-(\pgfkeysvalueof{/tikz/left  delimiter bottom yshift})},
  every right delimiter'/.style={
    delimiter' top=  \pgfkeysvalueof{/tikz/right delimiter top    yshift},
    delimiter' bot=-(\pgfkeysvalueof{/tikz/right delimiter bottom yshift})},
  every above delimiter'/.style={
    delimiter' top=  \pgfkeysvalueof{/tikz/above delimiter right  xshift},
    delimiter' bot=-(\pgfkeysvalueof{/tikz/above delimiter left   xshift})},
  every below delimiter'/.style={
    delimiter' top=  \pgfkeysvalueof{/tikz/below delimiter right  xshift},
    delimiter' bot=-(\pgfkeysvalueof{/tikz/below delimiter left   xshift})},
  left  delimiter top    yshift/.initial=0pt,
  left  delimiter bottom yshift/.initial=0pt,
  right delimiter top    yshift/.initial=0pt,
  right delimiter bottom yshift/.initial=0pt,
  above delimiter left   xshift/.initial=0pt,
  above delimiter right  xshift/.initial=0pt,
  below delimiter left   xshift/.initial=0pt,
  below delimiter right  xshift/.initial=0pt}

\tikzset{ ams/.style={ vcenter, inner sep=+0pt, every delimiter/.style={yshift=+-1pt}, every left delimiter/.style={xshift=+ 2pt}, every right delimiter/.style={xshift=+-2pt}}, ams matrix/.style={ every outer matrix/.append style={inner sep=+1pt}, matrix anchor=center, matrix of math nodes, row sep=1.5ex, column sep=2\arraycolsep}, create ams matrix/.style n args={3}{#1matrix/.style={ ams, every matrix/.style={ ams matrix, left delimiter'={#2}, right delimiter'={#3}}}}, create ams matrix/.list={b[], B\lbrace\rbrace, p(), v||, V||}, ams delim' top/.style={ left delimiter top yshift={#1}, right delimiter top yshift={#1}}, ams delim' bot/.style={ left delimiter bottom yshift={#1}, right delimiter bottom yshift={#1}}} \begin{document} \hspace{0.2em} \tikz[bmatrix, ams delim' top=2ex] \matrix { \smash{1} & \smash{4} \ 7 & 10 \ 13 & 16 \ }; %% ---------------- \hspace{0.3em} $\begin{bmatrix} \smash{1} & \smash{4} \ 7 & 10 \ 13 & 16 \end{bmatrix}$

tikz matrix \hspace*{0.6em} bmatrix \bigskip

\noindent \foreach \top in {-3, -2.5, ..., 3}{ \tikz[bmatrix, ams delim' top=\top ex, ampersand replacement=&amp;] \matrix[label=below:\tiny\color{gray}$\top$ex]{ \smash{1} &amp; \smash{4} \ 7 &amp; 10 \ 13 &amp; 16 \};} % \tikz[ vcenter, every below delimiter/.style={yshift=1.5ex}, below delimiter left xshift= 1ex, below delimiter right xshift=-1ex, above delimiter left xshift= 1ex, above delimiter right xshift=-1ex, ]\matrix[ matrix of math nodes, above delimiter'=[, below delimiter'={]}, ]{\smash{1} & \smash{4} \ 7 & 10 \ 13 & 16 \}; \end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821