Alternative to \setlength in arrays?

602 views
Skip to first unread message

amc...@gmail.com

unread,
Feb 7, 2021, 10:26:58 PM2/7/21
to MathJax Users
Hello,

I often use \setlength{arraycolsep}{5pt} (or whatever length) to adjust the spacing of my arrays - for some purposes a more "squashed" array is better.  However, MathJax doesn't support this.  What other options are available for horizontally squashing an array?

Thanks!

Davide Cervone

unread,
Feb 10, 2021, 2:48:19 PM2/10/21
to mathja...@googlegroups.com
MathJax doesn't have anything built in that allows you to change the column spacing.  But it is possible to implement it.  Here is a configuration that does so:

<script>
MathJax = {
  startup: {
    ready() {
      //
      //  These would be replaced by import commands if you wanted to make
      //  a proper extension.
      //
      const {Configuration} = MathJax._.input.tex.Configuration;
      const {EnvironmentMap, CommandMap} = MathJax._.input.tex.SymbolMap;
      const TexError = MathJax._.input.tex.TexError.default;
      const ParseMethods = MathJax._.input.tex.ParseMethods.default;
      const BaseMethods = MathJax._.input.tex.base.BaseMethods.default;
      const {AmsMethods} = MathJax._.input.tex.ams.AmsMethods;
      
      //
      //  This function replaces the column spacing by the \arraycolsep, if specified
      //  and the row spacing is adjusted by \arraystretch, if it is defined.
      //
      function AdjustSpacing(parser, array) {
        const def = array.arraydef;
        def.columnspacing = lengths.get('\\arraycolsep');
        const stretch = parser.lookup('macro', 'arraystretch');  // check if the macro is defined
        if (stretch) {
          const [, n, u] = def.rowspacing.match(/^(\d(?:\.\d*)?|\.\d+)([a-z]+)$/) || [];
          const f = parseFloat(stretch._args[0]);
          if (n && !isNaN(f)) {
            def.rowspacing = (parseFloat(n) * f) + u;
          }
        }
        return array;
      }
      
      //
      //  Define an environment map to override the array environments
      //    so that we can adjust the spacing
      //
      new EnvironmentMap('my-array-env', ParseMethods.environment, {
        array:        ['AlignedArray'],
        subarray:     ['Array', null, null, null, null, '0em', '0.1em', 'S', 1],
        smallmatrix:  ['Array', null, null, null, 'c', '.333em', '.2em', 'S', 1],
        matrix:       ['Array', null, null, null, 'c'],
        pmatrix:      ['Array', null, '(', ')', 'c'],
        bmatrix:      ['Array', null, '[', ']', 'c'],
        Bmatrix:      ['Array', null, '\\{', '\\}', 'c'],
        vmatrix:      ['Array', null, '\\vert', '\\vert', 'c'],
        Vmatrix:      ['Array', null, '\\Vert', '\\Vert', 'c'],
        cases:        ['Array', null, '\\{', '.', 'll', null, '.2em', 'T']
      }, {
        //
        //  Create the usual array, but adjust the spacing after that.
        //
        AlignedArray(parser, begin) {
          return AdjustSpacing(parser, BaseMethods.AlignedArray(parser, begin));
        },
        Array(parser, begin, ...args) {
          return AdjustSpacing(parser, BaseMethods.Array(parser, begin, ...args));
        }
      });
      
      //
      //  This stores the lengths that can be set (only \arraycolsep for now).
      //
      const lengths = new Map([
        ['\\arraycolsep', '']
      ]);

      //
      //  Define the \setlength macro
      //  It should check that the dimension is valid, but currently doesn't
      //
      new CommandMap('my-setlength', {
        setlength: 'SetLength'
      }, {
        SetLength(parser, name) {
          const id = parser.GetArgument('\\' + name);
          const dim = parser.GetArgument('\\' + name);
          if (!lengths.has(id)) {
            throw new TexError('MyBadLength', 'Length "' + id + '" is not a known length');
          }
          lengths.set(id, dim);
        }
      });

      //
      //  Define the package for our new environments and macro
      //
      Configuration.create('my-arraysep', {
        handler: {
          environment: ['my-array-env'],
          macro: ['my-setlength'],
        }
      });

      MathJax.startup.defaultReady();
    }
  },
  tex: {packages: {'[+]': ['my-arraysep']}}  // Tell TeX to iuse our package
}
</script>


This defines \setlength so that you can use \setlength{\arraycolsep}{5pt}, and also lets you use \newcommand\arraystretch{2} to scale the separation between rows by the given factor.

Note, however, that MathJax doesn't have local definition grouping, so everything is global.  That means you would need to reset these values by hand if you want them to go back to their defaults:  \setlength{\arraycolsep}{} and \renewcommand\arraystretch{1} will do that.

Perhaps that will fit the bill.

Davide



--
You received this message because you are subscribed to the Google Groups "MathJax Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/mathjax-users/50cdf36f-62e1-452c-aa60-3ec38191f272n%40googlegroups.com.

amc...@gmail.com

unread,
Feb 15, 2021, 7:23:41 PM2/15/21
to MathJax Users
Thank you so much for your detailed reply.  I'm still not fully clear about the differences in scoping between LaTeX and MathJax - so your comments were very helpful.  Might this mean, though, that you could create a new environment called, say "tightarray" which defines an array with small column separation, thus still allowing normally spaced arrays?  A difficulty for me is that I'm hoping to use both normally spaced, and more tightly spaced, arrays in the same document.

Thanks again,
Alasdair

Davide Cervone

unread,
Feb 16, 2021, 7:43:59 PM2/16/21
to mathja...@googlegroups.com
Might this mean, though, that you could create a new environment called, say "tightarray" which defines an array with small column separation, thus still allowing normally spaced arrays?

That is actually easier (I thought you wanted a LaTeX-compatible solution).  Here is the configuration:

<script>
MathJax = {
  startup: {
    ready() {
      //
      //  These would be replaced by import commands if you wanted to make
      //  a proper extension.
      //
      const {Configuration} = MathJax._.input.tex.Configuration;
      const {EnvironmentMap} = MathJax._.input.tex.SymbolMap;
      const ParseUtil = MathJax._.input.tex.ParseUtil.default;
      const ParseMethods = MathJax._.input.tex.ParseMethods.default;
      const BaseMethods = MathJax._.input.tex.base.BaseMethods.default;
      
      //
      //  Define an environment map to add the new tightarray environment
      //
      new EnvironmentMap('my-tightarray', ParseMethods.environment, {
        tightarray:   ['TightArray'],
      }, {
        //
        //  Create a usual array, but with optional inter-column spacing specified,
        //    and optional vertical placement (as with the array environment).
        //
        TightArray(parser, begin) {
          const spacing = parser.GetBrackets('\\begin{' + begin.getName() + '}');
          const align = parser.GetBrackets('\\begin{' + begin.getName() + '}');
          const item = BaseMethods.Array(parser, begin, null, null, null, spacing);
          return ParseUtil.setArrayAlign(item, align);
        }
      });
      
      //
      //  Define the package for our new environment
      //
      Configuration.create('my-tightarray', {
        handler: {
          environment: ['my-tightarray'],
        }
      });

      MathJax.startup.defaultReady();
    }
  },
  tex: {packages: {'[+]': ['my-tightarray']}}  // Tell TeX to use our package
}
</script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>

This defined \begin{tightarry}...\end{tightarray} the acts like \begin{array}...\end{array} but allows an optional bracket argument before the array template that indicates the separation between columns.  E.g., 

\[
\begin{tightarray}[0em]{ccc}
    1 & 0 & a\\
    0 & 1 & b
\end{tightarray}
\]

would make an array with no space between the columns.  You can specify the space between each column (as a space-separated list), so 

\[
\begin{tightarray}[2em 1em]{c|c|c}
    1 & 0 & a\\
    0 & 1 & b
\end{tightarray}
\]

uses 2em between the first two columns, and 1em between the second two (and any subsequent) columns.  It also puts vertical lines between the columns in this case because of the vertical lines in the template.

See if that is more to your liking.

A difficulty for me is that I'm hoping to use both normally spaced, and more tightly spaced, arrays in the same document.

You can reset the \arraysep when you want to go back to normal, but I admit that that could be more trouble than it is worth.

This new environment might be what you need.

Davide


amc...@gmail.com

unread,
Feb 17, 2021, 8:23:02 PM2/17/21
to MathJax Users
Thank you Davide - that is just wonderful!  And it works perfectly.  I already had some configuration options, so I was able to slot this code into that.  

cheers,
Alasdair

Reply all
Reply to author
Forward
0 new messages