LaTeX writer: Provide a way to use table instead of longtable.

When the `float` class is attached to a table, a standard
floating `table` will be generated instead of a `longtable`.
Placement can be specified via the `latex-placement` attribute.
This will help, especially, those who use two-column layouts,
since `longtable` is incompatible with these.

Small change to the default LaTeX template: the `caption`
package is included and a default spacing set between the caption
and the table.

Closes #1023.
This commit is contained in:
John MacFarlane
2026-07-10 16:38:03 +02:00
parent d982f9f5ec
commit 3ecd95bf00
8 changed files with 291 additions and 77 deletions
+18 -2
View File
@@ -138,8 +138,8 @@ When using LaTeX, the following packages need to be available
[`amsfonts`], [`amsmath`], [`lm`], [`unicode-math`],
[`iftex`], [`listings`] (if the
`--listings` option is used), [`fancyvrb`], [`longtable`],
[`booktabs`], [`multirow`] (if the document contains a table with
cells that cross multiple rows), [`graphicx`] (if the document
[`caption`], [`booktabs`], [`multirow`] (if the document contains a table
with cells that cross multiple rows), [`graphicx`] (if the document
contains images), [`bookmark`], [`xcolor`],
[`soul`], [`geometry`] (with the `geometry` variable set),
[`setspace`] (with `linestretch`), and
@@ -191,6 +191,7 @@ better line breaks in URLs), and [`footnotehyper`] or
[`lua-ul`]: https://ctan.org/pkg/lua-ul
[`luatexja`]: https://ctan.org/pkg/luatexja
[`longtable`]: https://ctan.org/pkg/longtable
[`caption`]: https://ctan.org/pkg/caption
[`mathspec`]: https://ctan.org/pkg/mathspec
[`microtype`]: https://ctan.org/pkg/microtype
[`multirow`]: https://ctan.org/pkg/multirow
@@ -5005,6 +5006,21 @@ of the caption. (For the syntax, see
: Here's the caption. {#ident .class key="value"}
### Table placement in LaTeX ###
By default, pandoc will render tables in LaTeX using the `longtable`
environment. The tables will not "float" and they can span page boundaries.
If you prefer standard "floating" tables (which are limited to what can
fit on one page), add the `float` class to the table's attributes
(which can be specified after the caption). Optionally, the `latex-placement`
attribute may be used to pass parameters affecting the float placement:
: The caption of the table. {#ident .float latex-placement="ht"}
Note that `longtable` does not work with two-column layouts, so if you
are producing a two-column document using LaTeX, you will need to specify
the `float` class on every table (or use a Lua filter to add it automatically).
## Metadata blocks
### Extension: `pandoc_title_block` ###
+2
View File
@@ -69,6 +69,8 @@ $-- tables
$--
$if(tables)$
\usepackage{longtable,booktabs,array}
\usepackage{caption}
\captionsetup[table]{skip=6pt}
\newcounter{none} % for unnumbered tables
$if(multirow)$
\usepackage{multirow}
+2
View File
@@ -305,6 +305,8 @@ tex2pdf program args tmpDir source = do
x | "! Package inputenc Error" `BC.isPrefixOf` x
&& program /= "xelatex"
-> "\nTry running pandoc with --pdf-engine=xelatex."
"! Package longtable Error: longtable not in 1-column mode."
-> "\nTry adding the .float class attribute to your tables."
_ -> ""
return $ Left $ logmsg <> extramsg
(ExitSuccess, Nothing) -> return $ Left ""
+8 -8
View File
@@ -56,7 +56,7 @@ import Text.Pandoc.Shared
import Text.Pandoc.URI
import Text.Pandoc.Slides
import Text.Pandoc.Walk (query, walk, walkM)
import Text.Pandoc.Writers.LaTeX.Notes (notesToLaTeX)
import Text.Pandoc.Writers.LaTeX.Util (getAccumulatedNotes)
import Text.Pandoc.Writers.LaTeX.Caption (getCaption)
import Text.Pandoc.Writers.LaTeX.Table (tableToLaTeX)
import Text.Pandoc.Writers.LaTeX.Citation (citationsToNatbib,
@@ -65,7 +65,7 @@ import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState (..), startingState,
PdfStandard (..))
import Text.Pandoc.Writers.LaTeX.Lang (toBabel)
import Text.Pandoc.Writers.LaTeX.Util (stringToLaTeX, StringContext(..),
toLabel, inCmd,
toLabel, inCmd, withExternalNotes,
wrapDiv, hypertarget, labelFor,
getListingsLanguage, mbBraced)
import Text.Pandoc.Writers.Shared
@@ -663,7 +663,7 @@ blockToLaTeX (DefinitionList lst) = do
let spacing = if all (isTightList . snd) lst
then text "\\tightlist"
else empty
notes <- notesToLaTeX <$> gets stNotes
notes <- getAccumulatedNotes
return $ text ("\\begin{description}" <> inc) $$ spacing $$ vcat items $$
"\\end{description}" $$ notes
blockToLaTeX HorizontalRule =
@@ -679,7 +679,7 @@ blockToLaTeX (Table attr blkCapt specs thead tbodies tfoot) =
(Ann.toTable attr blkCapt specs thead tbodies tfoot)
blockToLaTeX (Figure (ident, _, kvs) captnode body) = do
opts <- gets stOptions
(capt, captForLof, footnotes) <- getCaption inlineListToLaTeX True captnode
(capt, captForLof) <- withExternalNotes $ getCaption inlineListToLaTeX captnode
lab <- labelFor ident
let caption = "\\caption" <> captForLof <> braces capt <> lab
placement = case lookup "latex-placement" kvs of
@@ -705,6 +705,7 @@ blockToLaTeX (Figure (ident, _, kvs) captnode body) = do
Table {} -> Any True
_ -> Any False)
st <- get
footnotes <- getAccumulatedNotes
return $ (case () of
_ | containsTable body ->
-- placing a longtable in a figure or center environment does
@@ -764,10 +765,9 @@ listItemToLaTeX isOrdered lst
defListItemToLaTeX :: PandocMonad m => ([Inline], [[Block]]) -> LW m (Doc Text)
defListItemToLaTeX (term, defs) = do
-- needed to turn off 'listings' because it breaks inside \item[...]:
oldExternalNotes <- gets stExternalNotes
modify $ \s -> s{stInItem = True, stExternalNotes = True}
term' <- inlineListToLaTeX term
modify $ \s -> s{stInItem = False, stExternalNotes = oldExternalNotes}
modify $ \s -> s{ stInItem = True }
term' <- withExternalNotes $ inlineListToLaTeX term
modify $ \s -> s{ stInItem = False }
-- put braces around term if it contains an internal link,
-- since otherwise we get bad bracket interactions: \item[\hyperref[..]
let isInternalLink (Link _ _ (src,_))
+7 -16
View File
@@ -21,29 +21,20 @@ import Text.Pandoc.Definition
import Text.DocLayout (Doc, brackets, empty)
import Text.Pandoc.Shared
import Text.Pandoc.Walk
import Text.Pandoc.Writers.LaTeX.Notes (notesToLaTeX)
import Text.Pandoc.Writers.LaTeX.Types
( LW, WriterState (stExternalNotes, stNotes, stInCaption) )
import Text.Pandoc.Writers.LaTeX.Types ( LW, WriterState (stInCaption) )
-- | Produces the components of a LaTeX 'caption' command. Returns a triple
-- containing the caption text, the short caption for the list of
-- figures/tables, and the footnote definitions.
-- | Produces the components of a LaTeX 'caption' command. Returns a pair
-- containing the caption text and the short caption for the list of
-- figures/tables.
getCaption :: PandocMonad m
=> ([Inline] -> LW m (Doc Text)) -- ^ inlines converter
-> Bool -- ^ whether to extract notes
-> Caption
-> LW m (Doc Text, Doc Text, Doc Text)
getCaption inlineListToLaTeX externalNotes (Caption maybeShort long) = do
-> LW m (Doc Text, Doc Text)
getCaption inlineListToLaTeX (Caption maybeShort long) = do
modify $ \st -> st{ stInCaption = True }
let long' = blocksToInlines long
oldExternalNotes <- gets stExternalNotes
modify $ \st -> st{ stExternalNotes = externalNotes, stNotes = [] }
capt <- inlineListToLaTeX long'
footnotes <- if externalNotes
then notesToLaTeX <$> gets stNotes
else return empty
modify $ \st -> st{ stExternalNotes = oldExternalNotes, stNotes = [] }
-- We can't have footnotes in the list of figures/tables, so remove them:
let getNote (Note _) = Any True
getNote _ = Any False
@@ -55,4 +46,4 @@ getCaption inlineListToLaTeX externalNotes (Caption maybeShort long) = do
else return empty
Just short -> toShortCapt short
modify $ \st -> st{ stInCaption = False }
return (capt, captForLof, footnotes)
return (capt, captForLof)
+105 -51
View File
@@ -1,5 +1,7 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleContexts #-}
{- |
Module : Text.Pandoc.Writers.LaTeX.Table
Copyright : Copyright (C) 2006-2024 John MacFarlane
@@ -24,17 +26,17 @@ import qualified Data.Text as T
import Text.Pandoc.Class.PandocMonad (PandocMonad)
import Text.Pandoc.Definition
import Text.DocLayout
( Doc, braces, cr, empty, hcat, hsep, isEmpty, literal, nest
, text, vcat, ($$) )
( Doc, braces, brackets, cr, empty, hcat, hsep, isEmpty, literal, nest
, text, vcat, ($$))
import Text.Pandoc.Shared (splitBy, tshow)
import Text.Pandoc.Walk (walk, query)
import Data.Monoid (Any(..))
import Text.Pandoc.Writers.LaTeX.Caption (getCaption)
import Text.Pandoc.Writers.LaTeX.Notes (notesToLaTeX)
import Text.Pandoc.Writers.LaTeX.Types
( LW, WriterState (stBeamer, stExternalNotes, stInMinipage, stMultiRow
, stNotes, stTable, stOptions) )
import Text.Pandoc.Writers.LaTeX.Util (labelFor)
( LW, WriterState (stBeamer, stInMinipage, stMultiRow
, stTable, stOptions) )
import Text.Pandoc.Writers.LaTeX.Util (labelFor, withExternalNotes,
getAccumulatedNotes)
import Text.Printf (printf)
import qualified Text.Pandoc.Builder as B
import qualified Text.Pandoc.Writers.AnnotatedTable as Ann
@@ -46,30 +48,103 @@ tableToLaTeX :: PandocMonad m
-> Ann.Table
-> LW m (Doc Text)
tableToLaTeX inlnsToLaTeX blksToLaTeX tbl = do
let (Ann.Table (ident, classes, kvs) caption specs thead tbodies tfoot) = tbl
let placement = brackets $ maybe mempty (text . T.unpack)
$ lookup "latex-placement" kvs
-- if the float class is included in table attributes, we generate a floating
-- table environment; otherwise we use longtable
beamer <- gets stBeamer
let float = "float" `elem` classes
let renderTable = do
capt <- captionToLaTeX inlnsToLaTeX caption ident
let isSimpleTable =
all ((== ColWidthDefault) . snd) specs &&
all (all isSimpleCell)
(mconcat [ headRows thead
, concatMap bodyRows tbodies
, footRows tfoot
])
let colDesc' = colDescriptors isSimpleTable tbl
let colDesc = braces ("@{}" <> colDesc' <> "@{}")
-- the @{} removes extra space at beginning and end
let colCount = ColumnCount $ length specs
let mkHead = headToLaTeX blksToLaTeX isSimpleTable colCount
let mkRow = rowToLaTeX blksToLaTeX isSimpleTable colCount BodyCell
if float
then tableToLaTeXTable placement colDesc mkHead mkRow capt thead tbodies tfoot
else tableToLaTeXLongtable colDesc mkHead mkRow capt thead tbodies tfoot
-- See #5367 -- footnotehyper/footnote don't work in beamer,
-- so we need to produce the notes outside the table...
if float || beamer
then ($$) <$> withExternalNotes renderTable <*> getAccumulatedNotes
else renderTable
tableToLaTeXTable :: PandocMonad m
=> Doc Text
-> Doc Text
-> (Ann.TableHead -> LW m (Doc Text))
-> ([Ann.Cell] -> LW m (Doc Text))
-> Doc Text
-> Ann.TableHead
-> [Ann.TableBody]
-> Ann.TableFoot
-> LW m (Doc Text)
tableToLaTeXTable placement colDesc mkHead mkRow capt thead tbodies tfoot = do
opts <- gets stOptions
let hasTopCaption = not (isEmpty capt) &&
writerTableCaptionPosition opts == CaptionAbove
let hasBottomCaption = not (isEmpty capt) &&
writerTableCaptionPosition opts == CaptionBelow
head' <- if isEmptyHead thead
then return "\\toprule\\noalign{}"
else mkHead thead
rows' <- mapM mkRow $ mconcat (map bodyRows tbodies)
lastfoot <- mapM mkRow $ footRows tfoot
let foot' = (if isEmptyFoot tfoot
then mempty
else "\\midrule\\noalign{}" $$ vcat lastfoot)
$$ "\\bottomrule\\noalign{}"
modify $ \s -> s{ stTable = True }
let makeUnnumbered x = "{\\def\\LTcaptype{none} % do not increment counter" $$ x $$ "}"
return
$ (if null capt then makeUnnumbered else id)
$ "\\begin{table}" <> placement
$$ "\\centering"
$$ (if hasTopCaption
then capt <> "\\tabularnewline"
else mempty)
$$ "\\begin{tabular}" <> colDesc
$$ head'
$$ vcat rows'
$$ foot'
$$ "\\end{tabular}"
$$ (if hasBottomCaption
then capt <> "\\tabularnewline"
else mempty)
$$ "\\end{table}"
tableToLaTeXLongtable :: PandocMonad m
=> Doc Text
-> (Ann.TableHead -> LW m (Doc Text))
-> ([Ann.Cell] -> LW m (Doc Text))
-> Doc Text
-> Ann.TableHead
-> [Ann.TableBody]
-> Ann.TableFoot
-> LW m (Doc Text)
tableToLaTeXLongtable colDesc mkHead mkRow capt thead tbodies tfoot = do
opts <- gets stOptions
let (Ann.Table (ident, _, _) caption specs thead tbodies tfoot) = tbl
CaptionDocs capt captNotes <- captionToLaTeX inlnsToLaTeX caption ident
let hasTopCaption = not (isEmpty capt) &&
writerTableCaptionPosition opts == CaptionAbove
let hasBottomCaption = not (isEmpty capt) &&
writerTableCaptionPosition opts == CaptionBelow
let isSimpleTable =
all ((== ColWidthDefault) . snd) specs &&
all (all isSimpleCell)
(mconcat [ headRows thead
, concatMap bodyRows tbodies
, footRows tfoot
])
let removeNote (Note _) = Span ("", [], []) []
removeNote x = x
let colCount = ColumnCount $ length specs
-- The first head is not repeated on the following pages. If we were to just
-- use a single head, without a separate first head, then the caption would be
-- repeated on all pages that contain a part of the table. We avoid this by
-- making the caption part of the first head. The downside is that we must
-- duplicate the header rows for this.
head' <- do
let mkHead = headToLaTeX blksToLaTeX isSimpleTable colCount
case (hasTopCaption, isEmptyHead thead) of
(False, True) -> return "\\toprule\\noalign{}"
(False, False) -> mkHead thead
@@ -79,15 +154,15 @@ tableToLaTeX inlnsToLaTeX blksToLaTeX tbl = do
(True, False) -> do
-- avoid duplicate notes in head and firsthead:
firsthead <- mkHead thead
let removeNote (Note _) = Span ("", [], []) []
removeNote x = x
repeated <- mkHead (walk removeNote thead)
return $ capt <> "\\tabularnewline"
$$ firsthead
$$ "\\endfirsthead"
$$ repeated
rows' <- mapM (rowToLaTeX blksToLaTeX isSimpleTable colCount BodyCell) $
mconcat (map bodyRows tbodies)
lastfoot <- mapM (rowToLaTeX blksToLaTeX isSimpleTable colCount BodyCell) $
footRows tfoot
rows' <- mapM mkRow $ mconcat (map bodyRows tbodies)
lastfoot <- mapM mkRow $ footRows tfoot
let foot' = (if isEmptyFoot tfoot
then mempty
else "\\midrule\\noalign{}" $$ vcat lastfoot)
@@ -96,14 +171,11 @@ tableToLaTeX inlnsToLaTeX blksToLaTeX tbl = do
then "\\tabularnewline" $$ capt
else mempty)
modify $ \s -> s{ stTable = True }
notes <- notesToLaTeX <$> gets stNotes
beamer <- gets stBeamer
let makeUnnumbered x = "{\\def\\LTcaptype{none} % do not increment counter" $$ x $$ "}"
return
$ (if null capt then makeUnnumbered else id)
$ "\\begin{longtable}[]" <>
braces ("@{}" <> colDescriptors isSimpleTable tbl <> "@{}")
-- the @{} removes extra space at beginning and end
$ "\\begin{longtable}[]" <> colDesc
$$ head'
$$ "\\endhead"
$$ vcat
@@ -120,8 +192,6 @@ tableToLaTeX inlnsToLaTeX blksToLaTeX tbl = do
, vcat rows'
])
$$ "\\end{longtable}"
$$ captNotes
$$ notes
isSimpleCell :: Ann.Cell -> Bool
isSimpleCell (Ann.Cell _ _ (Cell _attr _align _rowspan _colspan blocks)) =
@@ -184,28 +254,18 @@ colAlign = \case
AlignCenter -> "c"
AlignDefault -> "l"
data CaptionDocs =
CaptionDocs
{ captionCommand :: Doc Text
, captionNotes :: Doc Text
}
captionToLaTeX :: PandocMonad m
=> ([Inline] -> LW m (Doc Text))
-> Caption
-> Text -- ^ table identifier (label)
-> LW m CaptionDocs
-> LW m (Doc Text)
captionToLaTeX inlnsToLaTeX caption ident = do
(captionText, captForLot, captNotes) <- getCaption inlnsToLaTeX False caption
(captionText, captForLot) <- getCaption inlnsToLaTeX caption
label <- labelFor ident
return $ CaptionDocs
{ captionNotes = captNotes
, captionCommand = if isEmpty captionText && isEmpty label
then empty
else "\\caption" <> captForLot <>
braces captionText
<> label
}
return $ if isEmpty captionText && isEmpty label
then empty
else "\\caption" <> captForLot <>
braces captionText <> label
type BlocksWriter m = [Block] -> LW m (Doc Text)
@@ -322,11 +382,6 @@ cellToLaTeX blockListToLaTeX isSimpleTable colCount celltype annotatedCell = do
let align = case align' of
AlignDefault -> specAlign
_ -> align'
beamer <- gets stBeamer
externalNotes <- gets stExternalNotes
-- See #5367 -- footnotehyper/footnote don't work in beamer,
-- so we need to produce the notes outside the table...
modify $ \st -> st{ stExternalNotes = beamer }
let isPlainOrPara = \case
Para{} -> True
Plain{} -> True
@@ -352,7 +407,6 @@ cellToLaTeX blockListToLaTeX isSimpleTable colCount celltype annotatedCell = do
(if hasLineBreaks then "\\strut" else mempty)
<> cr <>
"\\end{minipage}"
modify $ \st -> st{ stExternalNotes = externalNotes }
when (rowspan /= RowSpan 1) $
modify (\st -> st{ stMultiRow = True })
let inMultiColumn x = case colspan of
+20
View File
@@ -18,6 +18,8 @@ module Text.Pandoc.Writers.LaTeX.Util (
, labelFor
, getListingsLanguage
, mbBraced
, withExternalNotes
, getAccumulatedNotes
)
where
@@ -27,6 +29,7 @@ import Text.Pandoc.Class (PandocMonad, toLang)
import Text.Pandoc.Options (WriterOptions(..), isEnabled)
import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState(..))
import Text.Pandoc.Writers.LaTeX.Lang (toBabel)
import Text.Pandoc.Writers.LaTeX.Notes (notesToLaTeX)
import Text.Pandoc.Highlighting (toListingsLanguage)
import Text.DocLayout
import Text.Pandoc.Definition
@@ -285,3 +288,20 @@ mbBraced :: Text -> Text
mbBraced x = if not (T.all isAlphaNum x)
then "{" <> x <> "}"
else x
withExternalNotes :: PandocMonad m
=> LW m a
-> LW m a
withExternalNotes p = do
oldExternalNotes <- gets stExternalNotes
modify $ \st -> st{ stExternalNotes = True }
res <- p
modify $ \st -> st{ stExternalNotes = oldExternalNotes }
return res
getAccumulatedNotes :: PandocMonad m
=> LW m (Doc Text)
getAccumulatedNotes = do
res <- notesToLaTeX <$> gets stNotes
modify $ \st -> st{ stNotes = [] }
return res
+129
View File
@@ -0,0 +1,129 @@
```
% pandoc -t latex
: Here's the caption.
It may span multiple lines. {.float #ident latex-placement="ht"}
---------------------------------------------------------------
Centered Left Right
Header Aligned Aligned Default aligned
---------- --------- ----------- ---------------------------
First row 12.0 Example of a row that spans
multiple lines.
Second row 5.0 Here's another one. Note
the blank line between rows.
---------------------------------------------------------------
^D
\begin{table}[ht]
\centering
\caption{Here's the caption. It may span multiple
lines.}\label{ident}\tabularnewline
\begin{tabular}{@{}
>{\centering\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1667}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1528}}
>{\raggedleft\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1806}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3889}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\centering
Centered Header
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Left Aligned
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedleft
Right Aligned
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Default aligned
\end{minipage} \\
\midrule\noalign{}
First & row & 12.0 & Example of a row that spans multiple lines. \\
Second & row & 5.0 & Here's another one. Note the blank line between
rows. \\
\bottomrule\noalign{}
\end{tabular}
\end{table}
```
```
% pandoc -t latex
: Simple table with no column headers {.float #ident}
------- ------ ---------- -------
12 12 12 12
123 123 123 123
1 1 1 1
------- ------ ---------- -------
^D
\begin{table}[]
\centering
\caption{Simple table with no column
headers}\label{ident}\tabularnewline
\begin{tabular}{@{}rlcr@{}}
\toprule\noalign{}
12 & 12 & 12 & 12 \\
123 & 123 & 123 & 123 \\
1 & 1 & 1 & 1 \\
\bottomrule\noalign{}
\end{tabular}
\end{table}
```
```
% pandoc -t latex
+--------------------+---------------------+---------------+---------------+
| Name^[In English.] | Capital | Population\ | Area\ |
| | | (in 2018) | (in km^2^) |
+:==================:+:====================+:==============+:==============+
| Denmark | Copenhagen | 5,809,502 | 43,094 |
+--------------------+---------------------+---------------+---------------+
| Finland | Helsinki | 5,537,364 | 338,145 |
+--------------------+---------------------+---------------+---------------+
| Iceland^[Brrr.] | Reykjavik | 343,518 | 103,000 |
+--------------------+---------------------+---------------+---------------+
| Norway | Oslo | 5,372,191 | 323,802 |
+--------------------+---------------------+---------------+---------------+
| Sweden | Stockholm | 10,313,447 | 450,295 |
+====================+=====================+===============+===============+
| Total | | 27,376,022 | 1,258,336 |
+====================+=====================+===============+===============+
: States belonging to the *Nordics.* {#nordics source="wikipedia" .float}
^D
\begin{table}[]
\centering
\caption{States belonging to the
\emph{Nordics.}}\label{nordics}\tabularnewline
\begin{tabular}{@{}
>{\centering\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.2727}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.2857}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.2078}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.2078}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\centering
Name\footnotemark{}
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Capital
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Population\\
(in 2018)\strut
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Area\\
(in km\textsuperscript{2})\strut
\end{minipage} \\
\midrule\noalign{}
Denmark & Copenhagen & 5,809,502 & 43,094 \\
Finland & Helsinki & 5,537,364 & 338,145 \\
Iceland\footnotemark{} & Reykjavik & 343,518 & 103,000 \\
Norway & Oslo & 5,372,191 & 323,802 \\
Sweden & Stockholm & 10,313,447 & 450,295 \\
\midrule\noalign{}
Total & & 27,376,022 & 1,258,336 \\
\bottomrule\noalign{}
\end{tabular}
\end{table}
\addtocounter{footnote}{-1}
\footnotetext{In English.}
\addtocounter{footnote}{1}
\footnotetext{Brrr.}
```