4

I'm using pandoc to convert a Markdown document to LaTeX. I saved the default LaTeX template (pandoc -D latex) and modified it to my needs.

I now need to change how the tables look like:

  1. Change the text color of the table captions;
  2. Change the caption location from above the table to under the table;
  3. Use a "grid" table where the cell boundaries are visible;
  4. Change the headers to be bold text on grey background.

I was able to change the color of the table captions (point 1.) using:

\usepackage{caption}
\DeclareCaptionFont{myColor}{\color[RGB]{40,70,119}}
\captionsetup{labelfont=myColor,textfont=myColor,position=bottom}

but the position option is ignored (point 2.)

I would like to be able to control the styling of the pandoc generated LaTeX table. Is that possible? Any suggestion?

Thanks!

big_gie
  • 2,829
  • 3
  • 31
  • 45
  • `position` only changes whether the spacing/margins should be suitable for having the caption above or below the tabular, but the `\caption` command needs to come before the tabular to have the caption above the table. – Ulrich Schwarz Dec 03 '15 at 18:43
  • How about using a `\renewenvironment` on the `longtable`? Could I modify the environment so that I could, for example, place the caption after the table's lines? – big_gie Dec 03 '15 at 19:46

1 Answers1

9

It's actually possible to change how the tables are generated, instead of trying to fix them at a later time. What is needed is a pandoc filter.

Instead of telling pandoc to generate the final document, its AST needs to be fed to the filter so the wanted formatting can be generated instead of the default one. Then this modified AST is sent back to pandoc for the final conversion.

This AST is the JSON format.

The process is as follow:

pandoc -t json -s | ./filter.py | pandoc -f json

where filter.py is a filter taking JSON data as stdin and spiting modified JSON to stdout.

This can be done without piping by telling pandoc:

pandoc --filter ./filter.py -s

Here's the filter I am using:

#!/usr/bin/env python2

import pandocfilters as pf

def latex(s):
    return pf.RawBlock('latex', s)

def inlatex(s):
    return pf.RawInline('latex', s)

def tbl_caption(s):
    return pf.Para([inlatex(r'\caption{')] + s + [inlatex('}')])

def tbl_alignment(s):
    aligns = {
        "AlignDefault": 'l',
        "AlignLeft": 'l',
        "AlignCenter": 'c',
        "AlignRight": 'r',
    }
    return ''.join([aligns[e['t']] for e in s])

def tbl_headers(s):
    result = s[0][0]['c'][:]
    # Build the columns. Note how the every column value is bold.
    # We are still missing "\textbf{" for the first column
    # and a "}" for the last column.
    for i in range(1, len(s)):
        result.append(inlatex(r'} & \textbf{'))
        result.extend(s[i][0]['c'])
    # Don't forget to close the last column's "\textbf{" before newline
    result.append(inlatex(r'} \\ \hline'))
    # Put the missing "\textbf{" in front of the list
    result.insert(0, inlatex(r'\textbf{'))
    # Preprend the command to set the row color in front of everything
    result.insert(0, inlatex(r'\rowcolor{grey} '))
    return pf.Para(result)

def tbl_contents(s):
    result = []
    for row in s:
        para = []
        for col in row:
            para.extend(col[0]['c'])
            para.append(inlatex(' & '))
        result.extend(para)
        result[-1] = inlatex(r' \\ \hline' '\n')
    return pf.Para(result)

def do_filter(k, v, f, m):
    if k == "Table":
        # Ensure every alignment characters is surrounded by a pipes.
        # Get the string of the alignment characters
        # and split into an array for every characters.
        split_alignment = [c for c in tbl_alignment(v[1])]
        # Join this list into a single string with pipe symbols
        # between them, plus pipes at start and end.
        # This results in a boxed table.
        new_alignment = "|" + "|".join(split_alignment) + "|"
        return [latex(r'\begin{table}[h]'),
                latex(r'\centering'),
                latex(r'\begin{tabular}{%s} \hline' % new_alignment),
                tbl_headers(v[3]),
                tbl_contents(v[4]),
                latex(r'\end{tabular}'),
                # Put the caption after the tabular so it appears under table.
                tbl_caption(v[0]),
                latex(r'\end{table}')]


if __name__ == "__main__":
    pf.toJSONFilter(do_filter)

Note that it's using the pandocfilters python module. Install it using pip:

pip install pandocfilters

Sources:

big_gie
  • 2,829
  • 3
  • 31
  • 45
  • 1
    trying to run this filter results in [this error message](https://gist.github.com/salim-b/dd32c1f01221b2c9a88e3b66aa209c99)... – Salim B Sep 30 '17 at 21:09
  • The pandoc AST changes over time, therefore a filter like that is not bulletproof - nevertheless: If you want to adjust how your tables look for a specific document it is a solid approach. Thanks for sharing it, took a few hours to dive in, but I'm quite happy with the result. – dahrens Apr 20 '21 at 02:59