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.
- rtflite-0.1.0/.github/workflows/ci-tests.yml +56 -0
- rtflite-0.1.0/.github/workflows/mkdocs.yml +42 -0
- rtflite-0.1.0/.gitignore +19 -0
- rtflite-0.1.0/.python-version +1 -0
- rtflite-0.1.0/CHANGELOG.md +20 -0
- rtflite-0.1.0/LICENSE +20 -0
- rtflite-0.1.0/LICENSES_THIRD_PARTY +24 -0
- rtflite-0.1.0/PKG-INFO +62 -0
- rtflite-0.1.0/README.md +32 -0
- rtflite-0.1.0/docs/articles/example-baseline.md +102 -0
- rtflite-0.1.0/docs/articles/example-baseline.qmd +106 -0
- rtflite-0.1.0/docs/articles/images/example-baseline/output.pdf +0 -0
- rtflite-0.1.0/docs/assets/IBMPlexMono-Text.woff2 +0 -0
- rtflite-0.1.0/docs/assets/IBMPlexMono-TextItalic.woff2 +0 -0
- rtflite-0.1.0/docs/assets/favicon.png +0 -0
- rtflite-0.1.0/docs/assets/logo.png +0 -0
- rtflite-0.1.0/docs/changelog.md +20 -0
- rtflite-0.1.0/docs/index.md +32 -0
- rtflite-0.1.0/docs/javascripts/fix-embed-focus.js +6 -0
- rtflite-0.1.0/docs/reference/convert.md +8 -0
- rtflite-0.1.0/docs/reference/encode.md +8 -0
- rtflite-0.1.0/docs/reference/input.md +14 -0
- rtflite-0.1.0/docs/reference/row.md +11 -0
- rtflite-0.1.0/docs/reference/strwidth.md +8 -0
- rtflite-0.1.0/docs/scripts/logo-text.svg +3 -0
- rtflite-0.1.0/docs/scripts/logo.R +17 -0
- rtflite-0.1.0/docs/scripts/logo.sh +53 -0
- rtflite-0.1.0/docs/scripts/sync.sh +40 -0
- rtflite-0.1.0/docs/stylesheets/extra.css +73 -0
- rtflite-0.1.0/examples/example-baseline.py +44 -0
- rtflite-0.1.0/mkdocs.yml +86 -0
- rtflite-0.1.0/pyproject.toml +69 -0
- rtflite-0.1.0/requirements-dev.lock +377 -0
- rtflite-0.1.0/requirements.lock +36 -0
- rtflite-0.1.0/scripts/download_fonts.sh +22 -0
- rtflite-0.1.0/scripts/update_color_table.R +33 -0
- rtflite-0.1.0/scripts/update_unicode_latex.py +94 -0
- rtflite-0.1.0/src/rtflite/__init__.py +3 -0
- rtflite-0.1.0/src/rtflite/convert.py +143 -0
- rtflite-0.1.0/src/rtflite/data/__init__.py +0 -0
- rtflite-0.1.0/src/rtflite/data/baseline.csv +15 -0
- rtflite-0.1.0/src/rtflite/dictionary/__init__.py +0 -0
- rtflite-0.1.0/src/rtflite/dictionary/color_table.py +667 -0
- rtflite-0.1.0/src/rtflite/dictionary/libreoffice.py +23 -0
- rtflite-0.1.0/src/rtflite/dictionary/unicode_latex.py +692 -0
- rtflite-0.1.0/src/rtflite/encode.py +369 -0
- rtflite-0.1.0/src/rtflite/fonts/README.md +24 -0
- rtflite-0.1.0/src/rtflite/fonts/__init__.py +0 -0
- rtflite-0.1.0/src/rtflite/fonts/cros/Caladea-Regular.ttf +0 -0
- rtflite-0.1.0/src/rtflite/fonts/cros/Carlito-Regular.ttf +0 -0
- rtflite-0.1.0/src/rtflite/fonts/cros/Gelasio-Regular.ttf +0 -0
- rtflite-0.1.0/src/rtflite/fonts/liberation/LiberationMono-Regular.ttf +0 -0
- rtflite-0.1.0/src/rtflite/fonts/liberation/LiberationSans-Regular.ttf +0 -0
- rtflite-0.1.0/src/rtflite/fonts/liberation/LiberationSerif-Regular.ttf +0 -0
- rtflite-0.1.0/src/rtflite/input.py +742 -0
- rtflite-0.1.0/src/rtflite/row.py +347 -0
- rtflite-0.1.0/src/rtflite/strwidth.py +124 -0
- rtflite-0.1.0/tests/__init__.py +0 -0
- rtflite-0.1.0/tests/fixtures/README.md +16 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_input_rtf_minimal.txt +44 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_input_rtf_page_line.txt +1 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_input_rtf_page_margin_line.txt +1 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_input_rtf_title_line.txt +1 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_bg.txt +1 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_cell.txt +1 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_fg.txt +1 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_fg_bg.txt +1 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_paragraph.txt +1 -0
- rtflite-0.1.0/tests/fixtures/r_outputs/test_row_rtf_row.txt +6 -0
- rtflite-0.1.0/tests/fixtures/run_r_tests.py +77 -0
- rtflite-0.1.0/tests/test_common.py +136 -0
- rtflite-0.1.0/tests/test_convert.py +209 -0
- rtflite-0.1.0/tests/test_input.py +75 -0
- rtflite-0.1.0/tests/test_row.py +202 -0
- rtflite-0.1.0/tests/test_strwidth.py +166 -0
- 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
|
rtflite-0.1.0/.gitignore
ADDED
|
@@ -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
|
+
[](https://pypi.org/project/rtflite/)
|
|
34
|
+

|
|
35
|
+
[](https://github.com/pharmaverse/rtflite/actions/workflows/ci-tests.yml)
|
|
36
|
+
[](https://pharmaverse.github.io/rtflite/)
|
|
37
|
+
[](https://pypistats.org/packages/rtflite)
|
|
38
|
+

|
|
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.
|
rtflite-0.1.0/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# rtflite <img src="docs/assets/logo.png" align="right" width="120" />
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/rtflite/)
|
|
4
|
+

|
|
5
|
+
[](https://github.com/pharmaverse/rtflite/actions/workflows/ci-tests.yml)
|
|
6
|
+
[](https://pharmaverse.github.io/rtflite/)
|
|
7
|
+
[](https://pypistats.org/packages/rtflite)
|
|
8
|
+

|
|
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
|
|
Binary file
|
|
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
|
+
[](https://pypi.org/project/rtflite/)
|
|
4
|
+

|
|
5
|
+
[](https://github.com/pharmaverse/rtflite/actions/workflows/ci-tests.yml)
|
|
6
|
+
[](https://pharmaverse.github.io/rtflite/)
|
|
7
|
+
[](https://pypistats.org/packages/rtflite)
|
|
8
|
+

|
|
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,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
|
+
)
|