8

I have a node style I would like to apply to many (but not all) the cells/columns/rows of a matrix of nodes. Currently, for every column or cell that I want the style to apply to, I declare the style as:

column 2/.style={column sep=-0.4pt},
column 3/.style={column sep=-0.4pt},
column 4/.style={column sep=-0.4pt},
column 5/.style={column sep=-0.4pt},
row 3 column 2/.style={my node style},
row 3 column 3/.style={my node style},
row 3 column 4/.style={my node style},
row 3 column 5/.style={my node style},
row 3 column 6/.style={my node style},

It would be more convenient if I could write something like

column 2 to 5/.style={column sep=-0.4pt},
row 3 column 2 to 5/.style={my node style},
row 4 column 2 to 5/.style={my node style},

or even better (for the last two)

cell 3 2 to cell 4 5/.style={my node style},

Here's a MWE where such keys would improve readability of the code

\documentclass[border=6pt]{standalone}

\usepackage{amsmath}
\newcommand\abs[1]{\lvert#1\rvert}

\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{matrix}
\usetikzlibrary{arrows.meta}

\tikzset{%%
  >=Stealth,
  my node style/.style={%%
    minimum width=\dimexpr0.60in+12pt\relax,
    minimum height=\dimexpr0.30cm+12pt\relax,
    outer sep=0pt,
    draw},
  }

\begin{document}

\begin{tikzpicture}

  \matrix (TBL) [%%
                 matrix of nodes,
                 nodes={%%
                   align=center,
                   inner sep=0pt,
                   anchor=center},
                 column 2/.style={column sep=-0.4pt},
                 column 3/.style={column sep=-0.4pt},
                 column 4/.style={column sep=-0.4pt},
                 column 5/.style={column sep=-0.4pt},
                 row 3 column 2/.style={my node style},
                 row 3 column 3/.style={my node style},
                 row 3 column 4/.style={my node style},
                 row 3 column 5/.style={my node style},
                 row 3 column 6/.style={my node style},
                ]
  {
                        & {$(-\infty,-2)$}               & {$(-2,-1)$}                     & {$(-1,1)$}                    & {$(1,2)$}                       & {$(2,\infty)$}                 \\[2pt]
   {$\abs{x^{2}-1}=\,$} & |[my node style]| {$x^{2}-1 $} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$1-x^{2}$} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$x^{2}-1$}  \\[-0.4pt]
   {$\abs{x^{2}-4}=\,$} &                   {$x^{2}-4 $} &                   {$4-x^{2}$}   &                   {$4-x^{2}$} &                   {$4-x^{2}$}   &                   {$x^{2}-4$}  \\[2pt]
   {$g(x) =$}           & |[my node style]| {$ 3 $ }     & |[my node style]| {$ 2x^{2}-5$} & |[my node style]| {$ -3 $}    & |[my node style]| { $2x^{2}-5$} & |[my node style]| {$ 3 $}      \\
  };

\end{tikzpicture}

\end{document}

enter image description here

Note: I'm also trying to avoid having to declare the style explicitly in each cell where I want it to apply as in rows 2 and 4 of the above example.

UPDATE

I've tried adding the following to my preamble

\tikzset{%%
    column \the\pgfmatrixcurrentcolumn\space to \the\pgfmatrixcurrentcolumn/.try,
  }

but when I try to call it as in:

\begin{tikzpicture}

  \matrix (TBL) [%%
                 matrix of nodes,
                 nodes={%%
                   align=center,
                   inner sep=0pt,
                   anchor=center},
                 column 2/.style={column sep=-0.4pt},
                 column 3/.style={column sep=-0.4pt},
                 column 4/.style={column sep=-0.4pt},
                 column 5/.style={column sep=-0.4pt},
                 row 3 column 2/.style={my node style},
                 row 3 column 3/.style={my node style},
                 row 3 column 4/.style={my node style},
                 row 3 column 5/.style={my node style},
                 row 3 column 6/.style={my node style},
                 column 2 to 5/.style={red},
                ]
  {
                        & {$(-\infty,-2)$}               & {$(-2,-1)$}                     & {$(-1,1)$}                    & {$(1,2)$}                       & {$(2,\infty)$}                 \\[2pt]
   {$\abs{x^{2}-1}=\,$} & |[my node style]| {$x^{2}-1 $} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$1-x^{2}$} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$x^{2}-1$}  \\[-0.4pt]
   {$\abs{x^{2}-4}=\,$} &                   {$x^{2}-4 $} &                   {$4-x^{2}$}   &                   {$4-x^{2}$} &                   {$4-x^{2}$}   &                   {$x^{2}-4$}  \\[2pt]
   {$g(x) =$}           & |[my node style]| {$ 3 $ }     & |[my node style]| {$ 2x^{2}-5$} & |[my node style]| {$ -3 $}    & |[my node style]| { $2x^{2}-5$} & |[my node style]| {$ 3 $}      \\
  };

\end{tikzpicture}

There is no apparent effect.

4 Answers 4

8

You can use the /.list handler for repeated settings. Also you can wrap them around for more complicated cases but here are two actions for simple use. enter image description here

\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{calc,matrix,arrows.meta}

\def\abs#1{|#1|}
\tikzset{
  foo1/.style={column #1/.style={column sep=-0.4pt}},
  foo2/.style={row 3 column #1/.style={nodes=my node style}},
  >=Stealth,
  my node style/.style={%%
    minimum width=0.60in+12pt,
    minimum height=0.30cm+12pt,
    outer sep=0pt,
    draw},
  }


\begin{document}
\begin{tikzpicture}

  \matrix (TBL) [%%
                 matrix of nodes,
                 nodes={%%
                   align=center,
                   inner sep=0pt,
                   anchor=center},
  foo1/.list={2,...,5},
  foo2/.list={3,...,5}
                ]
  {
                        & {$(-\infty,-2)$}               & {$(-2,-1)$}                     & {$(-1,1)$}                    & {$(1,2)$}                       & {$(2,\infty)$}                 \\[2pt]
   {$\abs{x^{2}-1}=\,$} & |[my node style]| {$x^{2}-1 $} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$1-x^{2}$} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$x^{2}-1$}  \\[-0.4pt]
   {$\abs{x^{2}-4}=\,$} &                   {$x^{2}-4 $} &                   {$4-x^{2}$}   &                   {$4-x^{2}$} &                   {$4-x^{2}$}   &                   {$x^{2}-4$}  \\[2pt]
   {$g(x) =$}           & {$ 3 $ }                       & {$ 2x^{2}-5$}                   & {$ -3 $}                      & { $2x^{2}-5$}                   & {$ 3 $}      \\
  };
\end{tikzpicture}
\end{document}
5
  • What if I wanted to apply to multiple row? Can list be nested?
    – A.Ellett
    Commented Jun 1, 2014 at 19:02
  • @A.Ellett Yes put another style that sets the list with two arguments; one argument for the outer list one for the inner
    – percusse
    Commented Jun 1, 2014 at 19:03
  • Could you illustrate the nested lists?
    – A.Ellett
    Commented Jun 1, 2014 at 19:06
  • Also, according to the documentation, /.list is processed within a foreach loop. But when I tried using \foreach to set \tikzset{...}, nothing seemed to take effect. I assumed that it was a scoping issue. Do you know what foreach doesn't seem to be localizing things under ./list?
    – A.Ellett
    Commented Jun 1, 2014 at 19:09
  • @A.Ellett I need to delay you a little. (unless someone else picks it up) but shortly, it's the other way around; it is not run under a foreach scope but it uses foreach to generate the keys. Otherwise as you point out the key setting will be local to the foreach spin.
    – percusse
    Commented Jun 1, 2014 at 19:16
1

This isn't quite the solution that I want, but it does kind of achieve the effect I want.

Using the etoolbox package, I define two macros: \foreachcell and \foreachcolumn

\usepackage{etoolbox}
\makeatletter
\newcommand\foreachcell{\ae@foreach@cell}
\def\ae@foreach@cell from (#1,#2) to (#3,#4) do #5{%%
  \def\aecol{#2}%%
  \def\aerow{#1}%%
  \whileboolexpr{ not ( test { \ifnumcomp{\aecol}{=}{#4}} and test{\ifnumcomp{\aerow}{=}{#3}} ) }
  {
    #5
    \edef\aecol{\number\numexpr\aecol+1\relax}
    \ifnum\aecol>#4\relax
      \edef\aerow{\number\numexpr\aerow+1\relax}
      \edef\aecol{#2}
    \fi
  }
}
\newcommand\foreachcolumn{\ae@foreach@col}
\def\ae@foreach@col from #1 to #2 do #3{%%
  \def\aecol{#1}%%
  \whileboolexpr{ test {\ifnumcomp{\aecol}{<}{#2}} or test{\ifnumcomp{\aecol}{=}{#2}} }
  { #3
    \edef\aecol{\number\numexpr\aecol+1\relax}
  }}
\makeatother

Then in a MWE:

\documentclass[border=6pt]{standalone}

\usepackage{amsmath}
\newcommand\abs[1]{\lvert#1\rvert}

\usepackage{etoolbox}

\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{matrix}
\usetikzlibrary{arrows.meta}

\makeatletter
\newcommand\foreachcell{\ae@foreach@cell}
\def\ae@foreach@cell from (#1,#2) to (#3,#4) do #5{%%
  \def\aecol{#2}%%
  \def\aerow{#1}%%
  \whileboolexpr{ not ( test { \ifnumcomp{\aecol}{=}{#4}} and test{\ifnumcomp{\aerow}{=}{#3}} ) }
  {
    #5
    \edef\aecol{\number\numexpr\aecol+1\relax}
    \ifnum\aecol>#4\relax
      \edef\aerow{\number\numexpr\aerow+1\relax}
      \edef\aecol{#2}
    \fi
  }
}
\newcommand\foreachcolumn{\ae@foreach@col}
\def\ae@foreach@col from #1 to #2 do #3{%%
  \def\aecol{#1}%%
  \whileboolexpr{ test {\ifnumcomp{\aecol}{<}{#2}} or test{\ifnumcomp{\aecol}{=}{#2}} }
  { #3
    \edef\aecol{\number\numexpr\aecol+1\relax}
  }}
\makeatother

\foreachcell from (2,2) to (4,6) do
{\tikzset{row \aerow\space column \aecol/.style={my node style}}}

\foreachcolumn from 2 to 5 do 
{\tikzset{column \aecol/.style={column sep=4pt}}}

\tikzset{%%
  >=Stealth,
  my node style/.style={%%
    minimum width=\dimexpr0.60in+12pt\relax,
    minimum height=\dimexpr0.30cm+12pt\relax,
    outer sep=0pt,
    draw},
  }

\begin{document}

\begin{tikzpicture}

  \matrix (TBL) [%%
                 matrix of nodes,
                 nodes={%%
                   align=center,
                   inner sep=0pt,
                   anchor=center},
                ]
  {
                        & {$(-\infty,-2)$}               & {$(-2,-1)$}                     & {$(-1,1)$}                    & {$(1,2)$}                       & {$(2,\infty)$}                 \\[2pt]
   {$\abs{x^{2}-1}=\,$} & |[my node style]| {$x^{2}-1 $} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$1-x^{2}$} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$x^{2}-1$}  \\[-0.4pt]
   {$\abs{x^{2}-4}=\,$} &                   {$x^{2}-4 $} &                   {$4-x^{2}$}   &                   {$4-x^{2}$} &                   {$4-x^{2}$}   &                   {$x^{2}-4$}  \\[2pt]
   {$g(x) =$}           & |[my node style]| {$ 3 $ }     & |[my node style]| {$ 2x^{2}-5$} & |[my node style]| {$ -3 $}    & |[my node style]| { $2x^{2}-5$} & |[my node style]| {$ 3 $}      \\
  };

\end{tikzpicture}

\end{document}

I get the desired output (except that draw does not take effect as I would like).

It would be nice to do this as keys. So, I'll not accept my own solution until someone shows how to effectively create the desired keys.

The problem with defining keys (as I attempted to do in the update to my question) is that this needs to be initialized (or so it seems to me) within \def\tikz@common@matrix@code in \tikz@do@matrix. I don't want to rewrite all of that. And I'm not savvy enough with patching to understand how to patch this to embed my desired keys in there.

1

Here's a solution that works basically the way you suggest. In order to avoid having to hack the definition of the tikz matrix code to make it respond to extra styles, I define a custom handler, called .matrix style used like: row 2 to 3 column 2 to 4/.matrix style={blue}. The row and column can come in either order, either can be omitted and it's possible to have just one number rather than a range. For instance the following are all valid:

row 2 to 3 column 2 to 4/.matrix style={...}
row 2 to 3 column 2/.matrix style={...}
column 2 to 3 row 3/.matrix style={...}
row 2 to 3/.matrix style={...}
column 4 row 2/.matrix style={...}

Because I apparently have too much time on my hands, I wrote both a plain tex version and an expl3 version.

First the plain tex version:

\makeatletter
\def\matrixstyle@ifempty#1{\ifx$#1$\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}

\def\matrixstyle@expectword#1#2{\matrixstyle@expectword@#1\nill{#2}}
\def\matrixstyle@expectword@#1#2\nill#3{%
    \@ifnextchar{#1}{%
        \matrixstyle@ifempty{#2}{%
            \def\next{#3}%
        }{%
            \def\next{\matrixstyle@expectword@#2\nill{#3}}%
        }%
        \expandafter\next\@gobble
    }{%
        \matrixstyle@expectword@fail
    }%
}

\def\matrixstyle@expectword@fail#1.{\PackageError{matrix style}{Unexpected row/column specifier "\pgfkeyscurrentname"}{}}


\pgfkeys{/handlers/.matrix style/.code={\pgfkeys{\pgfkeyscurrentpath/.matrix code=\pgfkeysalso{#1}}}}

\pgfkeys{/handlers/.matrix code/.code={
        \edef\pgfkeyscurrentkey{\pgfkeyscurrentpath}%
        \pgfkeys@split@path
        \edef\matrixstyle@thepath{\pgfkeyscurrentpath}%
        \def\matrixstyle@thestyle{#1}%
        \edef\temp{\noexpand\matrixstyle@parse\pgfkeyscurrentname.}%
        \temp
    }
}

\def\matrixstyle@parse{%
    \let\matrixstyle@columnmin\empty%
    \let\matrixstyle@rowmin\empty%
    \matrixstyle@parse@
}

\def\matrixstyle@parse@{%
    \@ifnextchar.{%
        \expandafter\matrixstyle@finish@rows\@gobble
    }{%
        \@ifnextchar{c}{%
            \matrixstyle@expectword{column}{\def\type{column}\matrixstyle@parse@range@grab{\matrixstyle@parse@range@min}}%
        }{%
            \matrixstyle@expectword{row}{\def\type{row}\matrixstyle@parse@range@grab{\matrixstyle@parse@range@min}}%
        }%
    }
}

\newcount\tempcount
\newcount\tempcountb
\def\matrixstyle@parse@range@grab#1{\afterassignment#1\tempcount=\numexpr}
\def\matrixstyle@parse@range@min{%
    \expandafter\edef\csname matrixstyle@\type min\endcsname{\the\tempcount}%
    \expandafter\edef\csname matrixstyle@\type max\endcsname{\the\tempcount}%
    \@ifnextchar{t}{%
        \matrixstyle@expectword{to}{\matrixstyle@parse@range@grab{\matrixstyle@parse@range@max}}%
    }{%
        \matrixstyle@parse@
    }
}

\def\matrixstyle@parse@range@max{%
    \expandafter\edef\csname matrixstyle@\type max\endcsname{\the\tempcount}%
    \matrixstyle@parse@
}

\def\matrixstyle@finish@rows{%
    \let\matrixstyle@possiblespace\space
    \ifx\matrixstyle@rowmin\empty
        \let\matrixstyle@possiblespace\empty
        \let\matrixstyle@rowtext\empty
        \matrixstyle@finish@columns
    \else
        \tempcount=\matrixstyle@rowmin\relax
        \loop
            \edef\matrixstyle@rowtext{row \the\tempcount}%
            % Loops don't nest correctly because they both use the same \iterate command
            % either the inner loop needs to be in a scope, which won't work for us
            % or we need to save the value of \iterate
            \let\matrixstyle@saveiterate\iterate
            \matrixstyle@finish@columns
            \let\iterate\matrixstyle@saveiterate
            \advance\tempcount1\relax
        \unless\ifnum\tempcount>\matrixstyle@rowmax\repeat
    \fi
}

\def\matrixstyle@finish@columns{%
    \ifx\matrixstyle@columnmin\empty
        \let\matrixstyle@possiblespace\empty
        \let\matrixstyle@columntext\empty
        \matrixstyle@finish@key
    \else
        \tempcountb=\matrixstyle@columnmin\relax
        \loop
            \edef\matrixstyle@columntext{column \the\tempcountb}%
            \matrixstyle@finish@key
            \advance\tempcountb1\relax
        \unless\ifnum\tempcountb>\matrixstyle@columnmax\repeat
    \fi
}

\def\matrixstyle@finish@key{%
    \edef\temp{
        \matrixstyle@thepath/%
           \matrixstyle@rowtext \matrixstyle@possiblespace \matrixstyle@columntext
              /.code={\unexpanded\expandafter{\matrixstyle@thestyle}}%
    }%
    \expandafter\pgfkeys\expandafter{\temp}
}

Here's the expl3 version.

\usepackage{expl3}

\makeatletter
\pgfkeys{/handlers/.matrix style/.code={\pgfkeys{\pgfkeyscurrentpath/.matrix code=\pgfkeysalso{#1}}}}

\pgfkeys{/handlers/.matrix code/.code={
        \edef\pgfkeyscurrentkey{\pgfkeyscurrentpath}%
        \pgfkeys@split@path
        \matrixstyle@parse{#1}
    }
}
\makeatother

\ExplSyntaxOn
\makeatletter
\def \matrixstyle@parse { \matrixstyle_parse:n }
\makeatother

\tl_new:N \l_matrixstyle_path_tl
\tl_new:N \l_matrixstyle_style_tl
\tl_new:N \l_matrixstyle_type_tl
\tl_new:N \l_matrixstyle_possible_space_tl

\tl_new:N \l_matrixstyle_columntext_tl
\tl_new:N \l_matrixstyle_columnmin_tl
\tl_new:N \l_matrixstyle_columnmax_tl

\tl_new:N \l_matrixstyle_rowtext_tl
\tl_new:N \l_matrixstyle_rowmin_tl
\tl_new:N \l_matrixstyle_rowmax_tl

\cs_new:Nn \matrixstyle_expectword:nn {
    \matrixstyle_expectword_aux:wn #1 \q_stop { #2 }
}

\cs_gset:Npn \use_i_delimit_by_period:nw #1 #2 . { #1 } 

\cs_new:Npn \matrixstyle_expectword_aux:wn #1 #2 \q_stop #3 {
    \peek_meaning_remove_ignore_spaces:NTF { #1 } {
        \tl_if_empty:nTF { #2 } {
            #3
        }{
            \matrixstyle_expectword_aux:wn #2 \q_stop { #3 }
        }
    }{ % An error. Escape out and throw an error.
        \use_i_delimit_by_period:nw { \PackageError{matrix style}{Unexpected row/column specifier "\pgfkeyscurrentname"}{} }
    }
}


\cs_new:Nn \matrixstyle_parse:n {
    \tl_clear:N \l_matrixstyle_columnmin_tl
    \tl_clear:N \l_matrixstyle_rowmin_tl
    \tl_set:Nn \l_matrixstyle_style_tl { #1 }%
    \tl_set:Nx \l_matrixstyle_path_tl { \pgfkeyscurrentpath }%
    \use:x { \exp_not:N \matrixstyle_parse_aux: \pgfkeyscurrentname . }
}

\cs_new:Npn \matrixstyle_parse_aux: {
    \peek_meaning_remove_ignore_spaces:NTF . {
        \matrixstyle_finish_rows:
    }{
        \peek_meaning_ignore_spaces:NTF { c }{
            \matrixstyle_expectword:nn { column } {
                \tl_set:Nn \l_matrixstyle_type_tl {column}
                \matrixstyle_parse_rangegrab:nw { \matrixstyle_parse_rangemin: }
            }%
        }{%
            \matrixstyle_expectword:nn { row }{
                \tl_set:Nn \l_matrixstyle_type_tl {row}
                \matrixstyle_parse_rangegrab:nw { \matrixstyle_parse_rangemin: }
            }%
        }%
    }
}

\newcount\tempcount
\cs_new:Npn \matrixstyle_parse_rangegrab:nw #1 {
    \afterassignment #1
    \tempcount = \int_eval:w
}

\cs_new:Nn \matrixstyle_parse_rangemin: {
    \tl_set:co { l_matrixstyle_ \tl_use:N \l_matrixstyle_type_tl min_tl }{ \the\tempcount }%
    \tl_set:co { l_matrixstyle_ \tl_use:N \l_matrixstyle_type_tl max_tl }{ \the\tempcount }
    \peek_meaning_ignore_spaces:NTF { t }{
        \matrixstyle_expectword:nn { to }{
            \matrixstyle_parse_rangegrab:nw { \matrixstyle_parse_rangemax: }
        }%
    }{%
        \matrixstyle_parse_aux:
    }
}

\cs_new:Nn \matrixstyle_parse_rangemax: {
    \tl_set:co { l_matrixstyle_ \tl_use:N \l_matrixstyle_type_tl max_tl }{ \the\tempcount }
    \matrixstyle_parse_aux:
}

\cs_new:Nn \matrixstyle_finish_rows: {%
    \tl_set_eq:NN \l_matrixstyle_possible_space_tl \c_space_tl
    \tl_if_empty:NTF \l_matrixstyle_rowmin_tl {
        \tl_clear:N \l_matrixstyle_possible_space_tl
        \tl_clear:N \l_matrixstyle_rowtext_tl
        \matrixstyle_finish_columns:
    } {
        \int_step_inline:nnn
            { \tl_use:N \l_matrixstyle_rowmin_tl }
            { \tl_use:N \l_matrixstyle_rowmax_tl }
            {
                \tl_set:Nn \l_matrixstyle_rowtext_tl { row ~ ##1 }
                \matrixstyle_finish_columns:
            }
    }
}

\cs_new:Nn \matrixstyle_finish_columns: {%
    \tl_if_empty:NTF  \l_matrixstyle_columnmin_tl {
        \tl_clear:N \l_matrixstyle_possible_space_tl
        \tl_clear:N \l_matrixstyle_columntext_tl
        \matrixstyle_finish_key:
    } {
        \int_step_inline:nnn
            { \tl_use:N \l_matrixstyle_columnmin_tl }
            { \tl_use:N \l_matrixstyle_columnmax_tl }
            {
                \tl_set:Nn \l_matrixstyle_columntext_tl { column ~ ##1 }
                \matrixstyle_finish_key:
            }
    }
}

\makeatletter
\cs_new:Nn \matrixstyle_finish_key: {
    \exp_args:Nx \pgfkeys
        {   \tl_use:N \l_matrixstyle_path_tl /
            \tl_use:N \l_matrixstyle_rowtext_tl
            \tl_use:N \l_matrixstyle_possible_space_tl
            \tl_use:N \l_matrixstyle_columntext_tl
        /. code = { \exp_not:o { \l_matrixstyle_style_tl } } } 
}
\makeatother
\ExplSyntaxOff

The plain tex version in use:

\documentclass[border=6pt]{standalone}

\usepackage{amsmath}
\newcommand\abs[1]{\lvert#1\rvert}

\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{matrix}
\usetikzlibrary{arrows.meta}


\makeatletter
\def\matrixstyle@ifempty#1{\ifx$#1$\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}

\def\matrixstyle@expectword#1#2{\matrixstyle@expectword@#1\nill{#2}}
\def\matrixstyle@expectword@#1#2\nill#3{%
    \@ifnextchar{#1}{%
        \matrixstyle@ifempty{#2}{%
            \def\next{#3}%
        }{%
            \def\next{\matrixstyle@expectword@#2\nill{#3}}%
        }%
        \expandafter\next\@gobble
    }{%
        \matrixstyle@expectword@fail
    }%
}

\def\matrixstyle@expectword@fail#1.{\PackageError{matrix style}{Unexpected row/column specifier "\pgfkeyscurrentname"}{}}


\pgfkeys{/handlers/.matrix style/.code={\pgfkeys{\pgfkeyscurrentpath/.matrix code=\pgfkeysalso{#1}}}}

\pgfkeys{/handlers/.matrix code/.code={
        \edef\pgfkeyscurrentkey{\pgfkeyscurrentpath}%
        \pgfkeys@split@path
        \edef\matrixstyle@thepath{\pgfkeyscurrentpath}%
        \def\matrixstyle@thestyle{#1}%
        \edef\temp{\noexpand\matrixstyle@parse\pgfkeyscurrentname.}%
        \temp
    }
}

\def\matrixstyle@parse{%
    \let\matrixstyle@columnmin\empty%
    \let\matrixstyle@rowmin\empty%
    \matrixstyle@parse@
}

\def\matrixstyle@parse@{%
    \@ifnextchar.{%
        \expandafter\matrixstyle@finish@rows\@gobble
    }{%
        \@ifnextchar{c}{%
            \matrixstyle@expectword{column}{\def\type{column}\matrixstyle@parse@range@grab{\matrixstyle@parse@range@min}}%
        }{%
            \matrixstyle@expectword{row}{\def\type{row}\matrixstyle@parse@range@grab{\matrixstyle@parse@range@min}}%
        }%
    }
}

\newcount\tempcount
\newcount\tempcountb
\def\matrixstyle@parse@range@grab#1{\afterassignment#1\tempcount=\numexpr}
\def\matrixstyle@parse@range@min{%
    \expandafter\edef\csname matrixstyle@\type min\endcsname{\the\tempcount}%
    \expandafter\edef\csname matrixstyle@\type max\endcsname{\the\tempcount}%
    \@ifnextchar{t}{%
        \matrixstyle@expectword{to}{\matrixstyle@parse@range@grab{\matrixstyle@parse@range@max}}%
    }{%
        \matrixstyle@parse@
    }
}

\def\matrixstyle@parse@range@max{%
    \expandafter\edef\csname matrixstyle@\type max\endcsname{\the\tempcount}%
    \matrixstyle@parse@
}

\def\matrixstyle@finish@rows{%
    \let\matrixstyle@possiblespace\space
    \ifx\matrixstyle@rowmin\empty
        \let\matrixstyle@possiblespace\empty
        \let\matrixstyle@rowtext\empty
        \matrixstyle@finish@columns
    \else
        \tempcount=\matrixstyle@rowmin\relax
        \loop
            \edef\matrixstyle@rowtext{row \the\tempcount}%
            % Loops don't nest correctly because they both use the same \iterate command
            % either the inner loop needs to be in a scope, which won't work for us
            % or we need to save the value of \iterate
            \let\matrixstyle@saveiterate\iterate
            \matrixstyle@finish@columns
            \let\iterate\matrixstyle@saveiterate
            \advance\tempcount1\relax
        \unless\ifnum\tempcount>\matrixstyle@rowmax\repeat
    \fi
}

\def\matrixstyle@finish@columns{%
    \ifx\matrixstyle@columnmin\empty
        \let\matrixstyle@possiblespace\empty
        \let\matrixstyle@columntext\empty
        \matrixstyle@finish@key
    \else
        \tempcountb=\matrixstyle@columnmin\relax
        \loop
            \edef\matrixstyle@columntext{column \the\tempcountb}%
            \matrixstyle@finish@key
            \advance\tempcountb1\relax
        \unless\ifnum\tempcountb>\matrixstyle@columnmax\repeat
    \fi
}

\def\matrixstyle@finish@key{%
    \edef\temp{
        \matrixstyle@thepath/%
           \matrixstyle@rowtext \matrixstyle@possiblespace \matrixstyle@columntext
              /.code={\unexpanded\expandafter{\matrixstyle@thestyle}}%
    }%
    \expandafter\pgfkeys\expandafter{\temp}
}


\begin{document}

\tikzset{%%
  my node style/.style={%%
    minimum width=\dimexpr0.60in+12pt\relax,
    minimum height=\dimexpr0.30cm+12pt\relax,
    outer sep=0pt,
    draw},
  }

\begin{tikzpicture}

  \matrix (TBL) [%%
                 matrix of nodes,
                 nodes={%%
                   align=center,
                   inner sep=0pt,
                   anchor=center},
                     column 2 to 3 row 2 to 3/.matrix style={blue}
                ]
  {
                        & {$(-\infty,-2)$}               & {$(-2,-1)$}                     & {$(-1,1)$}                    & {$(1,2)$}                       & {$(2,\infty)$}                 \\[2pt]
   {$\abs{x^{2}-1}=\,$} & |[my node style]| {$x^{2}-1 $} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$1-x^{2}$} & |[my node style]| {$x^{2}-1$}   & |[my node style]| {$x^{2}-1$}  \\[-0.4pt]
   {$\abs{x^{2}-4}=\,$} &                   {$x^{2}-4 $} &                   {$4-x^{2}$}   &                   {$4-x^{2}$} &                   {$4-x^{2}$}   &                   {$x^{2}-4$}  \\[2pt]
   {$g(x) =$}           & |[my node style]| {$ 3 $ }     & |[my node style]| {$ 2x^{2}-5$} & |[my node style]| {$ -3 $}    & |[my node style]| { $2x^{2}-5$} & |[my node style]| {$ 3 $}      \\
  };

\end{tikzpicture}

\end{document} 
0

For the syntax row <r1> to <r2> columns <c1> to <c2> = <style> you would need to extend the .unknown key of /tikz so that it also checks for that.

But that already checks for a lot of stuff (Is it pgf key? Is it a color? Is it an arrow specification? Is it a shape?)


A row <r1> to <r2> columns <c1> to <c2>/.handler = <style> has been provided to you.


With a few keys and the .list handler, this is pretty easy to implement (and I've used many of these here) without going to deep into the internals of TikZ or PGFkeys.

The keys are

  • for plain columns and rows
    • columns = {<foreach list of columns>}{<style>}
      appends the style <style> to the column <i> style for the <i> in the list.
    • rows = {<foreach list of rows>}{<style>}
      appends the style <style> to the rows <i> style for the <i> in the list.
    • columns*/rows* as above but appends nodes = {<style>}.
  • for connected areas
    • range = {<r1> - <c1> to <r2> - <c2> = <style>}
      appends the style <style> to the cells in the supplied range.
    • range lists = {rows <foreach list of rows> columns <foreach list of column> = <style>
      appends the style <style> to the cells that lie in the specified ranges.
    • range*/range lists* as above but appends nodes = {<style>}.
  • for a list of various cells
    • rows cols = {r<r1>c<r1>, r<r2>c<c2>, …, r<rn>c<rn>}{<style>}
      appends the style <style> to the specified cells.

      This is still parsed by \foreach and one should be able to do rows cols = {r1c2, r1c..., r1c7}{<style>} Of course, you can change the arguments however you want. Since everything is done with .list (i.e. \foreach under the hood) spaces shouldn't matter.

    • rows cols* as above.

With a bit of math we can also implement if matrix/if matrix* (that are nestable) where we can use the PGFmath functions row and col to evaluate any conditional, then

if matrix* = {iseven(row + col)}{<style A>}{<style B>}

applies <style A> and <style B> alternatingly.

Example

The matrix below is just using

matrix of math nodes,
columns      = {1}      {anchor=base east},
columns      = {2,...,5}{column sep = -.4pt},
range lists* = {rows 2, 4 columns 2, ..., 6 = my node style},
checkers     = {1}{1}{fill=green!35}{fill=blue!25}

where checkers is using if matrix.

Code

\documentclass[border=6pt, tikz]{standalone}
\usepackage{amsmath}
\newcommand\abs[1]{\lvert#1\rvert}
\usetikzlibrary{matrix}
\makeatletter
\pgfqkeys{/utils}{
  if matrix/.code n args=3{%
    \begingroup
      \pgfmathdeclarefunction{row}{0}{\edef\pgfmathresult{\the\pgfmatrixcurrentrow}}%
      \pgfmathdeclarefunction{col}{0}{\edef\pgfmathresult{\the\pgfmatrixcurrentcolumn}}%
      \pgfmathparse{#1}%
    \expandafter\endgroup\expandafter
    \ifdim\pgfmathresult pt=0pt
      \expandafter\pgfutil@firstoftwo
    \else
      \expandafter\pgfutil@secondoftwo
    \fi
    {\pgfkeysalso{#3}}{\pgfkeysalso{#2}}}}
\makeatother
\tikzset{
  % columns = { <list> }{ <style> }
  columns/.style 2 args={
   /utils/tempa/.style={column ##1/.append style={#2}},
   /utils/tempa/.list={#1}},
  columns*/.style 2 args={columns={#1}{nodes={#2}}},
  %
  % rows = { <list> }{ <style> }
  rows/.style 2 args={
   /utils/tempa/.style={row ##1/.append style={#2}},
   /utils/tempa/.list={#1}},
  rows*/.style 2 args={rows={#1}{nodes={#2}}},
  %
  % rows cols = {r<r1>c<r1>, r<r2>c<c2>, …, r<rn>c<rn>}{ <style> }
  rows cols/.style 2 args={
   /utils/tempa/.style args={r##1c##2}{row ##1 column ##2/.append style={#2}},
   /utils/tempa/.list={#1}},
  rows cols*/.style 2 args={rows cols={#1}{nodes={#2}}},
  %
  % range = <r1> - <c1> to <r2> - <c2> = <style>
  range/.style args={#1-#2to#3-#4=#5}{
    range lists={rows#1,...,#3columns#2,...,#4={#5}}},
  range*/.style args={#1=#2}{range={#1=nodes={#2}}},
  %
  % range lists = { rows <list> columns <list> = <style> }
  range lists/.style args={rows#1columns#2=#3}{
   /utils/tempa/.style={
     /utils/tempb/.style={row ##1 column ####1/.append style={#3}},
     /utils/tempb/.list={#2}},
   /utils/tempa/.list={#1}},
  range lists*/.style args={#1=#2}{range lists={#1=nodes={#2}}},
  %
  % matrix math
  cells={
    if matrix/.style n args={3}{/utils/if matrix={##1}{##2}{##3}},
    if matrix*/.style n args={3}{/utils/if matrix={##1}{nodes={##2}}{nodes={##3}}},
    nodes={if matrix*/.style n args={3}{if matrix={####1}{####2}{####3}}}},
  if matrix/.style n args={3}{cells={/utils/if matrix={#1}{#2}{#3}}},
  if matrix*/.style n args={3}{if matrix={#1}{nodes={#2}}{nodes={#3}}},
}
\begin{document}
\begin{tikzpicture}[
  my node style/.style={
    minimum width=.60in+12pt,
    minimum height=.30cm+12pt,
    text depth=+0pt,
    font=\vphantom{$()0+-x^2$},
    draw
  },
  checkers/.style n args = {4}{
    if matrix*   = {and(row > #1, col > #2)}{
      if matrix  =   {iseven(row+col)}
                     {#3}{#4}}{}}
]
\matrix (TBL) [%%
  matrix of math nodes,
  columns      = {1}      {anchor=base east},
  columns      = {2,...,5}{column sep = -.4pt},
  range lists* = {rows 2, 4 columns 2, ..., 6 = my node style},
  % or:
  % columns    = {2, ..., 6}{rows* = {2, 4}{my node style}},
  % or:
  % rows cols* = {r2c2,r2c...,r2c6,r4c2,r4c...,r4c6}{my node style},
  checkers     = {1}{1}{fill=green!35}{fill=blue!25}
] {
                   & (-\infty,-2) & (-2,-1)  & (-1,1)  & (1,2)    & (2,\infty) \\[2pt]
  \abs{x^{2}-1}={} & x^{2}-1      & x^{2}-1  & 1-x^{2} &  x^{2}-1 & x^{2}-1    \\
  \abs{x^{2}-4}={} & x^{2}-4      & 4-x^{2}  & 4-x^{2} & 4-x^{2}  & x^{2}-4    \\[2pt]
           g(x)={} &  3           & 2x^{2}-5 &  -3     & 2x^{2}-5 & 3          \\
};
\end{tikzpicture}
\end{document}

Ouput

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .