charite-plot 0.1.1__tar.gz → 0.3.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.
- charite_plot-0.3.0/CHANGELOG.md +54 -0
- charite_plot-0.3.0/CITATION.cff +19 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/LICENSE.md +4 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/PKG-INFO +44 -10
- {charite_plot-0.1.1 → charite_plot-0.3.0}/README.md +39 -9
- {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/__init__.py +17 -8
- charite_plot-0.3.0/charite_plot/_theme_common.py +57 -0
- charite_plot-0.3.0/charite_plot/altair_themes.py +227 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/fonts.py +2 -0
- charite_plot-0.3.0/charite_plot/mpl_themes.py +215 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/palettes.py +2 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/altair.md +14 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/altair_themes.md +1 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/mpl_themes.md +1 -1
- charite_plot-0.3.0/docs/assets/theme_example.png +0 -0
- charite_plot-0.3.0/docs/citing.md +20 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/index.md +5 -5
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/installation.md +2 -2
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/matplotlib.md +25 -10
- {charite_plot-0.1.1 → charite_plot-0.3.0}/examples/mpl_showcase.py +5 -3
- charite_plot-0.3.0/examples/palette_preview.py +61 -0
- charite_plot-0.3.0/examples/poly_showcase.py +107 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/mkdocs.yml +1 -0
- charite_plot-0.1.1/CHANGELOG.md +0 -27
- charite_plot-0.1.1/charite_plot/altair_themes.py +0 -163
- charite_plot-0.1.1/charite_plot/mpl_themes.py +0 -129
- charite_plot-0.1.1/docs/assets/theme_example.png +0 -0
- charite_plot-0.1.1/examples/palette_preview.py +0 -47
- charite_plot-0.1.1/examples/poly_showcase.py +0 -108
- {charite_plot-0.1.1 → charite_plot-0.3.0}/.github/workflows/ci.yml +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/.gitignore +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/colors.py +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/py.typed +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/colors.md +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/fonts.md +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/palettes.md +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/assets/palette_preview.png +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/colors.md +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/palettes.md +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/stylesheets/extra.css +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/examples/altair_showcase.py +0 -0
- {charite_plot-0.1.1 → charite_plot-0.3.0}/pyproject.toml +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.3.0] - 2026-07-18
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `theme_charite` (matplotlib) gained a `background` parameter (sets figure and axes facecolor).
|
|
13
|
+
- Altair now provides a `using()` context manager mirroring the matplotlib one, for scoping the theme to a `with` block.
|
|
14
|
+
- Explicit `__all__` declarations on every module (and the package) to define the public API surface for `from charite_plot import *` and tooling.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **Unified API across backends.** The matplotlib activate function was renamed `apply_theme(params)` → `enable(**kwargs)`, and `using()` now takes theme keyword arguments instead of a pre-built dict — matching the Altair backend. Migrate `apply_theme(theme_charite(palette="x"))` to `enable(palette="x")` and `using(theme_charite(palette="x"))` to `using(palette="x")`. `theme_charite()` still returns a plain dict if you prefer to apply it manually via `mpl.rcParams.update()`.
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
|
|
22
|
+
- `mpl_themes.apply_theme()` — replaced by `mpl_themes.enable()` (see above).
|
|
23
|
+
|
|
24
|
+
## [0.2.0] - 2026-07-01
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `theme_charite` (matplotlib) gained `interactive` and `tiny_margins` parameters.
|
|
29
|
+
- `theme_charite` (Altair) gained `thickness` and `tiny_margins` parameters, bringing it to parity with the matplotlib backend.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- Font-size ramp is now shared between both backends: labels scale at 1× and legend text at 0.8× the base size. Altair legend labels are slightly smaller and axis labels slightly larger as a result.
|
|
34
|
+
|
|
35
|
+
## [0.1.1] - 2026-06-13
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- README images now use absolute raw GitHub URLs so they render correctly on PyPI.
|
|
40
|
+
- Corrected PyPI project URLs (homepage, docs, repository, bug tracker).
|
|
41
|
+
|
|
42
|
+
## [0.1.0] - 2026-06-12
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- Initial release.
|
|
47
|
+
- Matplotlib theme (`mpl_themes.theme_charite`) with `apply_theme()` and `using()` context manager.
|
|
48
|
+
- Altair/Vega-Lite theme (`altair_themes.theme_charite`) with `register()` and `enable()`.
|
|
49
|
+
- 10 built-in colour palettes: `primary`, `secondary`, `mono`, `light`, `versus`, `nineties`, `brickhouse`, `sunrise`, `berryseason`, `goldelse`.
|
|
50
|
+
- 27 Charité corporate identity colour constants in `colors.py`.
|
|
51
|
+
- `make_palette()` for subsampling and interpolating palettes.
|
|
52
|
+
- Font fallback chain: Charité Text Office → Charit? Text Office → Calibri → DejaVu Sans → sans-serif.
|
|
53
|
+
- MkDocs Material documentation with API reference.
|
|
54
|
+
- MIT License.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it as below."
|
|
3
|
+
type: software
|
|
4
|
+
title: "charite-plot: Matplotlib and Altair Themes for Charité – Universitätsmedizin Berlin"
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: Ramezani
|
|
7
|
+
given-names: Pedram
|
|
8
|
+
email: pedram.ramezani@charite.de
|
|
9
|
+
version: 0.3.0
|
|
10
|
+
date-released: 2026-07-01
|
|
11
|
+
license: MIT
|
|
12
|
+
url: "https://github.com/pedramezani/charite-plot"
|
|
13
|
+
repository-code: "https://github.com/pedramezani/charite-plot"
|
|
14
|
+
keywords:
|
|
15
|
+
- matplotlib
|
|
16
|
+
- altair
|
|
17
|
+
- theme
|
|
18
|
+
- visualization
|
|
19
|
+
- charite
|
|
@@ -7,3 +7,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
|
7
7
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
8
|
|
|
9
9
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
This package is based on the original `charite` R package developed by Johannes Julius Mohn (https://github.com/johannesjuliusm/charite), which is also distributed under the MIT License.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: charite-plot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Matplotlib and Altair themes for Charité – Universitätsmedizin Berlin
|
|
5
5
|
Project-URL: Homepage, https://github.com/pedramezani/charite-plot
|
|
6
6
|
Project-URL: Documentation, https://pedramezani.github.io/charite-plot
|
|
@@ -17,6 +17,10 @@ License: # MIT License
|
|
|
17
17
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
18
18
|
|
|
19
19
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
This package is based on the original `charite` R package developed by Johannes Julius Mohn (https://github.com/johannesjuliusm/charite), which is also distributed under the MIT License.
|
|
20
24
|
License-File: LICENSE.md
|
|
21
25
|
Keywords: altair,charite,matplotlib,theme,visualization
|
|
22
26
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -49,6 +53,13 @@ Description-Content-Type: text/markdown
|
|
|
49
53
|
|
|
50
54
|
# charite-plot
|
|
51
55
|
|
|
56
|
+

|
|
57
|
+

|
|
58
|
+

|
|
59
|
+

|
|
60
|
+

|
|
61
|
+

|
|
62
|
+
|
|
52
63
|
A Python package with a Charité-styled Matplotlib theme, [visual identity](https://marke.charite.de/d/Y3FxSwD6Tz3a) colour palettes, and an Altair theme — ported from the [`charite` R package](https://github.com/johannesjuliusm/charite).
|
|
53
64
|
|
|
54
65
|
## Installation
|
|
@@ -78,9 +89,9 @@ Preview the available colour palettes.
|
|
|
78
89
|
|
|
79
90
|
```python
|
|
80
91
|
import matplotlib.pyplot as plt
|
|
81
|
-
from charite_plot.mpl_themes import
|
|
92
|
+
from charite_plot.mpl_themes import enable
|
|
82
93
|
|
|
83
|
-
|
|
94
|
+
enable()
|
|
84
95
|
|
|
85
96
|
fig, ax = plt.subplots()
|
|
86
97
|
ax.plot([1, 2, 3], [4, 7, 3])
|
|
@@ -91,9 +102,9 @@ plt.show()
|
|
|
91
102
|
Use as a context manager to scope the theme to a single figure:
|
|
92
103
|
|
|
93
104
|
```python
|
|
94
|
-
from charite_plot.mpl_themes import
|
|
105
|
+
from charite_plot.mpl_themes import using
|
|
95
106
|
|
|
96
|
-
with using(
|
|
107
|
+
with using(palette="goldelse"):
|
|
97
108
|
fig, ax = plt.subplots()
|
|
98
109
|
ax.bar(["A", "B", "C"], [3, 7, 5])
|
|
99
110
|
```
|
|
@@ -119,11 +130,13 @@ enable(palette="berryseason", font_size=13)
|
|
|
119
130
|
|
|
120
131
|
| Symbol | Description |
|
|
121
132
|
|--------|-------------|
|
|
122
|
-
| `mpl_themes.theme_charite()` | Returns a matplotlib rcParams dict for the Charité theme |
|
|
123
|
-
| `mpl_themes.
|
|
124
|
-
| `mpl_themes.using(
|
|
125
|
-
| `altair_themes.theme_charite()` | Returns a Vega-Lite config dict for the Charité theme |
|
|
133
|
+
| `mpl_themes.theme_charite(**kwargs)` | Returns a matplotlib rcParams dict for the Charité theme |
|
|
134
|
+
| `mpl_themes.enable(**kwargs)` | Applies the theme permanently to `rcParams` |
|
|
135
|
+
| `mpl_themes.using(**kwargs)` | Context manager: applies the theme temporarily |
|
|
136
|
+
| `altair_themes.theme_charite(**kwargs)` | Returns a Vega-Lite config dict for the Charité theme |
|
|
126
137
|
| `altair_themes.enable(**kwargs)` | Registers and enables the theme in Altair |
|
|
138
|
+
| `altair_themes.using(**kwargs)` | Context manager: enables the theme temporarily |
|
|
139
|
+
| `altair_themes.register()` | Registers the theme without enabling it (Altair-only) |
|
|
127
140
|
| `PALETTES` | Dict of 10 named colour palettes |
|
|
128
141
|
| `make_palette(name, n, reverse)` | Subsample or interpolate any palette |
|
|
129
142
|
| `CHARITE_COLORS` | Dict of all 27 hex colour constants |
|
|
@@ -137,9 +150,30 @@ The fallback chain follows the official Charité brand guidelines:
|
|
|
137
150
|
`DejaVu Sans` ships with Matplotlib and is always available as the penultimate fallback; `sans-serif` lets the browser or system choose if nothing else matches (important for Altair/Vega-Lite). To override the preferred font:
|
|
138
151
|
|
|
139
152
|
```python
|
|
140
|
-
|
|
153
|
+
enable(font="Arial")
|
|
141
154
|
```
|
|
142
155
|
|
|
156
|
+
## How to cite
|
|
157
|
+
|
|
158
|
+
If you use charite-plot in your work, please cite it as:
|
|
159
|
+
|
|
160
|
+
```bibtex
|
|
161
|
+
@software{ramezani2026chariteplot,
|
|
162
|
+
author = {Ramezani, Pedram},
|
|
163
|
+
title = {charite-plot: Matplotlib and Altair Themes for Charité – Universitätsmedizin Berlin},
|
|
164
|
+
year = {2026},
|
|
165
|
+
version = {0.3.0},
|
|
166
|
+
url = {https://github.com/pedramezani/charite-plot},
|
|
167
|
+
license = {MIT},
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Acknowledgements
|
|
172
|
+
|
|
173
|
+
This package is based on the original [`charite` R package](https://github.com/johannesjuliusm/charite) developed by Johannes Julius Mohn.
|
|
174
|
+
|
|
143
175
|
## License
|
|
144
176
|
|
|
145
177
|
MIT © 2026 Pedram Ramezani
|
|
178
|
+
|
|
179
|
+
The original `charite` R package by Johannes Julius Mohn is likewise MIT licensed.
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# charite-plot
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
3
10
|
A Python package with a Charité-styled Matplotlib theme, [visual identity](https://marke.charite.de/d/Y3FxSwD6Tz3a) colour palettes, and an Altair theme — ported from the [`charite` R package](https://github.com/johannesjuliusm/charite).
|
|
4
11
|
|
|
5
12
|
## Installation
|
|
@@ -29,9 +36,9 @@ Preview the available colour palettes.
|
|
|
29
36
|
|
|
30
37
|
```python
|
|
31
38
|
import matplotlib.pyplot as plt
|
|
32
|
-
from charite_plot.mpl_themes import
|
|
39
|
+
from charite_plot.mpl_themes import enable
|
|
33
40
|
|
|
34
|
-
|
|
41
|
+
enable()
|
|
35
42
|
|
|
36
43
|
fig, ax = plt.subplots()
|
|
37
44
|
ax.plot([1, 2, 3], [4, 7, 3])
|
|
@@ -42,9 +49,9 @@ plt.show()
|
|
|
42
49
|
Use as a context manager to scope the theme to a single figure:
|
|
43
50
|
|
|
44
51
|
```python
|
|
45
|
-
from charite_plot.mpl_themes import
|
|
52
|
+
from charite_plot.mpl_themes import using
|
|
46
53
|
|
|
47
|
-
with using(
|
|
54
|
+
with using(palette="goldelse"):
|
|
48
55
|
fig, ax = plt.subplots()
|
|
49
56
|
ax.bar(["A", "B", "C"], [3, 7, 5])
|
|
50
57
|
```
|
|
@@ -70,11 +77,13 @@ enable(palette="berryseason", font_size=13)
|
|
|
70
77
|
|
|
71
78
|
| Symbol | Description |
|
|
72
79
|
|--------|-------------|
|
|
73
|
-
| `mpl_themes.theme_charite()` | Returns a matplotlib rcParams dict for the Charité theme |
|
|
74
|
-
| `mpl_themes.
|
|
75
|
-
| `mpl_themes.using(
|
|
76
|
-
| `altair_themes.theme_charite()` | Returns a Vega-Lite config dict for the Charité theme |
|
|
80
|
+
| `mpl_themes.theme_charite(**kwargs)` | Returns a matplotlib rcParams dict for the Charité theme |
|
|
81
|
+
| `mpl_themes.enable(**kwargs)` | Applies the theme permanently to `rcParams` |
|
|
82
|
+
| `mpl_themes.using(**kwargs)` | Context manager: applies the theme temporarily |
|
|
83
|
+
| `altair_themes.theme_charite(**kwargs)` | Returns a Vega-Lite config dict for the Charité theme |
|
|
77
84
|
| `altair_themes.enable(**kwargs)` | Registers and enables the theme in Altair |
|
|
85
|
+
| `altair_themes.using(**kwargs)` | Context manager: enables the theme temporarily |
|
|
86
|
+
| `altair_themes.register()` | Registers the theme without enabling it (Altair-only) |
|
|
78
87
|
| `PALETTES` | Dict of 10 named colour palettes |
|
|
79
88
|
| `make_palette(name, n, reverse)` | Subsample or interpolate any palette |
|
|
80
89
|
| `CHARITE_COLORS` | Dict of all 27 hex colour constants |
|
|
@@ -88,9 +97,30 @@ The fallback chain follows the official Charité brand guidelines:
|
|
|
88
97
|
`DejaVu Sans` ships with Matplotlib and is always available as the penultimate fallback; `sans-serif` lets the browser or system choose if nothing else matches (important for Altair/Vega-Lite). To override the preferred font:
|
|
89
98
|
|
|
90
99
|
```python
|
|
91
|
-
|
|
100
|
+
enable(font="Arial")
|
|
92
101
|
```
|
|
93
102
|
|
|
103
|
+
## How to cite
|
|
104
|
+
|
|
105
|
+
If you use charite-plot in your work, please cite it as:
|
|
106
|
+
|
|
107
|
+
```bibtex
|
|
108
|
+
@software{ramezani2026chariteplot,
|
|
109
|
+
author = {Ramezani, Pedram},
|
|
110
|
+
title = {charite-plot: Matplotlib and Altair Themes for Charité – Universitätsmedizin Berlin},
|
|
111
|
+
year = {2026},
|
|
112
|
+
version = {0.3.0},
|
|
113
|
+
url = {https://github.com/pedramezani/charite-plot},
|
|
114
|
+
license = {MIT},
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Acknowledgements
|
|
119
|
+
|
|
120
|
+
This package is based on the original [`charite` R package](https://github.com/johannesjuliusm/charite) developed by Johannes Julius Mohn.
|
|
121
|
+
|
|
94
122
|
## License
|
|
95
123
|
|
|
96
124
|
MIT © 2026 Pedram Ramezani
|
|
125
|
+
|
|
126
|
+
The original `charite` R package by Johannes Julius Mohn is likewise MIT licensed.
|
|
@@ -5,12 +5,12 @@ Quick start
|
|
|
5
5
|
Matplotlib::
|
|
6
6
|
|
|
7
7
|
import matplotlib.pyplot as plt
|
|
8
|
-
from charite_plot.mpl_themes import
|
|
8
|
+
from charite_plot.mpl_themes import enable
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
enable() # permanent
|
|
11
11
|
# or temporarily:
|
|
12
12
|
from charite_plot.mpl_themes import using
|
|
13
|
-
with using(
|
|
13
|
+
with using(palette="goldelse"):
|
|
14
14
|
fig, ax = plt.subplots()
|
|
15
15
|
ax.plot([1, 2, 3])
|
|
16
16
|
|
|
@@ -21,10 +21,19 @@ Altair::
|
|
|
21
21
|
# charts rendered after this call use the theme automatically
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
from .colors import * # noqa:
|
|
25
|
-
from .
|
|
26
|
-
from . import
|
|
27
|
-
from . import
|
|
24
|
+
from .colors import * # noqa: F403 (all color constants + CHARITE_COLORS)
|
|
25
|
+
from .colors import __all__ as _COLOR_ALL
|
|
26
|
+
from .palettes import PALETTES, make_palette
|
|
27
|
+
from . import mpl_themes
|
|
28
|
+
from . import altair_themes
|
|
28
29
|
|
|
29
|
-
__version__ = "0.
|
|
30
|
+
__version__ = "0.3.0"
|
|
30
31
|
__author__ = "Pedram Ramezani"
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
*_COLOR_ALL,
|
|
35
|
+
"PALETTES",
|
|
36
|
+
"make_palette",
|
|
37
|
+
"mpl_themes",
|
|
38
|
+
"altair_themes",
|
|
39
|
+
]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Shared theme primitives for the matplotlib and Altair backends.
|
|
2
|
+
|
|
3
|
+
These small ``NamedTuple`` structures keep the per-backend theme builders
|
|
4
|
+
readable by giving names to the derived size/margin values. The font-size
|
|
5
|
+
ratios are shared so both backends scale identically from their base size
|
|
6
|
+
(matplotlib works in points, Altair in pixels, but the ratios are the same).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import NamedTuple
|
|
10
|
+
|
|
11
|
+
__all__ = ["FontSizes", "Margins", "Thickness", "resolve_font_sizes"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FontSizes(NamedTuple):
|
|
15
|
+
"""Derived font sizes, all scaled from the base ``font_size``."""
|
|
16
|
+
title: float
|
|
17
|
+
subtitle: float
|
|
18
|
+
label: float
|
|
19
|
+
legend: float
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Margins(NamedTuple):
|
|
23
|
+
"""Derived margins/paddings around the plot panel.
|
|
24
|
+
|
|
25
|
+
``wspace`` / ``hspace`` are subplot-spacing fractions used only by the
|
|
26
|
+
matplotlib backend; they default to ``0`` so the Altair backend can build
|
|
27
|
+
a ``Margins`` without supplying them.
|
|
28
|
+
"""
|
|
29
|
+
title: float
|
|
30
|
+
label: float
|
|
31
|
+
legend: float
|
|
32
|
+
wspace: float = 0.0
|
|
33
|
+
hspace: float = 0.0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Thickness(NamedTuple):
|
|
37
|
+
"""Derived line widths, scaled from the base ``thickness``.
|
|
38
|
+
|
|
39
|
+
``lines`` / ``patches`` are matplotlib-specific defaults; they carry
|
|
40
|
+
defaults so the Altair backend can build a ``Thickness`` from just the
|
|
41
|
+
axis-related widths.
|
|
42
|
+
"""
|
|
43
|
+
axes: float
|
|
44
|
+
grid: float
|
|
45
|
+
ticks: float
|
|
46
|
+
lines: float = 1.5
|
|
47
|
+
patches: float = 0.0
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def resolve_font_sizes(font_size: float) -> FontSizes:
|
|
51
|
+
"""Return the standard Charité font-size ramp derived from *font_size*."""
|
|
52
|
+
return FontSizes(
|
|
53
|
+
title=round(font_size * 1.2),
|
|
54
|
+
subtitle=font_size,
|
|
55
|
+
label=font_size,
|
|
56
|
+
legend=round(font_size * 0.8),
|
|
57
|
+
)
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""Altair / Vega-Lite theme for Charité – Universitätsmedizin Berlin.
|
|
2
|
+
|
|
3
|
+
Register and enable with::
|
|
4
|
+
|
|
5
|
+
from charite_plot.altair_themes import enable
|
|
6
|
+
enable() # default params
|
|
7
|
+
enable(palette="goldelse") # custom palette
|
|
8
|
+
enable(font="Arial", font_size=13) # font override
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from contextlib import contextmanager
|
|
14
|
+
from uuid import uuid4
|
|
15
|
+
|
|
16
|
+
from .colors import (
|
|
17
|
+
BLACK, WHITE, TEXT_GREY, PRIME_BLUE, PRIME_LGREY,
|
|
18
|
+
SECOND_DBLUE, KORALL,
|
|
19
|
+
)
|
|
20
|
+
from .palettes import PALETTES
|
|
21
|
+
from .fonts import build_font_stack
|
|
22
|
+
from ._theme_common import Margins, Thickness, resolve_font_sizes
|
|
23
|
+
|
|
24
|
+
from typing import TYPE_CHECKING
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from altair.theme import AxisConfigKwds, ThemeConfig
|
|
28
|
+
|
|
29
|
+
__all__ = ["theme_charite", "enable", "using", "register"]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _css_font_stack(preferred: str | None) -> str:
|
|
33
|
+
"""Return a CSS font-family string (comma-separated, quoted if needed)."""
|
|
34
|
+
def _quote(name: str) -> str:
|
|
35
|
+
return f'"{name}"' if " " in name else name
|
|
36
|
+
|
|
37
|
+
return ", ".join(_quote(f) for f in build_font_stack(preferred=preferred))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def theme_charite(
|
|
41
|
+
font: str | None = None,
|
|
42
|
+
font_size: int = 12,
|
|
43
|
+
thickness: float = 0.5,
|
|
44
|
+
grid: bool = False,
|
|
45
|
+
palette: str | list[str] = "primary",
|
|
46
|
+
background: str = "white",
|
|
47
|
+
tiny_margins: bool = False,
|
|
48
|
+
) -> ThemeConfig:
|
|
49
|
+
"""Return an Altair theme config dict for the Charité corporate theme.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
font:
|
|
54
|
+
Preferred font. Falls back through Charité Text Office → Charit? Text Office → Calibri → DejaVu Sans → sans-serif.
|
|
55
|
+
font_size:
|
|
56
|
+
Base font size in pixels.
|
|
57
|
+
thickness:
|
|
58
|
+
Axis line and tick width.
|
|
59
|
+
grid:
|
|
60
|
+
Show axis grid lines.
|
|
61
|
+
palette:
|
|
62
|
+
Built-in palette name or list of hex colors for the categorical range.
|
|
63
|
+
background:
|
|
64
|
+
Chart background color.
|
|
65
|
+
tiny_margins:
|
|
66
|
+
Minimise all paddings around the chart.
|
|
67
|
+
"""
|
|
68
|
+
colors = PALETTES[palette] if isinstance(palette, str) else list(palette)
|
|
69
|
+
font_stack = _css_font_stack(preferred=font)
|
|
70
|
+
|
|
71
|
+
FONT_SIZES = resolve_font_sizes(font_size)
|
|
72
|
+
MARGINS = Margins(
|
|
73
|
+
title=8 if tiny_margins else 12, # chart title offset
|
|
74
|
+
label=3 if tiny_margins else 6, # axis / legend title padding
|
|
75
|
+
legend=2 if tiny_margins else 4, # legend inner padding
|
|
76
|
+
)
|
|
77
|
+
THICKNESS = Thickness(
|
|
78
|
+
axes=thickness, # domain line width
|
|
79
|
+
grid=thickness * 0.8, # grid line width
|
|
80
|
+
ticks=thickness, # tick mark width
|
|
81
|
+
lines=2, # line-mark stroke width (independent of thickness)
|
|
82
|
+
patches=0.4, # geoshape stroke width
|
|
83
|
+
)
|
|
84
|
+
CHART_PAD = 6 if tiny_margins else 10
|
|
85
|
+
|
|
86
|
+
axis: AxisConfigKwds = {
|
|
87
|
+
"labelFont": font_stack,
|
|
88
|
+
"titleFont": font_stack,
|
|
89
|
+
"labelFontSize": FONT_SIZES.label,
|
|
90
|
+
"titleFontSize": FONT_SIZES.subtitle,
|
|
91
|
+
"labelColor": TEXT_GREY,
|
|
92
|
+
"titleColor": TEXT_GREY,
|
|
93
|
+
"titlePadding": MARGINS.label,
|
|
94
|
+
"domain": True,
|
|
95
|
+
"domainColor": BLACK,
|
|
96
|
+
"domainWidth": THICKNESS.axes,
|
|
97
|
+
"ticks": True,
|
|
98
|
+
"tickColor": BLACK,
|
|
99
|
+
"tickWidth": THICKNESS.ticks,
|
|
100
|
+
"tickSize": 4,
|
|
101
|
+
"grid": grid,
|
|
102
|
+
"gridColor": PRIME_LGREY,
|
|
103
|
+
"gridWidth": THICKNESS.grid,
|
|
104
|
+
"gridOpacity": 0.85,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
"config": {
|
|
109
|
+
"background": background,
|
|
110
|
+
"font": font_stack,
|
|
111
|
+
"padding": {"top": CHART_PAD, "bottom": CHART_PAD, "left": CHART_PAD, "right": CHART_PAD},
|
|
112
|
+
"view": {"stroke": None},
|
|
113
|
+
"axis": axis,
|
|
114
|
+
"axisX": axis,
|
|
115
|
+
"axisY": axis,
|
|
116
|
+
"legend": {
|
|
117
|
+
"labelFont": font_stack,
|
|
118
|
+
"titleFont": font_stack,
|
|
119
|
+
"labelFontSize": FONT_SIZES.legend,
|
|
120
|
+
"titleFontSize": FONT_SIZES.subtitle,
|
|
121
|
+
"labelColor": TEXT_GREY,
|
|
122
|
+
"titleColor": TEXT_GREY,
|
|
123
|
+
"titlePadding": MARGINS.label,
|
|
124
|
+
"padding": MARGINS.legend,
|
|
125
|
+
"rowPadding": FONT_SIZES.legend / 4,
|
|
126
|
+
"symbolSize": 100,
|
|
127
|
+
},
|
|
128
|
+
"header": {
|
|
129
|
+
"labelFont": font_stack,
|
|
130
|
+
"titleFont": font_stack,
|
|
131
|
+
"labelFontSize": FONT_SIZES.label,
|
|
132
|
+
"titleFontSize": FONT_SIZES.subtitle,
|
|
133
|
+
"labelColor": WHITE,
|
|
134
|
+
"titleColor": PRIME_BLUE,
|
|
135
|
+
"labelBackground": PRIME_BLUE,
|
|
136
|
+
},
|
|
137
|
+
"title": {
|
|
138
|
+
"font": font_stack,
|
|
139
|
+
"subtitleFont": font_stack,
|
|
140
|
+
"fontSize": FONT_SIZES.title,
|
|
141
|
+
"subtitleFontSize": FONT_SIZES.subtitle,
|
|
142
|
+
"color": PRIME_BLUE,
|
|
143
|
+
"subtitleColor": TEXT_GREY,
|
|
144
|
+
"anchor": "middle",
|
|
145
|
+
"offset": MARGINS.title,
|
|
146
|
+
},
|
|
147
|
+
"range": {
|
|
148
|
+
"category": colors,
|
|
149
|
+
"ordinal": colors,
|
|
150
|
+
"diverging": [SECOND_DBLUE, "#ffffff", KORALL],
|
|
151
|
+
"heatmap": ["#ffffff", PRIME_BLUE],
|
|
152
|
+
"ramp": ["#ffffff", PRIME_BLUE],
|
|
153
|
+
},
|
|
154
|
+
"bar": {"color": colors[0], "binSpacing": 1},
|
|
155
|
+
"line": {"color": colors[0], "strokeWidth": THICKNESS.lines},
|
|
156
|
+
"point": {"color": colors[0], "size": 60, "opacity": 0.85, "filled": True},
|
|
157
|
+
"area": {"color": colors[0], "opacity": 0.8},
|
|
158
|
+
"arc": {"color": colors[0]},
|
|
159
|
+
"rect": {"color": colors[0]},
|
|
160
|
+
"geoshape": {"stroke": WHITE, "strokeWidth": THICKNESS.patches},
|
|
161
|
+
"text": {"font": font_stack, "fontSize": FONT_SIZES.label, "color": TEXT_GREY},
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def register() -> None:
|
|
167
|
+
"""Register the Charité theme with Altair's theme registry (default params)."""
|
|
168
|
+
import altair as alt
|
|
169
|
+
alt.theme.register("charite", enable=False)(theme_charite)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def enable(**kwargs) -> None:
|
|
173
|
+
"""Register and enable the Charité theme in Altair.
|
|
174
|
+
|
|
175
|
+
Parameters
|
|
176
|
+
----------
|
|
177
|
+
**kwargs:
|
|
178
|
+
Any parameter accepted by ``theme_charite``
|
|
179
|
+
(``font``, ``font_size``, ``thickness``, ``grid``, ``palette``,
|
|
180
|
+
``background``, ``tiny_margins``).
|
|
181
|
+
|
|
182
|
+
Examples
|
|
183
|
+
--------
|
|
184
|
+
```python
|
|
185
|
+
from charite_plot.altair_themes import enable
|
|
186
|
+
enable(palette="goldelse", font_size=13)
|
|
187
|
+
```
|
|
188
|
+
"""
|
|
189
|
+
import altair as alt
|
|
190
|
+
func = (lambda: theme_charite(**kwargs)) if kwargs else theme_charite
|
|
191
|
+
alt.theme.register("charite", enable=True)(func)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@contextmanager
|
|
195
|
+
def using(**kwargs):
|
|
196
|
+
"""Temporarily enable the Charité theme, restoring the previous theme on exit.
|
|
197
|
+
|
|
198
|
+
Mirrors :func:`charite_plot.mpl_themes.using`. Charts created (or serialised
|
|
199
|
+
with ``chart.to_json()`` / ``chart.to_dict()``) inside the ``with`` block use
|
|
200
|
+
the Charité theme; the previously active theme is restored afterwards.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
**kwargs:
|
|
205
|
+
Any parameter accepted by ``theme_charite``.
|
|
206
|
+
|
|
207
|
+
Examples
|
|
208
|
+
--------
|
|
209
|
+
```python
|
|
210
|
+
from charite_plot.altair_themes import using
|
|
211
|
+
with using(palette="goldelse"):
|
|
212
|
+
spec = chart.to_json()
|
|
213
|
+
```
|
|
214
|
+
"""
|
|
215
|
+
import altair as alt
|
|
216
|
+
func = (lambda: theme_charite(**kwargs)) if kwargs else theme_charite
|
|
217
|
+
# Register under a unique throwaway name so we don't clobber the primary
|
|
218
|
+
# "charite" registration and so nested ``using`` blocks don't collide.
|
|
219
|
+
# ``alt.theme.enable`` restores the previous theme on exit; the temporary
|
|
220
|
+
# registration is removed afterwards to keep the registry clean.
|
|
221
|
+
name = f"_charite_{uuid4().hex}"
|
|
222
|
+
alt.theme.register(name, enable=False)(func)
|
|
223
|
+
try:
|
|
224
|
+
with alt.theme.enable(name):
|
|
225
|
+
yield
|
|
226
|
+
finally:
|
|
227
|
+
alt.theme.unregister(name)
|