2

In How to set vertical alignment for NiceMatrix block?, a user asked as to whether it is possible to redefine \Block in such a way it aligns text vertically to the top

The solution suggested by F. Pantigny (the author of the awesome package nicematrix) is to redefine a custom commands called \HighBlock and \LowBlock

My notes on this solution

  • \HighBlock does not align with the contents of the row it appears in
  • \LowBlock and \Block seem to be unaligned with the baseline. In fact, it seems that NiceTabular environment does not align contents of first row with the baseline of the text, but this is solved with the option [baseline=1] (only when \Block is not used)

I think it is good thing to provide new options which explicitly allow for vertical alignment of block contents in such a way baselines are exactly the same

\documentclass{article}

\usepackage{calc} \newlength{\widthWidest}

\usepackage{nicematrix}

\NiceMatrixOptions{rules/color=[gray]{0.75}, hvlines}

\begin{document}

\ExplSyntaxOn
\makeatletter

\NewDocumentCommand { \HighBlock } { m m }
{
    \tl_gput_right:Nx \g_nicematrix_code_after_tl 
    {
        \__Alan_high_block:nnnn
        { \int_use:c { c@iRow } }
        { \int_use:c { c@jCol } }
        { #1 }
        { \exp_not:n { #2 } }
    }
}

\cs_new_protected:Nn \__Alan_high_block:nnnn
{
    \__Alan_analyze:w #3 \q_stop 
    \pgfpicture
    \pgfrememberpicturepositiononpagetrue
    \pgf@relevantforpicturesizefalse
    \__nicematrix_qpoint:n { row - #1 } 
    \dim_set_eq:NN \l_tmpa_dim \pgf@y
    \__nicematrix_qpoint:n { col - #2 } 
    \dim_set_eq:NN \l_tmpb_dim \pgf@x
    \__nicematrix_qpoint:n { col - \int_eval:n { #2 + \l_tmpb_int } } 
    \pgftransformshift { \pgfpoint { \dim_eval:n { (\l_tmpb_dim + \pgf@x) / 2 } } { \l_tmpa_dim } }
    \pgfnode
    { rectangle }
    { north }
    { #4 }
    { }
    { }
    \endpgfpicture
}

\NewDocumentCommand { \LowBlock } { m m }
{
    \tl_gput_right:Nx \g_nicematrix_code_after_tl 
    {
        \__Alan_low_block:nnnn
        { \int_use:c { c@iRow } }
        { \int_use:c { c@jCol } }
        { #1 }
        { \exp_not:n { #2 } }
    }
}

\cs_new_protected:Nn \__Alan_low_block:nnnn
{
    \__Alan_analyze:w #3 \q_stop 
    \pgfpicture
    \pgfrememberpicturepositiononpagetrue
    \pgf@relevantforpicturesizefalse
    \__nicematrix_qpoint:n { row - \int_eval:n { #1 + \l_tmpa_int } } 
    \dim_set_eq:NN \l_tmpa_dim \pgf@y
    \__nicematrix_qpoint:n { col - #2 } 
    \dim_set_eq:NN \l_tmpb_dim \pgf@x
    \__nicematrix_qpoint:n { col - \int_eval:n { #2 + \l_tmpb_int } } 
    \pgftransformshift { \pgfpoint { \dim_eval:n { (\l_tmpb_dim + \pgf@x) / 2 } } { \l_tmpa_dim } }
    \pgfnode
    { rectangle }
    { south }
    { #4 }
    { }
    { }
    \endpgfpicture
}

\cs_new_protected:Npn \__Alan_analyze:w #1 - #2 \q_stop
{
    \int_set:Nn \l_tmpa_int { #1 }
    \int_set:Nn \l_tmpb_int { #2 }
}

\makeatother
\ExplSyntaxOff

\setlength{\widthWidest}{\widthof{Test}}
\setlength{\tabcolsep}{0pt}


\begin{NiceTabular}{p{\widthWidest} p{\widthWidest} p{\widthWidest}}
    \HighBlock{3-2}{\smash{\rlap{\rule{4cm}{0.1pt}}}Test} & & Test
    \\
    & & 0
    \\
    0 & 0 & 0
\end{NiceTabular}

\medskip

\begin{NiceTabular}{p{\widthWidest} p{\widthWidest} p{\widthWidest}}
    \LowBlock{3-2}{\smash{\rlap{\rule{4cm}{0.1pt}}}Test} & & 0
    \\
    & & 0
    \\
    &  & Test
    \\
\end{NiceTabular}

\medskip

\begin{NiceTabular}{p{\widthWidest} p{\widthWidest} p{\widthWidest}}
    \Block{3-1}{\smash{\rlap{\rule{4cm}{0.1pt}}}Test} & & 0
    \\
    & & Test
    \\
    0 & 0 & 0
\end{NiceTabular}

\smash{\rlap{\rule{4cm}{0.1pt}}Test}%
\begin{NiceTabular}[baseline=1]{p{\widthWidest}}
\Block{1-1}{Test}
\end{NiceTabular}

\end{document}

1 Answers1

1

You are right: that environment {HighBlock} does not align the baseline of the block with the baseline of the first row involved in the top. But it's by design. With that environment, the top border of the label of the block is put on the top line of the rectangle of the cells involved in that block. There is only a margin equal to the PGF/Tikz parameter inner sep.

Here is an example:

\documentclass{article}
\usepackage{nicematrix}

\NiceMatrixOptions{rules/color=[gray]{0.75}, hvlines}

\begin{document}

\ExplSyntaxOn \makeatletter

\NewDocumentCommand { \HighBlock } { m m } { \tl_gput_right:Nx \g_nicematrix_code_after_tl { __Alan_high_block:nnnn { \int_use:c { c@iRow } } { \int_use:c { c@jCol } } { #1 } { \exp_not:n { #2 } } } }

\cs_new_protected:Nn __Alan_high_block:nnnn { __Alan_analyze:w #3 \q_stop \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse __nicematrix_qpoint:n { row - #1 } \dim_set_eq:NN \l_tmpa_dim \pgf@y __nicematrix_qpoint:n { col - #2 } \dim_set_eq:NN \l_tmpb_dim \pgf@x __nicematrix_qpoint:n { col - \int_eval:n { #2 + \l_tmpb_int } } \pgftransformshift { \pgfpoint { \dim_eval:n { (\l_tmpb_dim + \pgf@x) / 2 } } { \l_tmpa_dim } } \pgfnode { rectangle } { north } { #4 } { } { } \endpgfpicture }

\cs_new_protected:Npn __Alan_analyze:w #1 - #2 \q_stop { \int_set:Nn \l_tmpa_int { #1 } \int_set:Nn \l_tmpb_int { #2 } }

\makeatother \ExplSyntaxOff

\begin{NiceTabular}{ccc}[hvlines] \HighBlock{4-2}{\Huge x} \Block[fill=red!10]{4-2}{} & & first row \ & & second row \ & & third row \ & & fourth row \ text & text \ \end{NiceTabular}

\end{document}

Output of the above code

I have highlighted the block with \Block[fill=red!10]{4-2}{}.


The latest version of nicematrix (v. 6.14 of 2023/02/18) provides keys t, T, b, B and v-center of the command \Block for the vertical alignment of the content of the block.

Here is an example of use of the keys t and b which correspond to the behaviour expected by the OP.

\documentclass{article}
\usepackage{calc}
\newlength{\widthWidest}
\usepackage{nicematrix}

\NiceMatrixOptions{rules/color=[gray]{0.75}, hvlines}

\begin{document}

\setlength{\widthWidest}{\widthof{Test}} \setlength{\tabcolsep}{0pt}

With the key \verb|t|:

\begin{NiceTabular}{p{\widthWidest} p{\widthWidest} p{\widthWidest}} \Block[t]{3-2}{\smash{\rlap{\rule{4cm}{0.1pt}}}Test} & & Test \ & & 0 \ 0 & 0 & 0 \end{NiceTabular}

\vspace{1cm}

With the key \verb|b|:

\begin{NiceTabular}{p{\widthWidest} p{\widthWidest} p{\widthWidest}} \Block[b]{3-2}{\smash{\rlap{\rule{4cm}{0.1pt}}}Test} & & 0 \ & & 0 \ & & Test \ \end{NiceTabular}

\end{document}

Output of the above code

F. Pantigny
  • 40,250
  • Thanks for the response. With the new options, it is possible to align contents easily. It is still not as price as \smash{\rlap{\rule{4cm}{0.1pt}}Test}\begin{NiceTabular}[baseline=1]{p{\widthWidest}}Test\end{NiceTabular} – Al-Motasem Aldaoudeyeh Feb 21 '23 at 11:24
  • You probably want to say "as precise". You are right. I will try to modify to have exactly the expected output. – F. Pantigny Feb 21 '23 at 12:26
  • The behaviour of the keys t and b has been modified in the latest version of nicematrix (v. 6.15 2023-02-25). I think that now, t and b are as precise as baseline=1. – F. Pantigny Feb 27 '23 at 09:50