charite-plot 0.1.0__py3-none-any.whl

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.
@@ -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)
charite_plot/colors.py ADDED
@@ -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
+ ]
charite_plot/fonts.py ADDED
@@ -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()))
@@ -0,0 +1,129 @@
1
+ """Matplotlib theme for Charité – Universitätsmedizin Berlin."""
2
+
3
+ from contextlib import contextmanager
4
+
5
+ from cycler import cycler
6
+
7
+ from .colors import TEXT_GREY, PRIME_BLUE, PRIME_LGREY, BLACK
8
+ from .palettes import PALETTES
9
+ from .fonts import build_font_stack
10
+
11
+
12
+ def theme_charite(
13
+ font: str | None = None,
14
+ font_size: float = 10,
15
+ thickness: float = 0.5,
16
+ grid: bool = False,
17
+ palette: str | list[str] = "primary",
18
+ ) -> dict:
19
+ """Return matplotlib rcParams dict for the Charité corporate identity theme.
20
+
21
+ Parameters
22
+ ----------
23
+ font:
24
+ Preferred font family. Falls back through Charité Text Office →
25
+ Charit? Text Office → Calibri → DejaVu Sans if the requested font is not installed.
26
+ font_size:
27
+ Base font size in points. Defaults to 10 for screen; use 8 for print.
28
+ thickness:
29
+ Axis line and tick width. Mirrors the R ``thickness`` parameter.
30
+ grid:
31
+ Show major grid lines. Disabled by default.
32
+ palette:
33
+ Name of a built-in palette or a list of hex color strings used for the
34
+ ``axes.prop_cycle``.
35
+ """
36
+ colors = PALETTES[palette] if isinstance(palette, str) else list(palette)
37
+
38
+ return {
39
+ # Font
40
+ "font.family": "sans-serif",
41
+ "font.sans-serif": build_font_stack(preferred=font),
42
+ "font.size": font_size,
43
+
44
+ # Spines — only bottom and left visible (mirrors theme_classic in R)
45
+ "axes.spines.top": False,
46
+ "axes.spines.right": False,
47
+
48
+ # Axes
49
+ "axes.linewidth": thickness,
50
+ "axes.titlesize": round(font_size * 1.2),
51
+ "axes.titlecolor": PRIME_BLUE,
52
+ "axes.titlepad": 8,
53
+ "axes.labelsize": font_size,
54
+ "axes.labelcolor": TEXT_GREY,
55
+ "axes.edgecolor": BLACK,
56
+ "axes.facecolor": "white",
57
+ "axes.grid": grid,
58
+
59
+ # Grid (only visible when grid=True)
60
+ "grid.color": PRIME_LGREY,
61
+ "grid.linewidth": thickness * 0.6,
62
+ "grid.alpha": 0.8,
63
+
64
+ # Ticks
65
+ "xtick.color": BLACK,
66
+ "ytick.color": BLACK,
67
+ "xtick.labelsize": font_size - 1,
68
+ "ytick.labelsize": font_size - 1,
69
+ "xtick.labelcolor": TEXT_GREY,
70
+ "ytick.labelcolor": TEXT_GREY,
71
+ "xtick.major.size": 3,
72
+ "ytick.major.size": 3,
73
+ "xtick.major.width": thickness,
74
+ "ytick.major.width": thickness,
75
+ "xtick.minor.visible": False,
76
+ "ytick.minor.visible": False,
77
+
78
+ # Text
79
+ "text.color": TEXT_GREY,
80
+
81
+ # Figure
82
+ "figure.facecolor": "white",
83
+ "figure.edgecolor": "white",
84
+ "figure.dpi": 100,
85
+
86
+ # Lines / markers
87
+ "lines.linewidth": 1.5,
88
+ "lines.markersize": 6,
89
+
90
+ # Patches (bars, etc.)
91
+ "patch.linewidth": 0,
92
+
93
+ # Legend
94
+ "legend.frameon": False,
95
+ "legend.fontsize": round(font_size * 0.9),
96
+ "legend.title_fontsize": font_size,
97
+ "legend.labelcolor": TEXT_GREY,
98
+
99
+ # Save
100
+ "savefig.dpi": 300,
101
+ "savefig.bbox": "tight",
102
+ "savefig.transparent": True,
103
+
104
+ # Color cycle
105
+ "axes.prop_cycle": cycler("color", colors),
106
+ }
107
+
108
+
109
+ def apply_theme(params: dict) -> None:
110
+ """Apply a theme dict as the active matplotlib rcParams (permanent until reset)."""
111
+ import matplotlib as mpl
112
+ mpl.rcParams.update(params)
113
+
114
+
115
+ @contextmanager
116
+ def using(params: dict):
117
+ """Context manager: temporarily apply *params* then restore previous rcParams.
118
+
119
+ Examples
120
+ --------
121
+ ```python
122
+ with using(theme_charite(palette="goldelse")):
123
+ fig, ax = plt.subplots()
124
+ ax.plot([1, 2, 3])
125
+ ```
126
+ """
127
+ import matplotlib as mpl
128
+ with mpl.rc_context(params):
129
+ yield
@@ -0,0 +1,70 @@
1
+ """Charité color palettes built from the shared color definitions."""
2
+
3
+ from .colors import (
4
+ BLACK,
5
+ PRIME_BLUE, PRIME_LGREY, PRIME_DGREY,
6
+ SECOND_DBLUE, SECOND_LBLUE, KORALL,
7
+ BRAUN, MOCCA, GRASGRUEN, LIMETTE, GRUEN, MINT,
8
+ MINERAL, AQUA, LILA, LAVENDEL, BROMBEERE, PFLAUME,
9
+ WEINROT, HIMBEER, ROT, MANGO, RAPSGELB,
10
+ )
11
+
12
+ PALETTES: dict[str, list[str]] = {
13
+ "primary": [PRIME_BLUE, PRIME_DGREY, PRIME_LGREY],
14
+ "secondary": [SECOND_DBLUE, SECOND_LBLUE, KORALL],
15
+ "mono": [BLACK, PRIME_DGREY, PRIME_LGREY],
16
+ "light": [SECOND_LBLUE, PRIME_LGREY],
17
+ "versus": [PRIME_BLUE, ROT],
18
+ "nineties": [LILA, MINT, MINERAL],
19
+ "brickhouse": [WEINROT, HIMBEER, MINT, GRUEN],
20
+ "sunrise": [SECOND_DBLUE, SECOND_LBLUE, RAPSGELB, MANGO],
21
+ "berryseason": [HIMBEER, PFLAUME, BROMBEERE, SECOND_DBLUE, MOCCA, BRAUN],
22
+ "goldelse": [MANGO, RAPSGELB, LIMETTE, GRASGRUEN, AQUA, MINERAL, LAVENDEL, LILA],
23
+ }
24
+
25
+
26
+ def make_palette(
27
+ name_or_colors: "str | list[str]",
28
+ n: "int | None" = None,
29
+ reverse: bool = False,
30
+ ) -> list[str]:
31
+ """Return a list of hex colors from a named palette or custom color list.
32
+
33
+ Parameters
34
+ ----------
35
+ name_or_colors:
36
+ A palette name (see ``PALETTES``) or a list of hex color strings.
37
+ n:
38
+ Number of colors to return. ``None`` returns all colors in the palette.
39
+ If ``n`` is larger than the palette, colors are linearly interpolated.
40
+ If ``n`` is smaller, colors are subsampled evenly.
41
+ reverse:
42
+ Reverse the palette before sampling.
43
+ """
44
+ if isinstance(name_or_colors, str):
45
+ if name_or_colors not in PALETTES:
46
+ raise ValueError(
47
+ f"Unknown palette {name_or_colors!r}. "
48
+ f"Available palettes: {list(PALETTES)}"
49
+ )
50
+ colors = list(PALETTES[name_or_colors])
51
+ else:
52
+ colors = list(name_or_colors)
53
+
54
+ if reverse:
55
+ colors = colors[::-1]
56
+
57
+ if n is None:
58
+ return colors
59
+
60
+ if n == 1:
61
+ return [colors[0]]
62
+
63
+ if n <= len(colors):
64
+ step = (len(colors) - 1) / (n - 1)
65
+ return [colors[round(i * step)] for i in range(n)]
66
+
67
+ # n > palette length: interpolate via matplotlib (lazy import)
68
+ from matplotlib.colors import LinearSegmentedColormap, to_hex
69
+ cmap = LinearSegmentedColormap.from_list("_charite_tmp", colors, N=n)
70
+ return [to_hex(cmap(i / (n - 1))) for i in range(n)]
charite_plot/py.typed ADDED
File without changes
@@ -0,0 +1,146 @@
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: Framework :: Matplotlib
23
+ Classifier: Intended Audience :: Science/Research
24
+ Classifier: License :: OSI Approved :: MIT License
25
+ Classifier: Operating System :: OS Independent
26
+ Classifier: Programming Language :: Python :: 3
27
+ Classifier: Programming Language :: Python :: 3.9
28
+ Classifier: Programming Language :: Python :: 3.10
29
+ Classifier: Programming Language :: Python :: 3.11
30
+ Classifier: Programming Language :: Python :: 3.12
31
+ Classifier: Programming Language :: Python :: 3.13
32
+ Classifier: Programming Language :: Python :: 3.14
33
+ Classifier: Topic :: Scientific/Engineering :: Visualization
34
+ Classifier: Typing :: Typed
35
+ Requires-Python: >=3.9
36
+ Requires-Dist: cycler
37
+ Requires-Dist: matplotlib>=3.5
38
+ Provides-Extra: all
39
+ Requires-Dist: altair>=5.5; extra == 'all'
40
+ Requires-Dist: vega-datasets; extra == 'all'
41
+ Provides-Extra: altair
42
+ Requires-Dist: altair>=5.5; extra == 'altair'
43
+ Requires-Dist: vega-datasets; extra == 'altair'
44
+ Provides-Extra: docs
45
+ Requires-Dist: mkdocs-material>=9.0; extra == 'docs'
46
+ Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
47
+ Description-Content-Type: text/markdown
48
+
49
+ # charite-plot
50
+
51
+ 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).
52
+
53
+ ## Installation
54
+
55
+ ```bash
56
+ pip install charite-plot # Matplotlib only
57
+ pip install "charite-plot[altair]" # with Altair support
58
+ ```
59
+
60
+ ## Examples
61
+
62
+ Visualize your data with `theme_charite()` to match the Charité corporate style.
63
+
64
+ <p align="center">
65
+ <img src="docs/assets/theme_example.png" width="80%"/>
66
+ </p>
67
+
68
+ Preview the available colour palettes.
69
+
70
+ <p align="center">
71
+ <img src="docs/assets/palette_preview.png" width="80%"/>
72
+ </p>
73
+
74
+ ## Quick start
75
+
76
+ ### Matplotlib
77
+
78
+ ```python
79
+ import matplotlib.pyplot as plt
80
+ from charite_plot.mpl_themes import theme_charite, apply_theme
81
+
82
+ apply_theme(theme_charite())
83
+
84
+ fig, ax = plt.subplots()
85
+ ax.plot([1, 2, 3], [4, 7, 3])
86
+ ax.set_title("My chart")
87
+ plt.show()
88
+ ```
89
+
90
+ Use as a context manager to scope the theme to a single figure:
91
+
92
+ ```python
93
+ from charite_plot.mpl_themes import theme_charite, using
94
+
95
+ with using(theme_charite(palette="goldelse")):
96
+ fig, ax = plt.subplots()
97
+ ax.bar(["A", "B", "C"], [3, 7, 5])
98
+ ```
99
+
100
+ ### Altair
101
+
102
+ ```python
103
+ from charite_plot.altair_themes import enable
104
+ import altair as alt
105
+
106
+ enable()
107
+
108
+ chart = alt.Chart(df).mark_bar().encode(...)
109
+ ```
110
+
111
+ Customise with keyword arguments:
112
+
113
+ ```python
114
+ enable(palette="berryseason", font_size=13)
115
+ ```
116
+
117
+ ## API overview
118
+
119
+ | Symbol | Description |
120
+ |--------|-------------|
121
+ | `mpl_themes.theme_charite()` | Returns a matplotlib rcParams dict for the Charité theme |
122
+ | `mpl_themes.apply_theme(params)` | Applies a theme dict permanently to `rcParams` |
123
+ | `mpl_themes.using(params)` | Context manager: applies theme temporarily |
124
+ | `altair_themes.theme_charite()` | Returns a Vega-Lite config dict for the Charité theme |
125
+ | `altair_themes.enable(**kwargs)` | Registers and enables the theme in Altair |
126
+ | `PALETTES` | Dict of 10 named colour palettes |
127
+ | `make_palette(name, n, reverse)` | Subsample or interpolate any palette |
128
+ | `CHARITE_COLORS` | Dict of all 27 hex colour constants |
129
+
130
+ ## Fonts
131
+
132
+ The fallback chain follows the official Charité brand guidelines:
133
+
134
+ **Charité Text Office → Charit? Text Office → Calibri → DejaVu Sans**
135
+
136
+ > **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.
137
+
138
+ `DejaVu Sans` ships with Matplotlib and is always available as the final fallback. To override the preferred font:
139
+
140
+ ```python
141
+ apply_theme(theme_charite(font="Arial"))
142
+ ```
143
+
144
+ ## License
145
+
146
+ MIT © 2026 Pedram Ramezani
@@ -0,0 +1,11 @@
1
+ charite_plot/__init__.py,sha256=-fUXS1V1e2KnRsQ7p6m7Dz0aFAzaLhRaFATtfv8NiCg,894
2
+ charite_plot/altair_themes.py,sha256=ynVTYIKlE1k0yyvK_T0fM5R_7HDr9Wdg7bjsCLLDkhc,5466
3
+ charite_plot/colors.py,sha256=hTH4D88RyZ7eOZ_-0Sx7hOv2CjNfzR9CvFJloLKU5fk,2077
4
+ charite_plot/fonts.py,sha256=92y9-hxOrx8TAtDN0viTXEfp0XvpN8UDR5r6HKM-EcQ,1124
5
+ charite_plot/mpl_themes.py,sha256=4m4bQNHbVqZPQ5Hw9s02qh3aEFbBdqHiCFrbsIXXhRQ,3821
6
+ charite_plot/palettes.py,sha256=EsNdEqVB1S6iaXkSM3WxrIWU_1LmQMmDtNBF9g-YGnw,2443
7
+ charite_plot/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ charite_plot-0.1.0.dist-info/METADATA,sha256=g9UqffFmtqGAYCDkSaVF4ufq5vS6jU4zuMAKrseOxK8,5621
9
+ charite_plot-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
10
+ charite_plot-0.1.0.dist-info/licenses/LICENSE.md,sha256=6PeoiIPm5MX2SYYXmzg0MIMEWKR2N9xJB78zOeAezrw,1070
11
+ charite_plot-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -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.