charite-plot 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.
- charite_plot-0.1.0/.github/workflows/ci.yml +28 -0
- charite_plot-0.1.0/.gitignore +3 -0
- charite_plot-0.1.0/LICENSE.md +9 -0
- charite_plot-0.1.0/PKG-INFO +141 -0
- charite_plot-0.1.0/README.md +98 -0
- charite_plot-0.1.0/charite_plot/__init__.py +30 -0
- charite_plot-0.1.0/charite_plot/altair_themes.py +163 -0
- charite_plot-0.1.0/charite_plot/colors.py +77 -0
- charite_plot-0.1.0/charite_plot/fonts.py +37 -0
- charite_plot-0.1.0/charite_plot/mpl_themes.py +129 -0
- charite_plot-0.1.0/charite_plot/palettes.py +70 -0
- charite_plot-0.1.0/docs/altair.md +97 -0
- charite_plot-0.1.0/docs/api/altair_themes.md +8 -0
- charite_plot-0.1.0/docs/api/colors.md +58 -0
- charite_plot-0.1.0/docs/api/fonts.md +8 -0
- charite_plot-0.1.0/docs/api/mpl_themes.md +8 -0
- charite_plot-0.1.0/docs/api/palettes.md +34 -0
- charite_plot-0.1.0/docs/assets/palette_preview.png +0 -0
- charite_plot-0.1.0/docs/assets/theme_example.png +0 -0
- charite_plot-0.1.0/docs/colors.md +168 -0
- charite_plot-0.1.0/docs/index.md +62 -0
- charite_plot-0.1.0/docs/installation.md +44 -0
- charite_plot-0.1.0/docs/matplotlib.md +89 -0
- charite_plot-0.1.0/docs/palettes.md +114 -0
- charite_plot-0.1.0/docs/stylesheets/extra.css +50 -0
- charite_plot-0.1.0/examples/altair_showcase.py +168 -0
- charite_plot-0.1.0/examples/mpl_showcase.py +189 -0
- charite_plot-0.1.0/examples/palette_preview.py +47 -0
- charite_plot-0.1.0/examples/poly_showcase.py +108 -0
- charite_plot-0.1.0/mkdocs.yml +58 -0
- charite_plot-0.1.0/pyproject.toml +47 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- main
|
|
6
|
+
permissions:
|
|
7
|
+
contents: write
|
|
8
|
+
jobs:
|
|
9
|
+
deploy:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- name: Configure Git Credentials
|
|
14
|
+
run: |
|
|
15
|
+
git config user.name github-actions[bot]
|
|
16
|
+
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: 3.x
|
|
20
|
+
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
|
|
21
|
+
- uses: actions/cache@v4
|
|
22
|
+
with:
|
|
23
|
+
key: mkdocs-material-${{ env.cache_id }}
|
|
24
|
+
path: ~/.cache
|
|
25
|
+
restore-keys: |
|
|
26
|
+
mkdocs-material-
|
|
27
|
+
- run: pip install mkdocs-material mkdocstrings[python]
|
|
28
|
+
- run: mkdocs gh-deploy --force
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright 2026 Pedram Ramezani
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
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.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: charite-plot
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Matplotlib and Altair themes for Charité – Universitätsmedizin Berlin
|
|
5
|
+
Project-URL: Homepage, https://github.com/pedramramezani/charite-plot
|
|
6
|
+
Project-URL: Documentation, https://pedramramezani.github.io/charite-plot
|
|
7
|
+
Project-URL: Repository, https://github.com/pedramramezani/charite-plot
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/pedramramezani/charite-plot/issues
|
|
9
|
+
Author-email: Pedram Ramezani <pedramramezani.pr@gmail.com>
|
|
10
|
+
License: # MIT License
|
|
11
|
+
|
|
12
|
+
Copyright 2026 Pedram Ramezani
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
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.
|
|
19
|
+
License-File: LICENSE.md
|
|
20
|
+
Keywords: altair,charite,matplotlib,theme,visualization
|
|
21
|
+
Classifier: Development Status :: 3 - Alpha
|
|
22
|
+
Classifier: Intended Audience :: Science/Research
|
|
23
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
24
|
+
Classifier: Programming Language :: Python :: 3
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
29
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
30
|
+
Requires-Python: >=3.9
|
|
31
|
+
Requires-Dist: cycler
|
|
32
|
+
Requires-Dist: matplotlib>=3.5
|
|
33
|
+
Provides-Extra: all
|
|
34
|
+
Requires-Dist: altair>=5.5; extra == 'all'
|
|
35
|
+
Requires-Dist: vega-datasets; extra == 'all'
|
|
36
|
+
Provides-Extra: altair
|
|
37
|
+
Requires-Dist: altair>=5.5; extra == 'altair'
|
|
38
|
+
Requires-Dist: vega-datasets; extra == 'altair'
|
|
39
|
+
Provides-Extra: docs
|
|
40
|
+
Requires-Dist: mkdocs-material>=9.0; extra == 'docs'
|
|
41
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
|
|
44
|
+
# charite-plot
|
|
45
|
+
|
|
46
|
+
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).
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install charite-plot # Matplotlib only
|
|
52
|
+
pip install "charite-plot[altair]" # with Altair support
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
Visualize your data with `theme_charite()` to match the Charité corporate style.
|
|
58
|
+
|
|
59
|
+
<p align="center">
|
|
60
|
+
<img src="docs/assets/theme_example.png" width="80%"/>
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
Preview the available colour palettes.
|
|
64
|
+
|
|
65
|
+
<p align="center">
|
|
66
|
+
<img src="docs/assets/palette_preview.png" width="80%"/>
|
|
67
|
+
</p>
|
|
68
|
+
|
|
69
|
+
## Quick start
|
|
70
|
+
|
|
71
|
+
### Matplotlib
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import matplotlib.pyplot as plt
|
|
75
|
+
from charite_plot.mpl_themes import theme_charite, apply_theme
|
|
76
|
+
|
|
77
|
+
apply_theme(theme_charite())
|
|
78
|
+
|
|
79
|
+
fig, ax = plt.subplots()
|
|
80
|
+
ax.plot([1, 2, 3], [4, 7, 3])
|
|
81
|
+
ax.set_title("My chart")
|
|
82
|
+
plt.show()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Use as a context manager to scope the theme to a single figure:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from charite_plot.mpl_themes import theme_charite, using
|
|
89
|
+
|
|
90
|
+
with using(theme_charite(palette="goldelse")):
|
|
91
|
+
fig, ax = plt.subplots()
|
|
92
|
+
ax.bar(["A", "B", "C"], [3, 7, 5])
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Altair
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from charite_plot.altair_themes import enable
|
|
99
|
+
import altair as alt
|
|
100
|
+
|
|
101
|
+
enable()
|
|
102
|
+
|
|
103
|
+
chart = alt.Chart(df).mark_bar().encode(...)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Customise with keyword arguments:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
enable(palette="berryseason", font_size=13)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## API overview
|
|
113
|
+
|
|
114
|
+
| Symbol | Description |
|
|
115
|
+
|--------|-------------|
|
|
116
|
+
| `mpl_themes.theme_charite()` | Returns a matplotlib rcParams dict for the Charité theme |
|
|
117
|
+
| `mpl_themes.apply_theme(params)` | Applies a theme dict permanently to `rcParams` |
|
|
118
|
+
| `mpl_themes.using(params)` | Context manager: applies theme temporarily |
|
|
119
|
+
| `altair_themes.theme_charite()` | Returns a Vega-Lite config dict for the Charité theme |
|
|
120
|
+
| `altair_themes.enable(**kwargs)` | Registers and enables the theme in Altair |
|
|
121
|
+
| `PALETTES` | Dict of 10 named colour palettes |
|
|
122
|
+
| `make_palette(name, n, reverse)` | Subsample or interpolate any palette |
|
|
123
|
+
| `CHARITE_COLORS` | Dict of all 27 hex colour constants |
|
|
124
|
+
|
|
125
|
+
## Fonts
|
|
126
|
+
|
|
127
|
+
The fallback chain follows the official Charité brand guidelines:
|
|
128
|
+
|
|
129
|
+
**Charité Text Office → Charit? Text Office → Calibri → DejaVu Sans**
|
|
130
|
+
|
|
131
|
+
> **Ersatzschrift „Calibri"** — Falls die Hausschrift aus technischen Gründen nicht verwendet werden kann, ersetzt die Systemschriftart „Calibri" die Hausschrift. Dies ist beispielsweise bei der E-Mail-Korrespondenz der Fall.
|
|
132
|
+
|
|
133
|
+
`DejaVu Sans` ships with Matplotlib and is always available as the final fallback. To override the preferred font:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
apply_theme(theme_charite(font="Arial"))
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT © 2026 Pedram Ramezani
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# charite-plot
|
|
2
|
+
|
|
3
|
+
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
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install charite-plot # Matplotlib only
|
|
9
|
+
pip install "charite-plot[altair]" # with Altair support
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Examples
|
|
13
|
+
|
|
14
|
+
Visualize your data with `theme_charite()` to match the Charité corporate style.
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<img src="docs/assets/theme_example.png" width="80%"/>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
Preview the available colour palettes.
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
<img src="docs/assets/palette_preview.png" width="80%"/>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
### Matplotlib
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import matplotlib.pyplot as plt
|
|
32
|
+
from charite_plot.mpl_themes import theme_charite, apply_theme
|
|
33
|
+
|
|
34
|
+
apply_theme(theme_charite())
|
|
35
|
+
|
|
36
|
+
fig, ax = plt.subplots()
|
|
37
|
+
ax.plot([1, 2, 3], [4, 7, 3])
|
|
38
|
+
ax.set_title("My chart")
|
|
39
|
+
plt.show()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use as a context manager to scope the theme to a single figure:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from charite_plot.mpl_themes import theme_charite, using
|
|
46
|
+
|
|
47
|
+
with using(theme_charite(palette="goldelse")):
|
|
48
|
+
fig, ax = plt.subplots()
|
|
49
|
+
ax.bar(["A", "B", "C"], [3, 7, 5])
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Altair
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from charite_plot.altair_themes import enable
|
|
56
|
+
import altair as alt
|
|
57
|
+
|
|
58
|
+
enable()
|
|
59
|
+
|
|
60
|
+
chart = alt.Chart(df).mark_bar().encode(...)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Customise with keyword arguments:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
enable(palette="berryseason", font_size=13)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## API overview
|
|
70
|
+
|
|
71
|
+
| Symbol | Description |
|
|
72
|
+
|--------|-------------|
|
|
73
|
+
| `mpl_themes.theme_charite()` | Returns a matplotlib rcParams dict for the Charité theme |
|
|
74
|
+
| `mpl_themes.apply_theme(params)` | Applies a theme dict permanently to `rcParams` |
|
|
75
|
+
| `mpl_themes.using(params)` | Context manager: applies theme temporarily |
|
|
76
|
+
| `altair_themes.theme_charite()` | Returns a Vega-Lite config dict for the Charité theme |
|
|
77
|
+
| `altair_themes.enable(**kwargs)` | Registers and enables the theme in Altair |
|
|
78
|
+
| `PALETTES` | Dict of 10 named colour palettes |
|
|
79
|
+
| `make_palette(name, n, reverse)` | Subsample or interpolate any palette |
|
|
80
|
+
| `CHARITE_COLORS` | Dict of all 27 hex colour constants |
|
|
81
|
+
|
|
82
|
+
## Fonts
|
|
83
|
+
|
|
84
|
+
The fallback chain follows the official Charité brand guidelines:
|
|
85
|
+
|
|
86
|
+
**Charité Text Office → Charit? Text Office → Calibri → DejaVu Sans**
|
|
87
|
+
|
|
88
|
+
> **Ersatzschrift „Calibri"** — Falls die Hausschrift aus technischen Gründen nicht verwendet werden kann, ersetzt die Systemschriftart „Calibri" die Hausschrift. Dies ist beispielsweise bei der E-Mail-Korrespondenz der Fall.
|
|
89
|
+
|
|
90
|
+
`DejaVu Sans` ships with Matplotlib and is always available as the final fallback. To override the preferred font:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
apply_theme(theme_charite(font="Arial"))
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT © 2026 Pedram Ramezani
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""charite_plot — Matplotlib and Altair themes for Charité – Universitätsmedizin Berlin.
|
|
2
|
+
|
|
3
|
+
Quick start
|
|
4
|
+
-----------
|
|
5
|
+
Matplotlib::
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
from charite_plot.mpl_themes import theme_charite, apply_theme
|
|
9
|
+
|
|
10
|
+
apply_theme(theme_charite()) # permanent
|
|
11
|
+
# or temporarily:
|
|
12
|
+
from charite_plot.mpl_themes import using
|
|
13
|
+
with using(theme_charite(palette="goldelse")):
|
|
14
|
+
fig, ax = plt.subplots()
|
|
15
|
+
ax.plot([1, 2, 3])
|
|
16
|
+
|
|
17
|
+
Altair::
|
|
18
|
+
|
|
19
|
+
from charite_plot.altair_themes import enable
|
|
20
|
+
enable()
|
|
21
|
+
# charts rendered after this call use the theme automatically
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from .colors import * # noqa: F401, F403 (all color constants + CHARITE_COLORS)
|
|
25
|
+
from .palettes import PALETTES, make_palette # noqa: F401
|
|
26
|
+
from . import mpl_themes # noqa: F401
|
|
27
|
+
from . import altair_themes # noqa: F401
|
|
28
|
+
|
|
29
|
+
__version__ = "0.1.0"
|
|
30
|
+
__author__ = "Pedram Ramezani"
|
|
@@ -0,0 +1,163 @@
|
|
|
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 .colors import (
|
|
12
|
+
BLACK, WHITE, TEXT_GREY, PRIME_BLUE, PRIME_LGREY,
|
|
13
|
+
SECOND_DBLUE, KORALL,
|
|
14
|
+
)
|
|
15
|
+
from .palettes import PALETTES
|
|
16
|
+
from .fonts import build_font_stack
|
|
17
|
+
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from altair.theme import ThemeConfig
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _css_font_stack(preferred: str | None) -> str:
|
|
25
|
+
"""Return a CSS font-family string (comma-separated, quoted if needed)."""
|
|
26
|
+
def _quote(name: str) -> str:
|
|
27
|
+
return f'"{name}"' if " " in name else name
|
|
28
|
+
|
|
29
|
+
return ", ".join(_quote(f) for f in build_font_stack(preferred=preferred))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def theme_charite(
|
|
33
|
+
font: str | None = None,
|
|
34
|
+
font_size: int = 12,
|
|
35
|
+
grid: bool = False,
|
|
36
|
+
palette: str | list[str] = "primary",
|
|
37
|
+
background: str = "white",
|
|
38
|
+
) -> "ThemeConfig":
|
|
39
|
+
"""Return an Altair theme config dict for the Charité corporate theme.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
font:
|
|
44
|
+
Preferred font. Falls back through Charité Text Office → Charit? Text Office → Calibri → DejaVu Sans.
|
|
45
|
+
font_size:
|
|
46
|
+
Base font size in pixels.
|
|
47
|
+
grid:
|
|
48
|
+
Show axis grid lines.
|
|
49
|
+
palette:
|
|
50
|
+
Built-in palette name or list of hex colors for the categorical range.
|
|
51
|
+
background:
|
|
52
|
+
Chart background color.
|
|
53
|
+
"""
|
|
54
|
+
colors = PALETTES[palette] if isinstance(palette, str) else list(palette)
|
|
55
|
+
font_str = _css_font_stack(preferred=font)
|
|
56
|
+
label_size = font_size - 1
|
|
57
|
+
title_size = round(font_size * 1.2)
|
|
58
|
+
|
|
59
|
+
axis = {
|
|
60
|
+
"labelFont": font_str,
|
|
61
|
+
"titleFont": font_str,
|
|
62
|
+
"labelFontSize": label_size,
|
|
63
|
+
"titleFontSize": font_size,
|
|
64
|
+
"labelColor": TEXT_GREY,
|
|
65
|
+
"titleColor": TEXT_GREY,
|
|
66
|
+
"titlePadding": 6,
|
|
67
|
+
"domain": True,
|
|
68
|
+
"domainColor": BLACK,
|
|
69
|
+
"domainWidth": 0.5,
|
|
70
|
+
"ticks": True,
|
|
71
|
+
"tickColor": BLACK,
|
|
72
|
+
"tickWidth": 0.5,
|
|
73
|
+
"tickSize": 4,
|
|
74
|
+
"grid": grid,
|
|
75
|
+
"gridColor": PRIME_LGREY,
|
|
76
|
+
"gridWidth": 0.4,
|
|
77
|
+
"gridOpacity": 0.8,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
"config": {
|
|
82
|
+
"background": background,
|
|
83
|
+
"font": font_str,
|
|
84
|
+
"padding": {"top": 10, "bottom": 10, "left": 10, "right": 10},
|
|
85
|
+
"view": {"stroke": None},
|
|
86
|
+
"axis": axis,
|
|
87
|
+
"axisX": axis,
|
|
88
|
+
"axisY": axis,
|
|
89
|
+
"legend": {
|
|
90
|
+
"labelFont": font_str,
|
|
91
|
+
"titleFont": font_str,
|
|
92
|
+
"labelFontSize": label_size,
|
|
93
|
+
"titleFontSize": font_size,
|
|
94
|
+
"labelColor": TEXT_GREY,
|
|
95
|
+
"titleColor": TEXT_GREY,
|
|
96
|
+
"titlePadding": 6,
|
|
97
|
+
"padding": 4,
|
|
98
|
+
"rowPadding": 3,
|
|
99
|
+
"symbolSize": 100,
|
|
100
|
+
},
|
|
101
|
+
"header": {
|
|
102
|
+
"labelFont": font_str,
|
|
103
|
+
"titleFont": font_str,
|
|
104
|
+
"labelFontSize": label_size,
|
|
105
|
+
"titleFontSize": font_size,
|
|
106
|
+
"labelColor": WHITE,
|
|
107
|
+
"titleColor": PRIME_BLUE,
|
|
108
|
+
"labelBackground": PRIME_BLUE,
|
|
109
|
+
},
|
|
110
|
+
"title": {
|
|
111
|
+
"font": font_str,
|
|
112
|
+
"subtitleFont": font_str,
|
|
113
|
+
"fontSize": title_size,
|
|
114
|
+
"subtitleFontSize": font_size,
|
|
115
|
+
"color": PRIME_BLUE,
|
|
116
|
+
"subtitleColor": TEXT_GREY,
|
|
117
|
+
"anchor": "middle",
|
|
118
|
+
"offset": 12,
|
|
119
|
+
},
|
|
120
|
+
"range": {
|
|
121
|
+
"category": colors,
|
|
122
|
+
"ordinal": colors,
|
|
123
|
+
"diverging": [SECOND_DBLUE, "#ffffff", KORALL],
|
|
124
|
+
"heatmap": ["#ffffff", PRIME_BLUE],
|
|
125
|
+
"ramp": ["#ffffff", PRIME_BLUE],
|
|
126
|
+
},
|
|
127
|
+
"bar": {"color": colors[0], "binSpacing": 1},
|
|
128
|
+
"line": {"color": colors[0], "strokeWidth": 2},
|
|
129
|
+
"point": {"color": colors[0], "size": 60, "opacity": 0.85, "filled": True},
|
|
130
|
+
"area": {"color": colors[0], "opacity": 0.8},
|
|
131
|
+
"arc": {"color": colors[0]},
|
|
132
|
+
"rect": {"color": colors[0]},
|
|
133
|
+
"geoshape": {"stroke": WHITE, "strokeWidth": 0.4},
|
|
134
|
+
"text": {"font": font_str, "fontSize": label_size, "color": TEXT_GREY},
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def register() -> None:
|
|
140
|
+
"""Register the Charité theme with Altair's theme registry (default params)."""
|
|
141
|
+
import altair as alt
|
|
142
|
+
alt.theme.register("charite", enable=False)(theme_charite)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def enable(**kwargs) -> None:
|
|
146
|
+
"""Register and enable the Charité theme in Altair.
|
|
147
|
+
|
|
148
|
+
Parameters
|
|
149
|
+
----------
|
|
150
|
+
**kwargs:
|
|
151
|
+
Any parameter accepted by ``theme_charite``
|
|
152
|
+
(``font``, ``font_size``, ``grid``, ``palette``, ``background``).
|
|
153
|
+
|
|
154
|
+
Examples
|
|
155
|
+
--------
|
|
156
|
+
```python
|
|
157
|
+
from charite_plot.altair_themes import enable
|
|
158
|
+
enable(palette="goldelse", font_size=13)
|
|
159
|
+
```
|
|
160
|
+
"""
|
|
161
|
+
import altair as alt
|
|
162
|
+
func = (lambda: theme_charite(**kwargs)) if kwargs else theme_charite
|
|
163
|
+
alt.theme.register("charite", enable=True)(func)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Charité color definitions — the single source of truth shared by all themes."""
|
|
2
|
+
|
|
3
|
+
# Primary
|
|
4
|
+
WHITE = "#ffffff"
|
|
5
|
+
BLACK = "#000000"
|
|
6
|
+
TEXT_GREY = "#5e676c"
|
|
7
|
+
PRIME_BLUE = "#004d9b"
|
|
8
|
+
PRIME_LGREY = "#cbcfd2"
|
|
9
|
+
PRIME_DGREY = "#7e898f"
|
|
10
|
+
|
|
11
|
+
# Secondary
|
|
12
|
+
SECOND_DBLUE = "#002552"
|
|
13
|
+
SECOND_LBLUE = "#007bc3"
|
|
14
|
+
KORALL = "#ea5451"
|
|
15
|
+
|
|
16
|
+
# Accents
|
|
17
|
+
BRAUN = "#89725b"
|
|
18
|
+
MOCCA = "#c8b8ad"
|
|
19
|
+
GRASGRUEN = "#a1ba0c"
|
|
20
|
+
LIMETTE = "#d1d811"
|
|
21
|
+
GRUEN = "#008939"
|
|
22
|
+
MINT = "#88c69a"
|
|
23
|
+
MINERAL = "#009aa9"
|
|
24
|
+
AQUA = "#61c3d7"
|
|
25
|
+
LILA = "#564091"
|
|
26
|
+
LAVENDEL = "#7876b6"
|
|
27
|
+
BROMBEERE = "#6f186d"
|
|
28
|
+
PFLAUME = "#944292"
|
|
29
|
+
WEINROT = "#89014c"
|
|
30
|
+
HIMBEER = "#d74b7f"
|
|
31
|
+
ROT = "#e31f2c"
|
|
32
|
+
MANGO = "#fab600"
|
|
33
|
+
RAPSGELB = "#ffdf43"
|
|
34
|
+
|
|
35
|
+
# Special
|
|
36
|
+
EMPLOYER_BRANDING_GREEN = "#ccefcb"
|
|
37
|
+
|
|
38
|
+
# Lookup dict (lowercase keys)
|
|
39
|
+
CHARITE_COLORS: dict[str, str] = {
|
|
40
|
+
"white": WHITE,
|
|
41
|
+
"black": BLACK,
|
|
42
|
+
"text_grey": TEXT_GREY,
|
|
43
|
+
"prime_blue": PRIME_BLUE,
|
|
44
|
+
"prime_lgrey": PRIME_LGREY,
|
|
45
|
+
"prime_dgrey": PRIME_DGREY,
|
|
46
|
+
"second_dblue": SECOND_DBLUE,
|
|
47
|
+
"second_lblue": SECOND_LBLUE,
|
|
48
|
+
"korall": KORALL,
|
|
49
|
+
"braun": BRAUN,
|
|
50
|
+
"mocca": MOCCA,
|
|
51
|
+
"grasgruen": GRASGRUEN,
|
|
52
|
+
"limette": LIMETTE,
|
|
53
|
+
"gruen": GRUEN,
|
|
54
|
+
"mint": MINT,
|
|
55
|
+
"mineral": MINERAL,
|
|
56
|
+
"aqua": AQUA,
|
|
57
|
+
"lila": LILA,
|
|
58
|
+
"lavendel": LAVENDEL,
|
|
59
|
+
"brombeere": BROMBEERE,
|
|
60
|
+
"pflaume": PFLAUME,
|
|
61
|
+
"weinrot": WEINROT,
|
|
62
|
+
"himbeer": HIMBEER,
|
|
63
|
+
"rot": ROT,
|
|
64
|
+
"mango": MANGO,
|
|
65
|
+
"rapsgelb": RAPSGELB,
|
|
66
|
+
"employer_branding_green": EMPLOYER_BRANDING_GREEN,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
__all__ = [
|
|
70
|
+
"WHITE", "BLACK", "TEXT_GREY", "PRIME_BLUE", "PRIME_LGREY", "PRIME_DGREY",
|
|
71
|
+
"SECOND_DBLUE", "SECOND_LBLUE", "KORALL",
|
|
72
|
+
"BRAUN", "MOCCA", "GRASGRUEN", "LIMETTE", "GRUEN", "MINT",
|
|
73
|
+
"MINERAL", "AQUA", "LILA", "LAVENDEL", "BROMBEERE", "PFLAUME",
|
|
74
|
+
"WEINROT", "HIMBEER", "ROT", "MANGO", "RAPSGELB",
|
|
75
|
+
"EMPLOYER_BRANDING_GREEN",
|
|
76
|
+
"CHARITE_COLORS",
|
|
77
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Font detection and fallback utilities."""
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
|
|
5
|
+
FONT_STACK = ["Charité Text Office", "Charit? Text Office", "Calibri", "DejaVu Sans"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _available_fonts() -> set[str]:
|
|
9
|
+
try:
|
|
10
|
+
import matplotlib.font_manager as fm
|
|
11
|
+
return {f.name for f in fm.fontManager.ttflist}
|
|
12
|
+
except Exception:
|
|
13
|
+
return set()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def check_font(font: str) -> bool:
|
|
17
|
+
"""Return True if *font* is available on this system, else warn and return False."""
|
|
18
|
+
if font in _available_fonts():
|
|
19
|
+
return True
|
|
20
|
+
warnings.warn(
|
|
21
|
+
f"Font '{font}' is not installed on this system. "
|
|
22
|
+
"Using the fallback chain: Charité Text Office → Charit? Text Office → Calibri → DejaVu Sans.",
|
|
23
|
+
UserWarning,
|
|
24
|
+
stacklevel=3,
|
|
25
|
+
)
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def build_font_stack(preferred: str | None) -> list[str]:
|
|
30
|
+
"""Return the font list for matplotlib's ``font.sans-serif`` rcParam."""
|
|
31
|
+
if preferred is None:
|
|
32
|
+
return FONT_STACK
|
|
33
|
+
check_font(preferred)
|
|
34
|
+
return [preferred, *[f for f in FONT_STACK if f != preferred]]
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__":
|
|
37
|
+
print(sorted(_available_fonts()))
|