diff --git a/README.md b/README.md index 9ba126c..64c45fe 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,16 @@ # Greater Tables -Creating presentation quality tables from pandas dataframes is frustrating. It is hard to left align text and right align numbers using pandas display or `.to_html`. The package `great_tables` does a really nice job with pandas and polars frames but does not support indexes. And formatting numbers requires care. +Creating presentation quality tables from pandas dataframes is frustrating. It is hard to left-align text and right-align numbers using pandas `display` or `df.to_html`. The `great_tables` package does a really nice job with pandas and polars dataframes but does not support indexes or TeX output. + +This package is provides consistent HTML and TeX table output with flexible type-based formatting, and table rules. Its main class `GT` can be subclassed to set appropriate defaults for your project. + +The project is currently in **beta** status. + +## The Name + +Obviously, the name is a play on the `great_tables` package. But, I have been maintaining a set of macros called [GREATools](https://www.mynl.com/old/GREAT/home.html) (generalized, reusable, extensible actuarial tools) in VBA and Python since the late 1990s, and call all my macro packages "GREAT". ## Examples +Coming soon. - -## API diff --git a/doc-build-test.bat b/doc-build-test.bat new file mode 100644 index 0000000..fe998ae --- /dev/null +++ b/doc-build-test.bat @@ -0,0 +1,39 @@ +@echo off +setlocal + +:: Define paths +set REPO_URL=https://github.com/mynl/greater_tables_project +set BUILD_DIR=C:\tmp\greater_tables_docs +set VENV_DIR=%BUILD_DIR%\venv + +:: Remove existing directory if it exists +if exist "%BUILD_DIR%" rd /s /q "%BUILD_DIR%" + +:: Clone the latest development repo +git clone --depth 1 %REPO_URL% "%BUILD_DIR%" +if %errorlevel% neq 0 exit /b %errorlevel% + +pushd "%BUILD_DIR%" + +:: Create virtual environment +python -m venv "%VENV_DIR%" +if %errorlevel% neq 0 exit /b %errorlevel% + +:: Activate virtual environment +call "%VENV_DIR%\Scripts\activate" + +:: Upgrade pip and install dependencies from pyproject.toml +python -m pip install --upgrade pip +pip install --upgrade build setuptools +pip install . +pip install ".[doc]" || pip install sphinx # Ensure Sphinx is installed + +:: Build the documentation +sphinx-build -b html docs docs/_build/html +if %errorlevel% neq 0 exit /b %errorlevel% + +:: Deactivate virtual environment +deactivate + +echo Documentation build complete: %BUILD_DIR%\docs\_build\html +endlocal diff --git a/greater_tables/__init__.py b/greater_tables/__init__.py index a5d9e55..4b8d053 100644 --- a/greater_tables/__init__.py +++ b/greater_tables/__init__.py @@ -1,4 +1,4 @@ -__version__ = '1.1.0' +__version__ = '0.6.0' __project__ = 'greater_tables' __author__ = 'Stephen J Mildenhall' diff --git a/greater_tables/greater_tables.py b/greater_tables/greater_tables.py index fe20507..e8e4f94 100644 --- a/greater_tables/greater_tables.py +++ b/greater_tables/greater_tables.py @@ -9,6 +9,7 @@ import pandas as pd from pandas.api.types import is_datetime64_any_dtype, is_integer_dtype,\ is_float_dtype # , is_numeric_dtype from pathlib import Path +import re import sys import warnings @@ -52,7 +53,6 @@ class GT(object): default_float_str='{x:,.3f}', default_date_str='%Y-%m-%d', default_ratio_str='{x:.1%}', - cast_to_floats=True, table_hrule_width=1, table_vrule_width=1, hrule_widths=None, @@ -68,6 +68,7 @@ class GT(object): pef_precision=3, pef_lower=-3, pef_upper=6, + cast_to_floats=True, debug=False): """ Create a greater_tables formatting object. @@ -107,7 +108,6 @@ class GT(object): """ if not df.columns.is_unique: raise ValueError('df column names are not unique') - self.df = df.copy(deep=True) # the object being formatted self.raw_df = df.copy(deep=True) # if not column_names: @@ -171,7 +171,7 @@ class GT(object): try: self.df.iloc[:, i] = self.df.iloc[:, i].astype(float) logger.debug(f'coerce {i}={c} from {old_type} to float') - except ValueError: + except (ValueError, TypeError): logger.debug(f'coercing {i}={c} from {old_type} to float FAILED') # now can determine types @@ -264,8 +264,10 @@ class GT(object): # because of the problem of non-unique indexes use a list and # not a dict to pass the formatters to to_html self._df_formatters = None - self.df_style = None - self.df_html = None + self.df_style = '' + self.df_html = '' + self._clean_html = '' + self.tex = '' # finally sparsify and then apply formaters # this radically alters the df, so keep a copy for now... self.df_pre_applying_formatters = self.df.copy() @@ -287,11 +289,13 @@ class GT(object): def default_date_formatter(self, x): """Date formatter.""" try: + print(x, self.default_date_str) return x.strftime(self.default_date_str) if pd.notna(x) else "" # return self.default_date_str.format(x=x) # return f'{x:%Y-%m-%d}' # f"{dt:%H:%M:%S}" except ValueError: - # logger.error(f'date error with {x=}') + print('eeror ') + logger.error(f'date error with {x=}') return str(x) def default_integer_formatter(self, x): @@ -425,10 +429,7 @@ class GT(object): ratio cols like in constructor """ - self.df_style = self.make_style() - self.df_html = self.make_html() - logger.info('CREATED HTML STYLE') - return self.df_style + self.df_html + return self.html def make_style(self): if self.debug: @@ -643,14 +644,34 @@ class GT(object): html.append(f'