Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
JAEarly committed Jun 5, 2022
2 parents b2bdf55 + 8d6f2cb commit e599104
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 35 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) [2020,2021] [Joseph Early]
Copyright (c) [2020-2022] [Joseph Early]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
41 changes: 24 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@
This package extends its functionality to allow the table to be directly output in Latex, removing the tedious copy and paste chore.
The Latex output matches the table design, and there are utilities for adding table captions, labels, and positions.

![](docs/cover_cropped.png)

## Features
- Draw a table object in a Latex format.
- Matches table decoration (border, header, hlines, vlines).
- Applies horizontal column alignment.
- Allows the user to drop certain columns from the output.
- Allows the user to drop columns and rows from the output.
- Provides the ability to add a caption, reference label, and position to the Latex output.
- The output is correctly indented for directly copying into Latex.
- Supports [booktabs](https://ctan.org/pkg/booktabs?lang=en) formatting.
Expand All @@ -38,28 +36,32 @@ texttable
The single function `latextable.draw_latex` returns a formatted Latex string based on the provided table.
Aside from table, all arguments are optional.


```
draw_latex(table, caption=None, label=None, drop_columns=None, position=None):
draw_latex(table, caption=None, caption_short=None, caption_above=False, label=None, drop_columns=None,
drop_rows=None, position=None, use_booktabs=False):
table: Texttable table to be rendered in Latex.
caption: A string that adds a caption to the Latex formatting.
caption_short: A string that adds a short caption (used in the list of tables). Ignored if caption is None.
caption_above: If True, the caption will be added above the table rather than below it (default).
label: A string that adds a referencing label to the Latex formatting.
drop_columns: A list of column names that won't be in the Latex output.
Each column name must be in the table header.
Each column name must be in the table header.
drop_rows: A list of row indices that won't be in the Latex output.
Each row index must be in [0, number of rows - 1], where number of rows does not include the header.
position: A string that represents LaTex's float position of the table.
For example 'ht' results in the float position [ht].
For example 'ht' results in the float position [ht].
use_booktabs: Whether to override the table formatting with booktabs (https://ctan.org/pkg/booktabs?lang=en).
If true, the texttable formatting is ignored, and instead the default booktabs style is used.
This overrides the border, vertical lines, and horizontal lines.
Note the booktabs package will need to be included in your Latex document (\usepackage{booktabs}).
Defaults to false.
If true, the texttable formatting is ignored, and instead the default booktabs style is used.
This overrides the border, vertical lines, and horizontal lines.
Note the booktabs package will need to be included in your Latex document (\\usepackage{booktabs}).
Defaults to false.
return: The formatted Latex table returned as a single string.
```

### Examples
A basic example is given below.
For more see the [examples directory](examples/).
For more see the [examples directory](examples).

Code:

Expand Down Expand Up @@ -126,19 +128,24 @@ A working example is also given in this [Colab Notebook](https://colab.research.

## Release History

* 0.3.0
* Added support for [short captions](https://tex.stackexchange.com/questions/11579/short-captions-for-figures-in-listoffigures)
(thanks to [PhilW92](https://github.com/PhilW92)).
* Added the ability to drop rows as well as columns.
* Captions can now be placed above tables instead of below.
* 0.2.1
* Removed row hlines when using booktabs.
* 0.2.0
* Added support for booktabs and table positioning.
* 0.1.1
* Minor changes to documentation.
* 0.1.0
* Initial Release
* Initial Release.

## Meta

[Joseph Early](https://www.jearly.co.uk/)
[@JosephAEarly](https://twitter.com/JosephAEarly)
[email protected]
Website: [Joseph Early](https://www.jearly.co.uk/)
Twitter: [@JosephAEarly](https://twitter.com/JosephAEarly)
Email: [[email protected]](mailto:[email protected])

Distributed under the MIT license. See ``LICENSE`` for more information.
Distributed under the MIT license. See [LICENSE](LICENSE) for more information.
56 changes: 55 additions & 1 deletion examples/basic_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ def run():
example_2()
example_3()
example_4()
example_5()
example_6()
example_7()


def example_1():
Expand Down Expand Up @@ -45,7 +48,6 @@ def example_2():


def example_3():

# Example 3 - Position
table_3 = Texttable()
table_3.set_cols_align(["c"] * 4)
Expand Down Expand Up @@ -78,5 +80,57 @@ def example_4():
print(latextable.draw_latex(table_4, caption="A table using booktabs.", label="table:booktabs", use_booktabs=True))


def example_5():
# Example 5 - Short Caption
table_5 = Texttable()
table_5.set_cols_align(["c"] * 3)
table_5.set_deco(Texttable.HEADER | Texttable.BORDER)
table_5.add_rows([['Company', 'Market Cap', 'Country'],
['Apple', '2.425T', 'USA'],
['Saudi Aramco', '2.358T', 'Saudi Arabia'],
['Microsoft', '2.011T', 'USA']])
print('\n-- Example 5: Short Caption --')
print('Texttable Output:')
print(table_5.draw())
print('\nLatextable Output:')
print(latextable.draw_latex(table_5, caption="A table with a short caption.", label="table:short_caption",
caption_short="Short caption"))


def example_6():
# Example 6 - Drop rows
table_6 = Texttable()
table_6.set_deco(Texttable.HEADER)
table_6.set_cols_align(["c"] * 3)
table_6.add_rows([['Position', 'Team', 'Points'],
['1', 'Fulham', '90'],
['2', 'Bournemouth', '88'],
['3', 'Huddersfield', '82'],
['4', 'Nottingham Forest', '80']])
print('\n-- Example 6: Drop Rows --')
print('Texttable Output:')
print(table_6.draw())
print('\nLatextable Output:')
print(latextable.draw_latex(table_6, caption="A table with dropped rows.", label="table:dropped_rows",
drop_rows=[1, 2]))


def example_7():
# Example 7 - Caption above
table_7 = Texttable()
table_7.set_deco(Texttable.HEADER | Texttable.VLINES)
table_7.set_cols_align(["c"] * 3)
table_7.add_rows([['Rank', 'Name', 'ELO'],
['1', 'Stockfish 15', '3541'],
['2', 'Dragon by Komodo', '3535'],
['3', 'Fat Fritz', '3518']])
print('\n-- Example 7: Caption Above --')
print('Texttable Output:')
print(table_7.draw())
print('\nLatextable Output:')
print(latextable.draw_latex(table_7, caption="This caption is above the table!", label="table:caption_above",
caption_above=True))


if __name__ == "__main__":
run()
114 changes: 99 additions & 15 deletions latextable.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,61 @@ def __init__(self, column, header):
super().__init__("Cannot drop column {:s} - column not in table header ({:s})\n".format(column, str(header)))


def draw_latex(table, caption=None, label=None, drop_columns=None, position=None, use_booktabs=False):
class DropRowError(Exception):

def __init__(self, n_rows, row_idx):
super().__init__("Cannot drop row {:d} - row is outside the range [1,{:d}]\n".format(row_idx, n_rows))


def draw_latex(table, caption=None, caption_short=None, caption_above=False, label=None, drop_columns=None,
drop_rows=None, position=None, use_booktabs=False):
"""
Draw a Texttable table in Latex format.
Aside from table, all arguments are optional.
:param table: Texttable table to be rendered in Latex.
:param caption: A string that adds a caption to the Latex formatting.
:param caption_short: A string that adds a short caption (used in the list of tables). Ignored if caption is None.
:param caption_above: If True, the caption will be added above the table rather than below it (default).
:param label: A string that adds a referencing label to the Latex formatting.
:param drop_columns: A list of column names that won't be in the Latex output.
Each column name must be in the table header.
:param drop_rows: A list of row indices that won't be in the Latex output.
Each row index must be in [0, number of rows - 1], where number of rows does not include the header.
:param position: A string that represents LaTex's float position of the table.
For example 'ht' results in the float position [ht].
:param use_booktabs: Whether to override the table formatting with booktabs (https://ctan.org/pkg/booktabs?lang=en).
If true, the texttable formatting is ignored, and instead the default booktabs style is used.
This overrides the border, vertical lines, and horizontal lines.
Note the booktabs package will need to be included in your Latex document (\\usepackage{booktabs}).
Defaults to false.
:return: The formatted Latex table returned as a single string.
"""
_sanitise_drop_columns(table._header, drop_columns)
_sanitise_drop_rows(len(table._rows), drop_rows)
out = ""
out += _draw_latex_preamble(table, position, use_booktabs)
out += _draw_latex_header(table, drop_columns, use_booktabs)
out += _draw_latex_content(table, drop_columns, use_booktabs)
out += _draw_latex_postamble(table, caption, label, use_booktabs)
out += _draw_latex_preamble(table=table,
position=position,
caption=caption if caption_above else None,
caption_short=caption_short if caption_above else None,
use_booktabs=use_booktabs)
out += _draw_latex_header(table=table,
drop_columns=drop_columns,
use_booktabs=use_booktabs)
out += _draw_latex_content(table=table,
drop_columns=drop_columns,
drop_rows=drop_rows,
use_booktabs=use_booktabs)
out += _draw_latex_postamble(table=table,
caption=caption if not caption_above else None,
caption_short=caption_short if not caption_above else None,
label=label,
use_booktabs=use_booktabs)
return out


def _draw_latex_preamble(table, position, use_booktabs):
def _draw_latex_preamble(table, position, caption, caption_short, use_booktabs):
"""
Draw the Latex table preamble.
Expand All @@ -52,19 +78,23 @@ def _draw_latex_preamble(table, position, use_booktabs):
:param table: Texttable table to be rendered in Latex.
:return: The Latex table preamble as a single string.
"""
out = "\\begin{table}"

# Start table with optional position
out = "\\begin{table}"
if position is not None:
out += '[{}]'.format(position)

out += "\n"

# Add caption if given
out += _draw_table_caption(caption, caption_short)

# Begin center
out += _indent_text("\\begin{center}\n", 1)

# Column setup with/without vlines
if table._has_vlines() and not use_booktabs:
column_str = "|".join(table._align)
else:
column_str = " ".join(table._align)
column_str = "".join(table._align)

# Border with/without edges
if table._has_border() and not use_booktabs:
Expand Down Expand Up @@ -106,7 +136,7 @@ def _draw_latex_header(table, drop_columns, use_booktabs):
return out


def _draw_latex_content(table, drop_columns, use_booktabs):
def _draw_latex_content(table, drop_columns, drop_rows, use_booktabs):
"""
Draw the Latex table content.
Expand All @@ -119,10 +149,12 @@ def _draw_latex_content(table, drop_columns, use_booktabs):
:param table: Texttable table to be rendered in Latex.
:param drop_columns: A list of columns that should not be in the final Latex output.
:param drop_columns: A list of row indices that should not be in the final Latex output.
:return: The Latex table content as a single string.
"""
out = ""
for idx, row in enumerate(table._rows):
rows = _drop_rows(table._rows, drop_rows)
for idx, row in enumerate(rows):
row = _drop_columns(row, table._header, drop_columns)
clean_row = _clean_row(row)
out += _indent_text(" & ".join(clean_row) + " \\\\\n", 3)
Expand All @@ -131,7 +163,7 @@ def _draw_latex_content(table, drop_columns, use_booktabs):
return out


def _draw_latex_postamble(table, caption, label, use_booktabs):
def _draw_latex_postamble(table, caption, caption_short, label, use_booktabs):
"""
Draw the Latex table postamble.
Expand All @@ -148,23 +180,42 @@ def _draw_latex_postamble(table, caption, label, use_booktabs):
:param table: Texttable table to be rendered in Latex.
:param caption: A caption to add to the table.
:param caption_short: Short caption used in the list of tables. Ignored if caption is None.
:param label: A label to add to the table.
:return: The Latex table postamble as one string.
"""
# Add bottom rule
out = ""
if table._has_border() or use_booktabs:
rule = 'bottomrule' if use_booktabs else 'hline'
out += _indent_text("\\{}\n".format(rule), 3)

# Close tabular and center environments
out += _indent_text("\\end{tabular}\n", 2)
out += _indent_text("\\end{center}\n", 1)
if caption is not None:
out += _indent_text("\\caption{" + caption + "}\n", 1)

# Add caption if given
out += _draw_table_caption(caption, caption_short)

# Add caption if given
if label is not None:
out += _indent_text("\\label{" + label + "}\n", 1)

# End!
out += "\\end{table}"
return out


def _draw_table_caption(caption, caption_short):
out = ""
if caption is not None:
out += _indent_text("\\caption", 1)
if caption_short is not None:
out += "[" + caption_short + "]"
out += "{" + caption + "}\n"
return out


def _clean_row(row):
"""
Clean a row prior to drawing. Currently just removes newlines.
Expand Down Expand Up @@ -217,6 +268,39 @@ def _drop_columns(target, header, drop_columns):
return target


def _sanitise_drop_rows(n_rows, drop_rows):
"""
Check the rows to be dropped - 0 <= row_idx < n_rows for each row_idx to be dropped.
:param drop_rows: List of rows to be dropped.
:param n_rows: Number of rows in the table (excluding the header).
:return: None
"""
if drop_rows is None:
return
# Check row idxs (ignores case).
for row_idx in drop_rows:
if not 0 <= row_idx < n_rows:
raise DropRowError(n_rows, row_idx)


def _drop_rows(rows, drop_rows):
"""
Drop rows by their indices.
:param rows: Table from which the rows should be dropped.
:param drop_rows: List of rows to be dropped.
:return: The target array with the relevant rows dropped.
"""
rows = rows[:]
if drop_rows is None:
return rows
# Delete relevant indices (in reverse order so deletion doesn't affect other index positions)
for i in sorted(drop_rows, reverse=True):
del rows[i]
return rows


def _indent_text(text, indent):
"""
Indent a string by a certain number of tabs.
Expand Down
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[metadata]
description-file=README.md
license_files=LICENSE
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# This call to setup() does all the work
setup(
name="latextable",
version="0.2.1",
version="0.3.0",
py_modules=['latextable'],
install_requires=["texttable"],
description="An extension to the texttable library that exports tables directly to Latex.",
Expand Down
Loading

0 comments on commit e599104

Please sign in to comment.