rtflite 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. rtflite-0.1.0/.github/workflows/ci-tests.yml +56 -0
  2. rtflite-0.1.0/.github/workflows/mkdocs.yml +42 -0
  3. rtflite-0.1.0/.gitignore +19 -0
  4. rtflite-0.1.0/.python-version +1 -0
  5. rtflite-0.1.0/CHANGELOG.md +20 -0
  6. rtflite-0.1.0/LICENSE +20 -0
  7. rtflite-0.1.0/LICENSES_THIRD_PARTY +24 -0
  8. rtflite-0.1.0/PKG-INFO +62 -0
  9. rtflite-0.1.0/README.md +32 -0
  10. rtflite-0.1.0/docs/articles/example-baseline.md +102 -0
  11. rtflite-0.1.0/docs/articles/example-baseline.qmd +106 -0
  12. rtflite-0.1.0/docs/articles/images/example-baseline/output.pdf +0 -0
  13. rtflite-0.1.0/docs/assets/IBMPlexMono-Text.woff2 +0 -0
  14. rtflite-0.1.0/docs/assets/IBMPlexMono-TextItalic.woff2 +0 -0
  15. rtflite-0.1.0/docs/assets/favicon.png +0 -0
  16. rtflite-0.1.0/docs/assets/logo.png +0 -0
  17. rtflite-0.1.0/docs/changelog.md +20 -0
  18. rtflite-0.1.0/docs/index.md +32 -0
  19. rtflite-0.1.0/docs/javascripts/fix-embed-focus.js +6 -0
  20. rtflite-0.1.0/docs/reference/convert.md +8 -0
  21. rtflite-0.1.0/docs/reference/encode.md +8 -0
  22. rtflite-0.1.0/docs/reference/input.md +14 -0
  23. rtflite-0.1.0/docs/reference/row.md +11 -0
  24. rtflite-0.1.0/docs/reference/strwidth.md +8 -0
  25. rtflite-0.1.0/docs/scripts/logo-text.svg +3 -0
  26. rtflite-0.1.0/docs/scripts/logo.R +17 -0
  27. rtflite-0.1.0/docs/scripts/logo.sh +53 -0
  28. rtflite-0.1.0/docs/scripts/sync.sh +40 -0
  29. rtflite-0.1.0/docs/stylesheets/extra.css +73 -0
  30. rtflite-0.1.0/examples/example-baseline.py +44 -0
  31. rtflite-0.1.0/mkdocs.yml +86 -0
  32. rtflite-0.1.0/pyproject.toml +69 -0
  33. rtflite-0.1.0/requirements-dev.lock +377 -0
  34. rtflite-0.1.0/requirements.lock +36 -0
  35. rtflite-0.1.0/scripts/download_fonts.sh +22 -0
  36. rtflite-0.1.0/scripts/update_color_table.R +33 -0
  37. rtflite-0.1.0/scripts/update_unicode_latex.py +94 -0
  38. rtflite-0.1.0/src/rtflite/__init__.py +3 -0
  39. rtflite-0.1.0/src/rtflite/convert.py +143 -0
  40. rtflite-0.1.0/src/rtflite/data/__init__.py +0 -0
  41. rtflite-0.1.0/src/rtflite/data/baseline.csv +15 -0
  42. rtflite-0.1.0/src/rtflite/dictionary/__init__.py +0 -0
  43. rtflite-0.1.0/src/rtflite/dictionary/color_table.py +667 -0
  44. rtflite-0.1.0/src/rtflite/dictionary/libreoffice.py +23 -0
  45. rtflite-0.1.0/src/rtflite/dictionary/unicode_latex.py +692 -0
  46. rtflite-0.1.0/src/rtflite/encode.py +369 -0
  47. rtflite-0.1.0/src/rtflite/fonts/README.md +24 -0
  48. rtflite-0.1.0/src/rtflite/fonts/__init__.py +0 -0
  49. rtflite-0.1.0/src/rtflite/fonts/cros/Caladea-Regular.ttf +0 -0
  50. rtflite-0.1.0/src/rtflite/fonts/cros/Carlito-Regular.ttf +0 -0
  51. rtflite-0.1.0/src/rtflite/fonts/cros/Gelasio-Regular.ttf +0 -0
  52. rtflite-0.1.0/src/rtflite/fonts/liberation/LiberationMono-Regular.ttf +0 -0
  53. rtflite-0.1.0/src/rtflite/fonts/liberation/LiberationSans-Regular.ttf +0 -0
  54. rtflite-0.1.0/src/rtflite/fonts/liberation/LiberationSerif-Regular.ttf +0 -0
  55. rtflite-0.1.0/src/rtflite/input.py +742 -0
  56. rtflite-0.1.0/src/rtflite/row.py +347 -0
  57. rtflite-0.1.0/src/rtflite/strwidth.py +124 -0
  58. rtflite-0.1.0/tests/__init__.py +0 -0
  59. rtflite-0.1.0/tests/fixtures/README.md +16 -0
  60. rtflite-0.1.0/tests/fixtures/r_outputs/test_input_rtf_minimal.txt +44 -0
  61. rtflite-0.1.0/tests/fixtures/r_outputs/test_input_rtf_page_line.txt +1 -0
  62. rtflite-0.1.0/tests/fixtures/r_outputs/test_input_rtf_page_margin_line.txt +1 -0
  63. rtflite-0.1.0/tests/fixtures/r_outputs/test_input_rtf_title_line.txt +1 -0
  64. rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_bg.txt +1 -0
  65. rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_cell.txt +1 -0
  66. rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_fg.txt +1 -0
  67. rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_fg_bg.txt +1 -0
  68. rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_paragraph.txt +1 -0
  69. rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_row.txt +6 -0
  70. rtflite-0.1.0/tests/fixtures/run_r_tests.py +77 -0
  71. rtflite-0.1.0/tests/test_common.py +136 -0
  72. rtflite-0.1.0/tests/test_convert.py +209 -0
  73. rtflite-0.1.0/tests/test_input.py +75 -0
  74. rtflite-0.1.0/tests/test_row.py +202 -0
  75. rtflite-0.1.0/tests/test_strwidth.py +166 -0
  76. rtflite-0.1.0/tests/utils.py +27 -0
@@ -0,0 +1,56 @@
1
+ on:
2
+ push:
3
+ branches:
4
+ - main
5
+ pull_request:
6
+ branches:
7
+ - main
8
+
9
+ name: CI Tests
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
17
+ fail-fast: false
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+ - name: Install dependencies
26
+ run: |
27
+ # we are using the -e flag, so that code cov finds the source.
28
+ # this is not ideal, since installing an editable can technically
29
+ # differ from a normal install in surprising ways.
30
+ pip install -e '.[all]'
31
+ - name: Test with pytest
32
+ run: |
33
+ pip install pytest pytest-cov
34
+ pytest --cov=rtflite --cov-report=xml
35
+
36
+ # - name: Upload coverage reports to Codecov
37
+ # uses: codecov/codecov-action@v4
38
+ # with:
39
+ # name: "py${{ matrix.python-version }}"
40
+ # token: ${{ secrets.CODECOV_TOKEN }}
41
+
42
+ test-windows:
43
+ runs-on: windows-latest
44
+ steps:
45
+ - uses: actions/checkout@v4
46
+ - name: Set up Python
47
+ uses: actions/setup-python@v5
48
+ with:
49
+ python-version: "3.13"
50
+ - name: Install dependencies
51
+ run: |
52
+ pip install -e '.[all]'
53
+ - name: Test with pytest
54
+ run: |
55
+ pip install pytest pytest-cov
56
+ pytest --cov=rtflite --cov-report=xml
@@ -0,0 +1,42 @@
1
+ name: mkdocs
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ deploy:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - name: Configure Git Credentials
17
+ run: |
18
+ git config user.name github-actions[bot]
19
+ git config user.email 41898282+github-actions[bot]@users.noreply.github.com
20
+
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: 3.x
24
+ - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
25
+
26
+ - uses: actions/cache@v4
27
+ with:
28
+ key: mkdocs-material-${{ env.cache_id }}
29
+ path: .cache
30
+ restore-keys: |
31
+ mkdocs-material-
32
+
33
+ - name: Install dependencies
34
+ run: |
35
+ pip install mkdocs-material mkdocstrings-python
36
+ pip install pytest pytest-cov
37
+ pip install -e '.[all]'
38
+
39
+ - name: Generate coverage report and deploy mkdocs site
40
+ run: |
41
+ pytest --cov=rtflite --cov-report=html:docs/coverage/
42
+ mkdocs gh-deploy --force
@@ -0,0 +1,19 @@
1
+ # OS
2
+ .DS_Store
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[oc]
7
+ build/
8
+ dist/
9
+ wheels/
10
+ *.egg-info
11
+
12
+ # pytest
13
+ .coverage
14
+
15
+ # venv
16
+ .venv
17
+
18
+ # r2rtf
19
+ Rplots.pdf
@@ -0,0 +1 @@
1
+ 3.13.1
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## rtflite 0.1.0
4
+
5
+ ## New features
6
+
7
+ - Introduced core RTF document components, such as `RTFDocument`, `RTFPage`,
8
+ `RTFTitle`, `RTFColumnHeader`, and `RTFBody`. These classes establish the
9
+ foundation for composing structured RTF documents with a text encoding
10
+ pipeline. Use Pydantic for data validation.
11
+ - Implemented string width calculation using Pillow with metric-compatible fonts.
12
+ This will be incorporated in the pagination and layout algorithms in
13
+ future releases.
14
+ - Implemented a LibreOffice-based document converter for RTF to PDF conversion
15
+ with automatic LibreOffice detection mechanisms under Linux, macOS, and Windows.
16
+
17
+ ## Documentation
18
+
19
+ - Added an article on creating baseline characteristics tables.
20
+ - Integrated code coverage reports via pytest-cov into the documentation site.
rtflite-0.1.0/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2025 pharmaverse
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,24 @@
1
+ rtflite uses third-party Python packages which may be distributed under
2
+ different licenses. We have listed all of these third party packages and
3
+ their licenses below. However, the most up-to-date information can be found
4
+ via inspecting the dependencies field in the pyproject.toml file.
5
+
6
+ You must agree to the terms of these licenses, in addition to the rtflite
7
+ source code license, in order to use this software.
8
+
9
+ --------------------------------------------------
10
+ Third party Python packages listed by license type
11
+ [Format: Name - URL]
12
+ --------------------------------------------------
13
+
14
+ MIT License (https://opensource.org/license/mit)
15
+ * pydantic - https://github.com/pydantic/pydantic/blob/main/LICENSE
16
+
17
+ BSD 3-Clause License (https://opensource.org/license/bsd-3-clause)
18
+ * pandas - https://github.com/pandas-dev/pandas/blob/main/LICENSE
19
+
20
+ Modified BSD license (https://opensource.org/license/bsd-3-clause)
21
+ * numpy - https://github.com/numpy/numpy/blob/main/LICENSE.txt
22
+
23
+ MIT-CMU License (https://opensource.org/license/cmu-license)
24
+ * pillow - https://github.com/python-pillow/Pillow/blob/main/LICENSE
rtflite-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.3
2
+ Name: rtflite
3
+ Version: 0.1.0
4
+ Summary: Lightweight RTF composer for Python
5
+ Project-URL: Homepage, https://pharmaverse.github.io/rtflite/
6
+ Project-URL: Documentation, https://pharmaverse.github.io/rtflite/
7
+ Project-URL: Repository, https://github.com/pharmaverse/rtflite
8
+ Project-URL: Issues, https://github.com/pharmaverse/rtflite/issues
9
+ Project-URL: Changelog, https://github.com/pharmaverse/rtflite/blob/main/CHANGELOG.md
10
+ Author-email: Yilong Zhang <elong0527@gmail.com>, Nan Xiao <me@nanx.me>
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Healthcare Industry
14
+ Classifier: Intended Audience :: Information Technology
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Office/Business :: Office Suites
23
+ Classifier: Topic :: Text Processing
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: numpy>=2.0.0
26
+ Requires-Dist: pandas>=2.2.3
27
+ Requires-Dist: pillow>=11.0.0
28
+ Requires-Dist: pydantic>=2.9.2
29
+ Description-Content-Type: text/markdown
30
+
31
+ # rtflite <img src="docs/assets/logo.png" align="right" width="120" />
32
+
33
+ [![PyPI version](https://img.shields.io/pypi/v/rtflite)](https://pypi.org/project/rtflite/)
34
+ ![Python versions](https://img.shields.io/pypi/pyversions/rtflite)
35
+ [![CI Tests](https://github.com/pharmaverse/rtflite/actions/workflows/ci-tests.yml/badge.svg)](https://github.com/pharmaverse/rtflite/actions/workflows/ci-tests.yml)
36
+ [![mkdocs](https://github.com/pharmaverse/rtflite/actions/workflows/mkdocs.yml/badge.svg)](https://pharmaverse.github.io/rtflite/)
37
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/rtflite)](https://pypistats.org/packages/rtflite)
38
+ ![License](https://img.shields.io/pypi/l/rtflite)
39
+
40
+ Lightweight RTF composer for Python.
41
+
42
+ Specializes in precise formatting of production-quality tables and figures. Inspired by r2rtf.
43
+
44
+ ## Installation
45
+
46
+ You can install rtflite from PyPI:
47
+
48
+ ```bash
49
+ pip install rtflite
50
+ ```
51
+
52
+ Or install the development version from GitHub:
53
+
54
+ ```bash
55
+ git clone https://github.com/pharmaverse/rtflite.git
56
+ cd rtflite
57
+ python3 -m pip install -e .
58
+ ```
59
+
60
+ ## License
61
+
62
+ This project is licensed under the terms of the MIT license.
@@ -0,0 +1,32 @@
1
+ # rtflite <img src="docs/assets/logo.png" align="right" width="120" />
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/rtflite)](https://pypi.org/project/rtflite/)
4
+ ![Python versions](https://img.shields.io/pypi/pyversions/rtflite)
5
+ [![CI Tests](https://github.com/pharmaverse/rtflite/actions/workflows/ci-tests.yml/badge.svg)](https://github.com/pharmaverse/rtflite/actions/workflows/ci-tests.yml)
6
+ [![mkdocs](https://github.com/pharmaverse/rtflite/actions/workflows/mkdocs.yml/badge.svg)](https://pharmaverse.github.io/rtflite/)
7
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/rtflite)](https://pypistats.org/packages/rtflite)
8
+ ![License](https://img.shields.io/pypi/l/rtflite)
9
+
10
+ Lightweight RTF composer for Python.
11
+
12
+ Specializes in precise formatting of production-quality tables and figures. Inspired by r2rtf.
13
+
14
+ ## Installation
15
+
16
+ You can install rtflite from PyPI:
17
+
18
+ ```bash
19
+ pip install rtflite
20
+ ```
21
+
22
+ Or install the development version from GitHub:
23
+
24
+ ```bash
25
+ git clone https://github.com/pharmaverse/rtflite.git
26
+ cd rtflite
27
+ python3 -m pip install -e .
28
+ ```
29
+
30
+ ## License
31
+
32
+ This project is licensed under the terms of the MIT license.
@@ -0,0 +1,102 @@
1
+ # Baseline characteristics
2
+
3
+
4
+ <!-- `.md` and `.py` files are generated from the `.qmd` file. Please edit that file. -->
5
+
6
+ !!! tip
7
+
8
+ To run the code from this article as a Python script:
9
+
10
+ ```bash
11
+ python3 examples/example-baseline.py
12
+ ```
13
+
14
+ This article reproduces `vignettes/example-basechar.Rmd` in the r2rtf
15
+ package.
16
+
17
+ ## Imports
18
+
19
+ ``` python
20
+ from importlib.resources import files
21
+
22
+ import pandas as pd
23
+
24
+ import rtflite as rtf
25
+ ```
26
+
27
+ ## Ingest data
28
+
29
+ Load data from CSV file:
30
+
31
+ ``` python
32
+ data_path = files("rtflite.data").joinpath("baseline.csv")
33
+ df = pd.read_csv(data_path, na_filter=False)
34
+ print(df)
35
+ ```
36
+
37
+ var 1 1_pct 2 2_pct 3 3_pct 9999 9999_pct var_label
38
+ 0 Female 53 10.4 50 9.8 40 7.9 143 28.1 Gender
39
+ 1 Male 33 6.5 34 6.7 44 8.7 111 21.9 Gender
40
+ 2 <65 14 2.8 8 1.6 11 2.2 33 6.5 Age (Years)
41
+ 3 65-80 42 8.3 47 9.3 55 10.8 144 28.3 Age (Years)
42
+ 4 >80 30 5.9 29 5.7 18 3.5 77 15.2 Age (Years)
43
+ 5 Age (Years)
44
+ 6 Subjects with data 86 84 84 254 Age (Years)
45
+ 7 Mean 75.2 75.7 74.4 75.1 Age (Years)
46
+ 8 SD 8.6 8.3 7.9 8.2 Age (Years)
47
+ 9 Median 76.0 77.5 76.0 77.0 Age (Years)
48
+ 10 Range 52 to 89 51 to 88 56 to 88 51 to 89 Age (Years)
49
+ 11 White 78 15.4 78 15.4 74 14.6 230 45.3 Race
50
+ 12 Black 8 1.6 6 1.2 9 1.8 23 4.5 Race
51
+ 13 Other 0 0.0 0 0.0 1 0.2 1 0.2 Race
52
+
53
+ Create header data frames:
54
+
55
+ ``` python
56
+ header1 = pd.DataFrame([["", "Placebo", "Drug Low Dose", "Drug High Dose", "Total"]])
57
+ header2 = pd.DataFrame([["", "n", "(%)", "n", "(%)", "n", "(%)", "n", "(%)"]])
58
+ ```
59
+
60
+ ## Compose RTF
61
+
62
+ Create RTF document:
63
+
64
+ ``` python
65
+ doc = rtf.RTFDocument(
66
+ df=df,
67
+ rtf_title=rtf.RTFTitle(
68
+ text=["Demographic and Anthropometric Characteristics", "ITT Subjects"]
69
+ ),
70
+ rtf_column_header=[
71
+ rtf.RTFColumnHeader(df=header1, col_rel_width=[3] + [2] * 4),
72
+ rtf.RTFColumnHeader(
73
+ df=header2,
74
+ col_rel_width=[3] + [1.2, 0.8] * 4,
75
+ border_top=[""] + ["single"] * 8,
76
+ border_left=["single"] + ["single", ""] * 4,
77
+ ),
78
+ ],
79
+ rtf_body=rtf.RTFBody(
80
+ page_by=["var_label"],
81
+ col_rel_width=[3] + [1.2, 0.8] * 4 + [3],
82
+ text_justification=["l"] + ["c"] * 8 + ["l"],
83
+ text_format=[""] * 9 + ["b"],
84
+ border_left=["single"] + ["single", ""] * 4 + ["single"],
85
+ border_top=[""] * 9 + ["single"],
86
+ border_bottom=[""] * 9 + ["single"],
87
+ ),
88
+ )
89
+
90
+ doc.write_rtf("output.rtf")
91
+ ```
92
+
93
+ ## Convert to PDF
94
+
95
+ ``` python
96
+ converter = rtf.LibreOfficeConverter()
97
+ converter.convert(
98
+ input_files="output.rtf", output_dir=".", format="pdf", overwrite=True
99
+ )
100
+ ```
101
+
102
+ <embed src="../images/example-baseline/output.pdf" style="width:100%; height:400px" type="application/pdf">
@@ -0,0 +1,106 @@
1
+ <!-- `.md` and `.py` files are generated from the `.qmd` file. Please edit that file. -->
2
+
3
+ ---
4
+ title: "Baseline characteristics"
5
+ format: gfm
6
+ eval: false
7
+ ---
8
+
9
+ !!! tip
10
+
11
+ To run the code from this article as a Python script:
12
+
13
+ ```bash
14
+ python3 examples/example-baseline.py
15
+ ```
16
+
17
+ This article reproduces `vignettes/example-basechar.Rmd` in the r2rtf package.
18
+
19
+ ## Imports
20
+
21
+ ```{python}
22
+ from importlib.resources import files
23
+
24
+ import pandas as pd
25
+
26
+ import rtflite as rtf
27
+ ```
28
+
29
+ ## Ingest data
30
+
31
+ Load data from CSV file:
32
+
33
+ ```{python}
34
+ data_path = files("rtflite.data").joinpath("baseline.csv")
35
+ df = pd.read_csv(data_path, na_filter=False)
36
+ print(df)
37
+ ```
38
+
39
+ ```
40
+ var 1 1_pct 2 2_pct 3 3_pct 9999 9999_pct var_label
41
+ 0 Female 53 10.4 50 9.8 40 7.9 143 28.1 Gender
42
+ 1 Male 33 6.5 34 6.7 44 8.7 111 21.9 Gender
43
+ 2 <65 14 2.8 8 1.6 11 2.2 33 6.5 Age (Years)
44
+ 3 65-80 42 8.3 47 9.3 55 10.8 144 28.3 Age (Years)
45
+ 4 >80 30 5.9 29 5.7 18 3.5 77 15.2 Age (Years)
46
+ 5 Age (Years)
47
+ 6 Subjects with data 86 84 84 254 Age (Years)
48
+ 7 Mean 75.2 75.7 74.4 75.1 Age (Years)
49
+ 8 SD 8.6 8.3 7.9 8.2 Age (Years)
50
+ 9 Median 76.0 77.5 76.0 77.0 Age (Years)
51
+ 10 Range 52 to 89 51 to 88 56 to 88 51 to 89 Age (Years)
52
+ 11 White 78 15.4 78 15.4 74 14.6 230 45.3 Race
53
+ 12 Black 8 1.6 6 1.2 9 1.8 23 4.5 Race
54
+ 13 Other 0 0.0 0 0.0 1 0.2 1 0.2 Race
55
+ ```
56
+
57
+ Create header data frames:
58
+
59
+ ```{python}
60
+ header1 = pd.DataFrame([["", "Placebo", "Drug Low Dose", "Drug High Dose", "Total"]])
61
+ header2 = pd.DataFrame([["", "n", "(%)", "n", "(%)", "n", "(%)", "n", "(%)"]])
62
+ ```
63
+
64
+ ## Compose RTF
65
+
66
+ Create RTF document:
67
+
68
+ ```{python}
69
+ doc = rtf.RTFDocument(
70
+ df=df,
71
+ rtf_title=rtf.RTFTitle(
72
+ text=["Demographic and Anthropometric Characteristics", "ITT Subjects"]
73
+ ),
74
+ rtf_column_header=[
75
+ rtf.RTFColumnHeader(df=header1, col_rel_width=[3] + [2] * 4),
76
+ rtf.RTFColumnHeader(
77
+ df=header2,
78
+ col_rel_width=[3] + [1.2, 0.8] * 4,
79
+ border_top=[""] + ["single"] * 8,
80
+ border_left=["single"] + ["single", ""] * 4,
81
+ ),
82
+ ],
83
+ rtf_body=rtf.RTFBody(
84
+ page_by=["var_label"],
85
+ col_rel_width=[3] + [1.2, 0.8] * 4 + [3],
86
+ text_justification=["l"] + ["c"] * 8 + ["l"],
87
+ text_format=[""] * 9 + ["b"],
88
+ border_left=["single"] + ["single", ""] * 4 + ["single"],
89
+ border_top=[""] * 9 + ["single"],
90
+ border_bottom=[""] * 9 + ["single"],
91
+ ),
92
+ )
93
+
94
+ doc.write_rtf("output.rtf")
95
+ ```
96
+
97
+ ## Convert to PDF
98
+
99
+ ```{python}
100
+ converter = rtf.LibreOfficeConverter()
101
+ converter.convert(
102
+ input_files="output.rtf", output_dir=".", format="pdf", overwrite=True
103
+ )
104
+ ```
105
+
106
+ <embed src="../images/example-baseline/output.pdf" style="width:100%; height:400px" type="application/pdf">
Binary file
Binary file
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## rtflite 0.1.0
4
+
5
+ ## New features
6
+
7
+ - Introduced core RTF document components, such as `RTFDocument`, `RTFPage`,
8
+ `RTFTitle`, `RTFColumnHeader`, and `RTFBody`. These classes establish the
9
+ foundation for composing structured RTF documents with a text encoding
10
+ pipeline. Use Pydantic for data validation.
11
+ - Implemented string width calculation using Pillow with metric-compatible fonts.
12
+ This will be incorporated in the pagination and layout algorithms in
13
+ future releases.
14
+ - Implemented a LibreOffice-based document converter for RTF to PDF conversion
15
+ with automatic LibreOffice detection mechanisms under Linux, macOS, and Windows.
16
+
17
+ ## Documentation
18
+
19
+ - Added an article on creating baseline characteristics tables.
20
+ - Integrated code coverage reports via pytest-cov into the documentation site.
@@ -0,0 +1,32 @@
1
+ # rtflite <img src="assets/logo.png" align="right" width="120" />
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/rtflite)](https://pypi.org/project/rtflite/)
4
+ ![Python versions](https://img.shields.io/pypi/pyversions/rtflite)
5
+ [![CI Tests](https://github.com/pharmaverse/rtflite/actions/workflows/ci-tests.yml/badge.svg)](https://github.com/pharmaverse/rtflite/actions/workflows/ci-tests.yml)
6
+ [![mkdocs](https://github.com/pharmaverse/rtflite/actions/workflows/mkdocs.yml/badge.svg)](https://pharmaverse.github.io/rtflite/)
7
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/rtflite)](https://pypistats.org/packages/rtflite)
8
+ ![License](https://img.shields.io/pypi/l/rtflite)
9
+
10
+ Lightweight RTF composer for Python.
11
+
12
+ Specializes in precise formatting of production-quality tables and figures. Inspired by r2rtf.
13
+
14
+ ## Installation
15
+
16
+ You can install rtflite from PyPI:
17
+
18
+ ```bash
19
+ pip install rtflite
20
+ ```
21
+
22
+ Or install the development version from GitHub:
23
+
24
+ ```bash
25
+ git clone https://github.com/pharmaverse/rtflite.git
26
+ cd rtflite
27
+ python3 -m pip install -e .
28
+ ```
29
+
30
+ ## License
31
+
32
+ This project is licensed under the terms of the MIT license.
@@ -0,0 +1,6 @@
1
+ // Scroll to the top after the page has loaded to prevent jumping to the embed element
2
+ document.addEventListener("DOMContentLoaded", function () {
3
+ setTimeout(function () {
4
+ window.scrollTo(0, 0);
5
+ }, 250);
6
+ });
@@ -0,0 +1,8 @@
1
+ # Convert
2
+
3
+ ::: rtflite.convert
4
+ options:
5
+ members:
6
+ - LibreOfficeConverter
7
+ show_root_heading: true
8
+ show_source: false
@@ -0,0 +1,8 @@
1
+ # Encode
2
+
3
+ ::: rtflite.encode
4
+ options:
5
+ members:
6
+ - RTFDocument
7
+ show_root_heading: true
8
+ show_source: false
@@ -0,0 +1,14 @@
1
+ # Input
2
+
3
+ ::: rtflite.input
4
+ options:
5
+ members:
6
+ - TextAttributes
7
+ - TableAttributes
8
+ - BroadcastValue
9
+ - RTFPage
10
+ - RTFTitle
11
+ - RTFColumnHeader
12
+ - RTFBody
13
+ show_root_heading: true
14
+ show_source: false
@@ -0,0 +1,11 @@
1
+ # Row
2
+
3
+ ::: rtflite.row
4
+ options:
5
+ members:
6
+ - TextContent
7
+ - Border
8
+ - Cell
9
+ - Row
10
+ show_root_heading: true
11
+ show_source: false
@@ -0,0 +1,8 @@
1
+ # String width
2
+
3
+ ::: rtflite.strwidth
4
+ options:
5
+ members:
6
+ - get_string_width
7
+ show_root_heading: true
8
+ show_source: false
@@ -0,0 +1,3 @@
1
+ <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
2
+ <text x="50%" y="50%" font-family="Playwrite NO Guides" font-size="32" fill="#415A77" text-anchor="middle" dominant-baseline="middle">rtflite</text>
3
+ </svg>
@@ -0,0 +1,17 @@
1
+ hexSticker::sticker(
2
+ subplot = ~ plot.new(),
3
+ s_x = 1,
4
+ s_y = 1,
5
+ s_width = 0.1,
6
+ s_height = 0.1,
7
+ package = "",
8
+ p_x = 1,
9
+ p_y = 1,
10
+ p_size = 32,
11
+ h_size = 1.2,
12
+ p_color = "#415A77",
13
+ h_fill = "#FFF9F2",
14
+ h_color = "#415A77",
15
+ dpi = 320,
16
+ filename = "docs/assets/logo.png"
17
+ )