mr-theme 0.1.1__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.
mr_theme/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ """The MR-Theme Package.
2
+
3
+ .. moduleauthor:: Michael Rippstein <info@anatas.ch>
4
+
5
+ :copyright: Copyright 2026 by Michael Rippstein.
6
+ :license: MIT, see LICENSE for details.
7
+ """
8
+
9
+ from __future__ import annotations
@@ -0,0 +1,39 @@
1
+ """Basic Sphinx Theme.
2
+
3
+ .. moduleauthor:: Michael Rippstein <info@anatas.ch>
4
+
5
+ :copyright: Copyright 2026 by Michael Rippstein.
6
+ :license: MIT, see LICENSE for details.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from importlib.metadata import version as lib_version
12
+ from pathlib import Path
13
+ from typing import TYPE_CHECKING, Any
14
+
15
+ if TYPE_CHECKING:
16
+ from docutils import nodes
17
+ from sphinx.application import Sphinx
18
+
19
+
20
+ def add_theme_version(
21
+ app: Sphinx, # ruff: ignore[unused-function-argument]
22
+ pagename: str, # ruff: ignore[unused-function-argument]
23
+ templatename: str, # ruff: ignore[unused-function-argument]
24
+ context: dict[str, Any],
25
+ doctree: nodes.document, # ruff: ignore[unused-function-argument]
26
+ ) -> None:
27
+ """Update template names and assets for page build."""
28
+ # Update version number for the "made with version..." component
29
+ context['mr_theme_version'] = lib_version('mr_theme')
30
+
31
+
32
+ def setup(app: Sphinx) -> None:
33
+ """Setup the Sphinx application.
34
+
35
+ .. codeauthor:: Michael Rippstein <info@anatas.ch>
36
+ """
37
+ app.add_html_theme('mr_theme', Path(__file__).resolve().parent)
38
+
39
+ app.connect('html-page-context', add_theme_version)
@@ -0,0 +1,27 @@
1
+ {# Displays the copyright information (which is defined in conf.py). #}
2
+
3
+ {%- macro copyright_block() %}
4
+ {%- if hasdoc('copyright') %}
5
+ {%- set copyright_prefix = '<a href="' + pathto('copyright') + '">' + _('Copyright') + '</a>' -%}
6
+ {%- else %}
7
+ {%- set copyright_prefix = _('Copyright') %}
8
+ {%- endif %}
9
+ {%- if copyright is iterable and copyright is not string %}
10
+ {% for copyright_line in copyright %}
11
+ {% trans trimmed copyright_prefix=copyright_prefix, copyright=copyright_line|e %}
12
+ &#169; {{ copyright_prefix }} {{ copyright }}.
13
+ {% endtrans %}
14
+ {%- if not loop.last %}<br />{%- endif %}
15
+ {% endfor %}
16
+ {%- else %}
17
+ {% trans trimmed copyright_prefix=copyright_prefix, copyright=copyright|e %}
18
+ &#169; {{ copyright_prefix }} {{ copyright }}.
19
+ {% endtrans %}
20
+ {%- endif %}
21
+ {%- endmacro %}
22
+
23
+ {% if show_copyright and copyright %}
24
+ <p class="copyright">
25
+ {{- copyright_block() -}}
26
+ </p>
27
+ {% endif %}
File without changes
@@ -0,0 +1,6 @@
1
+ {# Displays the version of pydata-sphinx-theme used to build the documentation. #}
2
+ <p class="theme-version">
3
+ Built with <a href="https://gitlab.com/anatas_ch/pyl_mrtheme2">mr-theme</a> {{ mr_theme_version }}<br>
4
+ based on the <a href="https://pydata-sphinx-theme.readthedocs.io/en/stable/index.html">PyData Sphinx Theme</a>
5
+ {{ theme_version }}.
6
+ </p>
@@ -0,0 +1,13 @@
1
+ # :author: Michael Rippstein <info@anatas.ch>
2
+ # :copyright: Copyright 2026 by Michael Rippstein.
3
+ # :license: MIT, see LICENSE for details.
4
+
5
+ [theme]
6
+ inherit = "pydata_sphinx_theme"
7
+
8
+ [options]
9
+ 'navbar_center' = ['version', 'navbar-nav']
10
+ 'navbar_end' = ['navbar-icon-links']
11
+ 'primary_sidebar_end' = ['indices.html', 'sidebar-ethical-ads.html']
12
+ 'footer_start' = ['copyright_mr_theme']
13
+ 'footer_end' = ['sphinx-version', 'theme-version-mr-theme']
@@ -0,0 +1,4 @@
1
+ {# This will display the version of the docs #}
2
+ <div class="version-switcher__container version">
3
+ Version {{ release }}
4
+ </div>
@@ -0,0 +1,390 @@
1
+ """The MR ``matplotlib`` styles.
2
+
3
+ .. moduleauthor:: Michael Rippstein <info@anatas.ch>
4
+
5
+ :copyright: Copyright 2026 by Michael Rippstein.
6
+ :license: MIT, see LICENSE for details.
7
+
8
+ The «mr_general»-style
9
+ ----------------------
10
+
11
+ .. plot::
12
+
13
+ import matplotlib as mpl
14
+ import matplotlib.pyplot as plt
15
+ import numpy as np
16
+
17
+ import mr_theme.mpl_style
18
+
19
+ th = np.linspace(0, 2*np.pi, 128)
20
+
21
+ def demo(sty):
22
+ mpl.style.use(sty)
23
+ fig, ax = plt.subplots(figsize=(3, 3))
24
+
25
+ ax.set_title(f'style: {sty!r}')
26
+
27
+ ax.plot(th, np.cos(th), label='C0')
28
+ ax.plot(th, np.sin(th), label='C1')
29
+ ax.legend()
30
+
31
+
32
+ demo('default')
33
+ demo('mr_theme.mpl_style.mr_general')
34
+
35
+ Colors
36
+ ------
37
+
38
+ .. plot::
39
+ :include-source: False
40
+ :caption: The «MR» colors.
41
+
42
+ import matplotlib.pyplot as plt
43
+ from mr_theme.mpl_style import plot_color_table
44
+
45
+ plt.style.use('mr_theme.mpl_style.mr_general')
46
+ fig = plot_color_table(
47
+ [
48
+ 'mr:brown',
49
+ 'mr:red',
50
+ 'mr:orange',
51
+ 'mr:yellow',
52
+ 'mr:green',
53
+ 'mr:blue',
54
+ 'mr:violet',
55
+ 'mr:gray',
56
+ 'mr:white',
57
+ 'mr:black',
58
+ 'mr:gold',
59
+ 'mr:silver',
60
+ 'mr:pink',
61
+ 'mr:olive',
62
+ 'mr:cyan',
63
+ 'mr:pass',
64
+ 'mr:fail',
65
+ ],
66
+ [
67
+ 'mr:brown / mr:bn',
68
+ 'mr:red / mr:rd',
69
+ 'mr:orange / mr:og',
70
+ 'mr:yellow / mr:ye',
71
+ 'mr:green / mr:gn',
72
+ 'mr:blue / mr:bu',
73
+ 'mr:violet / mr:vi',
74
+ 'mr:gray / mr:gy',
75
+ 'mr:white / mr:wh',
76
+ 'mr:black / mr:bk',
77
+ 'mr:gold / mr:gd',
78
+ 'mr:silver / mr:sr',
79
+ 'mr:pink / mr:pk',
80
+ 'mr:olive',
81
+ 'mr:cyan / mr:turquoise / mr:tq',
82
+ 'mr:pass',
83
+ 'mr:fail',
84
+ ],
85
+ )
86
+
87
+ .. plot::
88
+ :include-source: False
89
+ :caption: The «MR» colors.
90
+
91
+ import matplotlib.pyplot as plt
92
+
93
+ from mr_theme.mpl_style import plot_color_table
94
+
95
+ plt.style.use('mr_theme.mpl_style.mr_general')
96
+ fig = plot_color_table(
97
+ [
98
+ 'mr:prim', 'mr:prim80', 'mr:prim60', 'mr:prim40', 'mr:prim20',
99
+ 'mr:seca', 'mr:seca80', 'mr:seca60', 'mr:seca40', 'mr:seca20',
100
+ 'mr:comp',
101
+ ],
102
+ ncols=5,
103
+ )
104
+
105
+ .. plot::
106
+ :include-source: False
107
+ :caption: The functional color names.
108
+
109
+ import matplotlib.pyplot as plt
110
+ from mr_theme.mpl_style import plot_color_table
111
+
112
+ plt.style.use('mr_theme.mpl_style.mr_general')
113
+ fig = plot_color_table(
114
+ [
115
+ 'mr:func:bgdark',
116
+ 'mr:func:bglight',
117
+ 'mr:func:grid',
118
+ 'mr:func:text',
119
+ 'mr:func:title'
120
+ ],
121
+ )
122
+
123
+ .. plot::
124
+ :include-source: False
125
+ :caption: The default color cycle.
126
+
127
+ import matplotlib.pyplot as plt
128
+ from mr_theme.mpl_style import plot_color_table, DEFAULT_CYCLE_COLORS
129
+
130
+ plt.style.use('mr_theme.mpl_style.mr_general')
131
+ fig = plot_color_table(DEFAULT_CYCLE_COLORS)
132
+ """
133
+
134
+ from __future__ import annotations
135
+
136
+ import math
137
+ from typing import TYPE_CHECKING, Any, Literal
138
+
139
+ import matplotlib as mpl
140
+ from matplotlib import pyplot as plt
141
+ from matplotlib.colors import ( # type: ignore
142
+ ListedColormap,
143
+ _colors_full_map, # ruff: ignore[import-private-name]
144
+ )
145
+ from matplotlib.patches import Rectangle
146
+
147
+ if TYPE_CHECKING:
148
+ from matplotlib.axes import Axes
149
+ from matplotlib.figure import Figure
150
+ from matplotlib.text import Text
151
+
152
+ MR_COLORS = {
153
+ 'mr:brown': '#8c564b', # 1
154
+ 'mr:red': '#D62728', # 2
155
+ 'mr:orange': '#FF7F0E', # 3
156
+ 'mr:yellow': '#FFF200', # 4
157
+ 'mr:green': '#2CA02C', # 5
158
+ 'mr:blue': '#1F77B4', # 6
159
+ 'mr:violet': '#9467BD', # 7
160
+ 'mr:gray': '#7f7f7f', # 8
161
+ 'mr:white': '#e3d9c6', # 9
162
+ 'mr:black': '#1f1f1f', # 0
163
+ 'mr:gold': '#FFCE0A',
164
+ 'mr:silver': '#E1E2E3',
165
+ 'mr:pink': '#e377c2',
166
+ 'mr:olive': '#bcbd22',
167
+ 'mr:cyan': '#17becf',
168
+ 'mr:pass': '#1BC237',
169
+ 'mr:fail': '#E31E1E',
170
+ 'mr:prim': '#005083',
171
+ 'mr:prim80': '#33739C',
172
+ 'mr:prim60': '#6696B4',
173
+ 'mr:prim40': '#99B9CD',
174
+ 'mr:prim20': '#CCDCE6',
175
+ 'mr:seca': '#3FB498',
176
+ 'mr:seca80': '#65C3AD',
177
+ 'mr:seca60': '#8BD2C1',
178
+ 'mr:seca40': '#B2E1D6',
179
+ 'mr:seca20': '#D8F0EA',
180
+ 'mr:comp': '#824C00',
181
+ 'mr:func:bgdark': '#333333',
182
+ 'mr:func:bglight': '#F2F2F2',
183
+ 'mr:func:grid': '#808080',
184
+ 'mr:func:text': '#585858',
185
+ }
186
+ MR_COLORS.update({
187
+ 'mr:bn': MR_COLORS['mr:brown'],
188
+ 'mr:rd': MR_COLORS['mr:red'],
189
+ 'mr:og': MR_COLORS['mr:orange'],
190
+ 'mr:ye': MR_COLORS['mr:yellow'],
191
+ 'mr:gn': MR_COLORS['mr:green'],
192
+ 'mr:bu': MR_COLORS['mr:blue'],
193
+ 'mr:vt': MR_COLORS['mr:violet'],
194
+ 'mr:gy': MR_COLORS['mr:gray'],
195
+ 'mr:wh': MR_COLORS['mr:white'],
196
+ 'mr:bk': MR_COLORS['mr:black'],
197
+ 'mr:gd': MR_COLORS['mr:gold'],
198
+ 'mr:sr': MR_COLORS['mr:silver'],
199
+ 'mr:pk': MR_COLORS['mr:pink'],
200
+ 'mr:tq': MR_COLORS['mr:cyan'],
201
+ 'mr:turquoise': MR_COLORS['mr:cyan'],
202
+ 'mr:func:title': MR_COLORS['mr:prim'],
203
+ })
204
+
205
+ _colors_full_map.update(MR_COLORS)
206
+
207
+ DEFAULT_CYCLE_COLORS = [
208
+ 'mr:brown',
209
+ 'mr:red',
210
+ 'mr:orange',
211
+ 'mr:yellow',
212
+ 'mr:green',
213
+ 'mr:blue',
214
+ 'mr:violet',
215
+ 'mr:gray',
216
+ 'mr:pink',
217
+ 'mr:olive',
218
+ ]
219
+ """This constant is only for the documentation of the color cycle used by the ``mr_general`` style."""
220
+
221
+ mr_cmap = ListedColormap(DEFAULT_CYCLE_COLORS, name='mr_cmap')
222
+ mpl.colormaps.register(cmap=mr_cmap)
223
+
224
+
225
+ def figure_title(fig: Figure, title: str, **kw_args: Any) -> Text:
226
+ """Format the figure title according to the style guide.
227
+
228
+ .. codeauthor:: Michael Rippstein <info@anatas.ch>
229
+
230
+ Parameters
231
+ ----------
232
+ fig: matplotlib.figure.Figure
233
+ A `matplotlib` figure object.
234
+ title
235
+ Title of the diagram.
236
+
237
+ Returns
238
+ -------
239
+ matplotlib.text.Text
240
+ The `matplotlib` text object.
241
+
242
+ Other Parameters
243
+ ----------------
244
+ **kw_args
245
+ Additional `kw_args` are :meth:`~matplotlib.figure.Figure.suptitle` or
246
+ :class:`~matplotlib.text.Text` properties.
247
+ The properties ``size`` (``fontsize``), ``weight`` (``fontweight``) and
248
+ ``color`` (``c``) are not allowed!
249
+
250
+ See Also
251
+ --------
252
+ matplotlib.figure.Figure.suptitle
253
+ """
254
+ return fig.suptitle(title, size='x-large', weight='bold', color='mr:func:title', **kw_args)
255
+
256
+
257
+ def axes_ticks_grid(ax: Axes, axis: Literal['both', 'x', 'y'] = 'both') -> None:
258
+ """Switch on the minorticks and format the minor grid lines.
259
+
260
+ .. codeauthor:: Michael Rippstein <info@anatas.ch>
261
+
262
+ Parameters
263
+ ----------
264
+ ax : matplotlib.axes.Axes
265
+ The axes object
266
+ axis
267
+ On which axis the minor grid is draw, by default on both.
268
+ """
269
+ ax.minorticks_on()
270
+ ax.grid(visible=True, which='both', axis=axis)
271
+ ax.grid(which='minor', axis=axis, linestyle=':')
272
+
273
+
274
+ def plot_color_table( # ruff: ignore[too-many-locals]
275
+ colors: list[str], labels: list[str] | None = None, *, ncols: int = 4, **kw_args: int
276
+ ) -> Figure:
277
+ """Plot color table for the documentation.
278
+
279
+ .. codeauthor:: Michael Rippstein <info@anatas.ch>
280
+
281
+ Parameters
282
+ ----------
283
+ colors
284
+ A list of valid colors name.
285
+ labels
286
+ A list of labels to name the colors. The list must have the same length as the `colors` list.
287
+ By default the strings in the `colors` list is used to print the colors name.
288
+ ncols
289
+ The number of columns, by default 4.
290
+
291
+ Keyword Arguments
292
+ -----------------
293
+ cell_width : int
294
+ The width of one cell, by default 240 pixel.
295
+ cell_height : int
296
+ The height of one cell, by default 22 pixel.
297
+ swatch_width : int
298
+ The width of the colour swatch, by default 48 pixel.
299
+ swatch_height : int
300
+ The height of the colour swatch, by default 18 pixel.
301
+ Must by a even number smaller than the `cell_height`.
302
+ margin : int
303
+ The margin around the table, by default 12 pixel.
304
+ dpi : int
305
+ The dpi of the image, by default 96.
306
+ fontsize : int
307
+ The fontsize, by default 14 pixel.
308
+ Must by a even number smaller than the `cell_height`.
309
+
310
+ Returns
311
+ -------
312
+ matplotlib.figure.Figure
313
+ A matplotlib figure object.
314
+ """
315
+ if labels is None:
316
+ labels = colors
317
+ cell_width = kw_args.get('cell_width', 240)
318
+ cell_height = kw_args.get('cell_height', 22)
319
+ swatch_width = kw_args.get('swatch_width', 48)
320
+ swatch_height = kw_args.get('swatch_height', 18)
321
+ margin = kw_args.get('margin', 12)
322
+ dpi = kw_args.get('dpi', 96)
323
+ fontsize = kw_args.get('fontsize', 14)
324
+ n = len(colors)
325
+ nrows = math.ceil(n / ncols)
326
+ width = cell_width * ncols + 2 * margin
327
+ height = cell_height * nrows + 2 * margin
328
+ fig, ax = plt.subplots(figsize=(width / dpi, height / dpi), dpi=dpi)
329
+ fig.subplots_adjust(
330
+ margin / width,
331
+ margin / height,
332
+ (width - margin) / width,
333
+ (height - margin) / height,
334
+ )
335
+ ax.set_xlim(0, cell_width * ncols)
336
+ ax.set_ylim(cell_height * (nrows - 0.5), -cell_height / 2.0)
337
+ ax.yaxis.set_visible(False)
338
+ ax.xaxis.set_visible(False)
339
+ ax.set_axis_off()
340
+ for i, (name, label) in enumerate(zip(colors, labels, strict=True)):
341
+ row = i % nrows
342
+ col = i // nrows
343
+ y = row * cell_height
344
+ swatch_start_x = cell_width * col
345
+ text_pos_x = cell_width * col + swatch_width + fontsize // 2
346
+ ax.text(
347
+ text_pos_x,
348
+ y,
349
+ label,
350
+ fontsize=fontsize,
351
+ horizontalalignment='left',
352
+ verticalalignment='center',
353
+ )
354
+ ax.add_patch(
355
+ Rectangle(
356
+ xy=(swatch_start_x, y - swatch_height // 2),
357
+ width=swatch_width,
358
+ height=swatch_height,
359
+ facecolor=name,
360
+ edgecolor='0.7',
361
+ )
362
+ )
363
+ return fig
364
+
365
+
366
+ def fig_text_info_note(fig: Figure, text: str) -> Text:
367
+ """Print a text in the bottom right corner of a `matplotlib` figure.
368
+
369
+ .. codeauthor:: Michael Rippstein <info@anatas.ch>
370
+
371
+ Parameters
372
+ ----------
373
+ fig: matplotlib.figure.Figure
374
+ A `matplotlib` figure object.
375
+ text
376
+ serial number
377
+
378
+ Returns
379
+ -------
380
+ matplotlib.text.Text
381
+ The `matplotlib` text object.
382
+ """
383
+ return fig.text(
384
+ 0.99,
385
+ 0.01,
386
+ text,
387
+ color='mr:func:text',
388
+ verticalalignment='bottom',
389
+ horizontalalignment='right',
390
+ )