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.
Files changed (42) hide show
  1. charite_plot-0.3.0/CHANGELOG.md +54 -0
  2. charite_plot-0.3.0/CITATION.cff +19 -0
  3. {charite_plot-0.1.1 → charite_plot-0.3.0}/LICENSE.md +4 -0
  4. {charite_plot-0.1.1 → charite_plot-0.3.0}/PKG-INFO +44 -10
  5. {charite_plot-0.1.1 → charite_plot-0.3.0}/README.md +39 -9
  6. {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/__init__.py +17 -8
  7. charite_plot-0.3.0/charite_plot/_theme_common.py +57 -0
  8. charite_plot-0.3.0/charite_plot/altair_themes.py +227 -0
  9. {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/fonts.py +2 -0
  10. charite_plot-0.3.0/charite_plot/mpl_themes.py +215 -0
  11. {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/palettes.py +2 -0
  12. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/altair.md +14 -0
  13. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/altair_themes.md +1 -0
  14. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/mpl_themes.md +1 -1
  15. charite_plot-0.3.0/docs/assets/theme_example.png +0 -0
  16. charite_plot-0.3.0/docs/citing.md +20 -0
  17. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/index.md +5 -5
  18. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/installation.md +2 -2
  19. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/matplotlib.md +25 -10
  20. {charite_plot-0.1.1 → charite_plot-0.3.0}/examples/mpl_showcase.py +5 -3
  21. charite_plot-0.3.0/examples/palette_preview.py +61 -0
  22. charite_plot-0.3.0/examples/poly_showcase.py +107 -0
  23. {charite_plot-0.1.1 → charite_plot-0.3.0}/mkdocs.yml +1 -0
  24. charite_plot-0.1.1/CHANGELOG.md +0 -27
  25. charite_plot-0.1.1/charite_plot/altair_themes.py +0 -163
  26. charite_plot-0.1.1/charite_plot/mpl_themes.py +0 -129
  27. charite_plot-0.1.1/docs/assets/theme_example.png +0 -0
  28. charite_plot-0.1.1/examples/palette_preview.py +0 -47
  29. charite_plot-0.1.1/examples/poly_showcase.py +0 -108
  30. {charite_plot-0.1.1 → charite_plot-0.3.0}/.github/workflows/ci.yml +0 -0
  31. {charite_plot-0.1.1 → charite_plot-0.3.0}/.gitignore +0 -0
  32. {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/colors.py +0 -0
  33. {charite_plot-0.1.1 → charite_plot-0.3.0}/charite_plot/py.typed +0 -0
  34. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/colors.md +0 -0
  35. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/fonts.md +0 -0
  36. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/api/palettes.md +0 -0
  37. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/assets/palette_preview.png +0 -0
  38. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/colors.md +0 -0
  39. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/palettes.md +0 -0
  40. {charite_plot-0.1.1 → charite_plot-0.3.0}/docs/stylesheets/extra.css +0 -0
  41. {charite_plot-0.1.1 → charite_plot-0.3.0}/examples/altair_showcase.py +0 -0
  42. {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.1.1
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
+ ![PyPI Version](https://img.shields.io/pypi/v/charite-plot?link=https%3A%2F%2Fpypi.org%2Fproject%2Fcharite-plot%2F)
57
+ ![PyPI License](https://img.shields.io/pypi/l/charite_plot)
58
+ ![PyPI Python Version](https://img.shields.io/pypi/pyversions/charite-plot)
59
+ ![PyPI Types](https://img.shields.io/pypi/types/charite-plot)
60
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/pedRamezani/charite-plot/ci.yml)
61
+ ![Website](https://img.shields.io/website?url=https%3A%2F%2Fpedramezani.github.io%2Fcharite-plot%2F&style=social&logo=materialformkdocs&label=documentation)
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 theme_charite, apply_theme
92
+ from charite_plot.mpl_themes import enable
82
93
 
83
- apply_theme(theme_charite())
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 theme_charite, using
105
+ from charite_plot.mpl_themes import using
95
106
 
96
- with using(theme_charite(palette="goldelse")):
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.apply_theme(params)` | Applies a theme dict permanently to `rcParams` |
124
- | `mpl_themes.using(params)` | Context manager: applies theme temporarily |
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
- apply_theme(theme_charite(font="Arial"))
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
+ ![PyPI Version](https://img.shields.io/pypi/v/charite-plot?link=https%3A%2F%2Fpypi.org%2Fproject%2Fcharite-plot%2F)
4
+ ![PyPI License](https://img.shields.io/pypi/l/charite_plot)
5
+ ![PyPI Python Version](https://img.shields.io/pypi/pyversions/charite-plot)
6
+ ![PyPI Types](https://img.shields.io/pypi/types/charite-plot)
7
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/pedRamezani/charite-plot/ci.yml)
8
+ ![Website](https://img.shields.io/website?url=https%3A%2F%2Fpedramezani.github.io%2Fcharite-plot%2F&style=social&logo=materialformkdocs&label=documentation)
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 theme_charite, apply_theme
39
+ from charite_plot.mpl_themes import enable
33
40
 
34
- apply_theme(theme_charite())
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 theme_charite, using
52
+ from charite_plot.mpl_themes import using
46
53
 
47
- with using(theme_charite(palette="goldelse")):
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.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 |
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
- apply_theme(theme_charite(font="Arial"))
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 theme_charite, apply_theme
8
+ from charite_plot.mpl_themes import enable
9
9
 
10
- apply_theme(theme_charite()) # permanent
10
+ enable() # permanent
11
11
  # or temporarily:
12
12
  from charite_plot.mpl_themes import using
13
- with using(theme_charite(palette="goldelse")):
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: 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
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.1.1"
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)
@@ -2,6 +2,8 @@
2
2
 
3
3
  import warnings
4
4
 
5
+ __all__ = ["FONT_STACK", "check_font", "build_font_stack"]
6
+
5
7
  FONT_STACK = ["Charité Text Office", "Charit? Text Office", "Calibri", "DejaVu Sans", "sans-serif"]
6
8
 
7
9