ggplot2-python 4.0.2.9000__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.
Files changed (54) hide show
  1. ggplot2_py/__init__.py +852 -0
  2. ggplot2_py/_compat.py +475 -0
  3. ggplot2_py/_plugins.py +129 -0
  4. ggplot2_py/_utils.py +544 -0
  5. ggplot2_py/aes.py +586 -0
  6. ggplot2_py/annotation.py +540 -0
  7. ggplot2_py/coord.py +2108 -0
  8. ggplot2_py/coords/__init__.py +49 -0
  9. ggplot2_py/datasets.py +265 -0
  10. ggplot2_py/draw_key.py +454 -0
  11. ggplot2_py/facet.py +1456 -0
  12. ggplot2_py/fortify.py +95 -0
  13. ggplot2_py/geom.py +4516 -0
  14. ggplot2_py/geoms/__init__.py +12 -0
  15. ggplot2_py/ggproto.py +279 -0
  16. ggplot2_py/guide.py +2925 -0
  17. ggplot2_py/guide_axis.py +615 -0
  18. ggplot2_py/guide_colourbar.py +657 -0
  19. ggplot2_py/guide_legend.py +1061 -0
  20. ggplot2_py/guides/__init__.py +8 -0
  21. ggplot2_py/labeller.py +296 -0
  22. ggplot2_py/labels.py +309 -0
  23. ggplot2_py/layer.py +954 -0
  24. ggplot2_py/layout.py +754 -0
  25. ggplot2_py/limits.py +314 -0
  26. ggplot2_py/plot.py +1401 -0
  27. ggplot2_py/plot_render.py +866 -0
  28. ggplot2_py/position.py +1269 -0
  29. ggplot2_py/protocols.py +171 -0
  30. ggplot2_py/py.typed +0 -0
  31. ggplot2_py/qplot.py +233 -0
  32. ggplot2_py/resources/diamonds.csv +53941 -0
  33. ggplot2_py/resources/economics.csv +575 -0
  34. ggplot2_py/resources/economics_long.csv +2871 -0
  35. ggplot2_py/resources/faithfuld.csv +5626 -0
  36. ggplot2_py/resources/luv_colours.csv +658 -0
  37. ggplot2_py/resources/midwest.csv +438 -0
  38. ggplot2_py/resources/mpg.csv +235 -0
  39. ggplot2_py/resources/msleep.csv +84 -0
  40. ggplot2_py/resources/presidential.csv +13 -0
  41. ggplot2_py/resources/seals.csv +1156 -0
  42. ggplot2_py/resources/txhousing.csv +8603 -0
  43. ggplot2_py/save.py +316 -0
  44. ggplot2_py/scale.py +2727 -0
  45. ggplot2_py/scales/__init__.py +4252 -0
  46. ggplot2_py/stat.py +6071 -0
  47. ggplot2_py/stats/__init__.py +9 -0
  48. ggplot2_py/theme.py +490 -0
  49. ggplot2_py/theme_defaults.py +1350 -0
  50. ggplot2_py/theme_elements.py +2052 -0
  51. ggplot2_python-4.0.2.9000.dist-info/METADATA +179 -0
  52. ggplot2_python-4.0.2.9000.dist-info/RECORD +54 -0
  53. ggplot2_python-4.0.2.9000.dist-info/WHEEL +4 -0
  54. ggplot2_python-4.0.2.9000.dist-info/licenses/LICENSE +3 -0
@@ -0,0 +1,1350 @@
1
+ """
2
+ Built-in complete themes for ggplot2.
3
+
4
+ Each function returns a ``Theme`` with all elements defined.
5
+ ``theme_grey()`` is the base default; all others derive from it.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Optional
11
+
12
+ from grid_py import Unit
13
+
14
+ from ggplot2_py.theme_elements import (
15
+ element_blank,
16
+ element_line,
17
+ element_rect,
18
+ element_text,
19
+ element_point,
20
+ element_polygon,
21
+ element_geom,
22
+ margin,
23
+ margin_auto,
24
+ rel,
25
+ )
26
+ from ggplot2_py.theme import Theme, theme, theme_replace_op
27
+
28
+ __all__ = [
29
+ "theme_grey",
30
+ "theme_gray",
31
+ "theme_bw",
32
+ "theme_linedraw",
33
+ "theme_light",
34
+ "theme_dark",
35
+ "theme_minimal",
36
+ "theme_classic",
37
+ "theme_void",
38
+ "theme_test",
39
+ "theme_sub_axis",
40
+ "theme_sub_axis_x",
41
+ "theme_sub_axis_y",
42
+ "theme_sub_axis_top",
43
+ "theme_sub_axis_bottom",
44
+ "theme_sub_axis_left",
45
+ "theme_sub_axis_right",
46
+ "theme_sub_legend",
47
+ "theme_sub_panel",
48
+ "theme_sub_plot",
49
+ "theme_sub_strip",
50
+ ]
51
+
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # Colour mixing helper
55
+ # ---------------------------------------------------------------------------
56
+
57
+ def _col_mix(ink: str, paper: str, amount: float) -> str:
58
+ """Mix *ink* and *paper* colours.
59
+
60
+ Parameters
61
+ ----------
62
+ ink : str
63
+ Foreground colour (e.g. ``"black"``).
64
+ paper : str
65
+ Background colour (e.g. ``"white"``).
66
+ amount : float
67
+ Fraction of *paper* to blend in (0 = pure ink, 1 = pure paper).
68
+
69
+ Returns
70
+ -------
71
+ str
72
+ A hex colour string.
73
+ """
74
+ import matplotlib.colors as mcolors
75
+ import numpy as np
76
+
77
+ try:
78
+ c_ink = np.array(mcolors.to_rgba(ink))
79
+ c_paper = np.array(mcolors.to_rgba(paper))
80
+ except ValueError:
81
+ # Fallback for colours matplotlib cannot parse
82
+ return ink
83
+
84
+ mixed = c_ink * (1 - amount) + c_paper * amount
85
+ mixed = np.clip(mixed, 0, 1)
86
+ return mcolors.to_hex(mixed, keep_alpha=True)
87
+
88
+
89
+ # ---------------------------------------------------------------------------
90
+ # Helper to build an all-None theme (mimics ggplot_global$theme_all_null)
91
+ # ---------------------------------------------------------------------------
92
+
93
+ def _theme_all_null() -> Theme:
94
+ """Return a complete theme with every element set to ``None``.
95
+
96
+ This is used by complete themes so that elements not explicitly set
97
+ in the theme definition become ``None`` rather than being missing.
98
+
99
+ Returns
100
+ -------
101
+ Theme
102
+ """
103
+ from ggplot2_py.theme_elements import get_element_tree
104
+
105
+ elements = {name: None for name in get_element_tree()}
106
+ return Theme(elements=elements, complete=True, validate=False)
107
+
108
+
109
+ # ---------------------------------------------------------------------------
110
+ # theme_grey / theme_gray
111
+ # ---------------------------------------------------------------------------
112
+
113
+ def theme_grey(
114
+ base_size: float = 11,
115
+ base_family: str = "",
116
+ header_family: Optional[str] = None,
117
+ base_line_size: Optional[float] = None,
118
+ base_rect_size: Optional[float] = None,
119
+ ink: str = "black",
120
+ paper: str = "white",
121
+ accent: str = "#3366FF",
122
+ ) -> Theme:
123
+ """The default ggplot2 theme with grey background and white gridlines.
124
+
125
+ Parameters
126
+ ----------
127
+ base_size : float
128
+ Base font size in points (default 11).
129
+ base_family : str
130
+ Base font family.
131
+ header_family : str or None
132
+ Font family for titles and headers.
133
+ base_line_size : float or None
134
+ Base size for line elements (default ``base_size / 22``).
135
+ base_rect_size : float or None
136
+ Base size for rect elements (default ``base_size / 22``).
137
+ ink : str
138
+ Foreground colour (default ``"black"``).
139
+ paper : str
140
+ Background colour (default ``"white"``).
141
+ accent : str
142
+ Accent colour (default ``"#3366FF"``).
143
+
144
+ Returns
145
+ -------
146
+ Theme
147
+ A complete theme.
148
+ """
149
+ if base_line_size is None:
150
+ base_line_size = base_size / 22
151
+ if base_rect_size is None:
152
+ base_rect_size = base_size / 22
153
+
154
+ half_line = base_size / 2
155
+
156
+ t = theme(
157
+ complete=True,
158
+ # Root elements
159
+ line=element_line(
160
+ colour=ink,
161
+ linewidth=base_line_size,
162
+ linetype=1,
163
+ lineend="butt",
164
+ linejoin="round",
165
+ ),
166
+ rect=element_rect(
167
+ fill=paper,
168
+ colour=ink,
169
+ linewidth=base_rect_size,
170
+ linetype=1,
171
+ linejoin="round",
172
+ ),
173
+ text=element_text(
174
+ family=base_family,
175
+ face="plain",
176
+ colour=ink,
177
+ size=base_size,
178
+ lineheight=0.9,
179
+ hjust=0.5,
180
+ vjust=0.5,
181
+ angle=0,
182
+ margin=margin(),
183
+ debug=False,
184
+ ),
185
+ title=element_text(family=header_family),
186
+ spacing=Unit(half_line, "pt"),
187
+ margins=margin_auto(half_line),
188
+ point=element_point(
189
+ colour=ink,
190
+ shape=19,
191
+ fill=paper,
192
+ size=(base_size / 11) * 1.5,
193
+ stroke=base_line_size,
194
+ ),
195
+ polygon=element_polygon(
196
+ fill=paper,
197
+ colour=ink,
198
+ linewidth=base_rect_size,
199
+ linetype=1,
200
+ linejoin="round",
201
+ ),
202
+ geom=element_geom(
203
+ ink=ink,
204
+ paper=paper,
205
+ accent=accent,
206
+ linewidth=base_line_size,
207
+ borderwidth=base_line_size,
208
+ linetype=1,
209
+ bordertype=1,
210
+ family=base_family,
211
+ fontsize=base_size,
212
+ pointsize=(base_size / 11) * 1.5,
213
+ pointshape=19,
214
+ ),
215
+
216
+ # Axis lines
217
+ axis_line=element_blank(),
218
+ axis_line_x=None,
219
+ axis_line_y=None,
220
+
221
+ # Axis text
222
+ axis_text=element_text(
223
+ size=rel(0.8),
224
+ colour=_col_mix(ink, paper, 0.302),
225
+ ),
226
+ axis_text_x=element_text(
227
+ margin=margin(t=0.8 * half_line / 2),
228
+ vjust=1,
229
+ ),
230
+ axis_text_x_top=element_text(
231
+ margin=margin(b=0.8 * half_line / 2),
232
+ vjust=0,
233
+ ),
234
+ axis_text_y=element_text(
235
+ margin=margin(r=0.8 * half_line / 2),
236
+ hjust=1,
237
+ ),
238
+ axis_text_y_right=element_text(
239
+ margin=margin(l=0.8 * half_line / 2),
240
+ hjust=0,
241
+ ),
242
+ axis_text_r=element_text(
243
+ margin=margin(l=0.8 * half_line / 2, r=0.8 * half_line / 2),
244
+ hjust=0.5,
245
+ ),
246
+
247
+ # Axis ticks
248
+ axis_ticks=element_line(colour=_col_mix(ink, paper, 0.2)),
249
+ axis_ticks_length=rel(0.5),
250
+ axis_ticks_length_x=None,
251
+ axis_ticks_length_x_top=None,
252
+ axis_ticks_length_x_bottom=None,
253
+ axis_ticks_length_y=None,
254
+ axis_ticks_length_y_left=None,
255
+ axis_ticks_length_y_right=None,
256
+ axis_minor_ticks_length=rel(0.75),
257
+
258
+ # Axis titles
259
+ axis_title_x=element_text(
260
+ margin=margin(t=half_line / 2),
261
+ vjust=1,
262
+ ),
263
+ axis_title_x_top=element_text(
264
+ margin=margin(b=half_line / 2),
265
+ vjust=0,
266
+ ),
267
+ axis_title_y=element_text(
268
+ angle=90,
269
+ margin=margin(r=half_line / 2),
270
+ vjust=1,
271
+ ),
272
+ axis_title_y_right=element_text(
273
+ angle=-90,
274
+ margin=margin(l=half_line / 2),
275
+ vjust=1,
276
+ ),
277
+
278
+ # Legend
279
+ legend_background=element_rect(colour=None),
280
+ legend_spacing=rel(2),
281
+ legend_spacing_x=None,
282
+ legend_spacing_y=None,
283
+ legend_margin=None,
284
+ legend_key=None,
285
+ legend_key_size=Unit(1.2, "lines"),
286
+ legend_key_height=None,
287
+ legend_key_width=None,
288
+ legend_key_spacing=None,
289
+ legend_text=element_text(size=rel(0.8)),
290
+ legend_title=element_text(hjust=0),
291
+ legend_ticks_length=rel(0.2),
292
+ legend_position="right",
293
+ legend_direction=None,
294
+ legend_justification="center",
295
+ legend_box=None,
296
+ legend_box_margin=margin_auto(0),
297
+ legend_box_background=element_blank(),
298
+ legend_box_spacing=rel(2),
299
+
300
+ # Panel
301
+ panel_background=element_rect(
302
+ fill=_col_mix(ink, paper, 0.92),
303
+ colour=None,
304
+ ),
305
+ panel_border=element_blank(),
306
+ panel_grid=element_line(colour=paper),
307
+ panel_grid_minor=element_line(linewidth=rel(0.5)),
308
+ panel_spacing=None,
309
+ panel_spacing_x=None,
310
+ panel_spacing_y=None,
311
+ panel_ontop=False,
312
+
313
+ # Strip
314
+ strip_background=element_rect(
315
+ fill=_col_mix(ink, paper, 0.85),
316
+ colour=None,
317
+ ),
318
+ strip_clip="on",
319
+ strip_text=element_text(
320
+ colour=_col_mix(ink, paper, 0.1),
321
+ size=rel(0.8),
322
+ margin=margin_auto(0.8 * half_line),
323
+ ),
324
+ strip_text_x=None,
325
+ strip_text_y=element_text(angle=-90),
326
+ strip_text_y_left=element_text(angle=90),
327
+ strip_placement="inside",
328
+ strip_placement_x=None,
329
+ strip_placement_y=None,
330
+ strip_switch_pad_grid=Unit(half_line / 2, "pt"),
331
+ strip_switch_pad_wrap=Unit(half_line / 2, "pt"),
332
+
333
+ # Plot
334
+ plot_background=element_rect(colour=paper),
335
+ plot_title=element_text(
336
+ size=rel(1.2),
337
+ hjust=0,
338
+ vjust=1,
339
+ margin=margin(b=half_line),
340
+ ),
341
+ plot_title_position="panel",
342
+ plot_subtitle=element_text(
343
+ hjust=0,
344
+ vjust=1,
345
+ margin=margin(b=half_line),
346
+ ),
347
+ plot_caption=element_text(
348
+ size=rel(0.8),
349
+ hjust=1,
350
+ vjust=1,
351
+ margin=margin(t=half_line),
352
+ ),
353
+ plot_caption_position="panel",
354
+ plot_tag=element_text(
355
+ size=rel(1.2),
356
+ hjust=0.5,
357
+ vjust=0.5,
358
+ ),
359
+ plot_tag_position="topleft",
360
+ plot_margin=None,
361
+ )
362
+
363
+ # Merge onto the all-null base so unset elements become None
364
+ base = _theme_all_null()
365
+ return theme_replace_op(base, t)
366
+
367
+
368
+ # Alias
369
+ theme_gray = theme_grey
370
+
371
+
372
+ # ---------------------------------------------------------------------------
373
+ # theme_bw
374
+ # ---------------------------------------------------------------------------
375
+
376
+ def theme_bw(
377
+ base_size: float = 11,
378
+ base_family: str = "",
379
+ header_family: Optional[str] = None,
380
+ base_line_size: Optional[float] = None,
381
+ base_rect_size: Optional[float] = None,
382
+ ink: str = "black",
383
+ paper: str = "white",
384
+ accent: str = "#3366FF",
385
+ ) -> Theme:
386
+ """Classic dark-on-light theme with a white panel and dark border.
387
+
388
+ Parameters
389
+ ----------
390
+ base_size : float
391
+ Base font size in points.
392
+ base_family : str
393
+ Base font family.
394
+ header_family : str or None
395
+ Header font family.
396
+ base_line_size : float or None
397
+ Base line size.
398
+ base_rect_size : float or None
399
+ Base rect size.
400
+ ink : str
401
+ Foreground colour.
402
+ paper : str
403
+ Background colour.
404
+ accent : str
405
+ Accent colour.
406
+
407
+ Returns
408
+ -------
409
+ Theme
410
+ """
411
+ base = theme_grey(
412
+ base_size=base_size,
413
+ base_family=base_family,
414
+ header_family=header_family,
415
+ base_line_size=base_line_size,
416
+ base_rect_size=base_rect_size,
417
+ ink=ink,
418
+ paper=paper,
419
+ accent=accent,
420
+ )
421
+ override = theme(
422
+ complete=True,
423
+ panel_background=element_rect(fill=paper, colour=None),
424
+ panel_border=element_rect(colour=_col_mix(ink, paper, 0.2)),
425
+ panel_grid=element_line(colour=_col_mix(ink, paper, 0.92)),
426
+ panel_grid_minor=element_line(linewidth=rel(0.5)),
427
+ strip_background=element_rect(
428
+ fill=_col_mix(ink, paper, 0.851),
429
+ colour=_col_mix(ink, paper, 0.2),
430
+ ),
431
+ )
432
+ return theme_replace_op(base, override)
433
+
434
+
435
+ # ---------------------------------------------------------------------------
436
+ # theme_linedraw
437
+ # ---------------------------------------------------------------------------
438
+
439
+ def theme_linedraw(
440
+ base_size: float = 11,
441
+ base_family: str = "",
442
+ header_family: Optional[str] = None,
443
+ base_line_size: Optional[float] = None,
444
+ base_rect_size: Optional[float] = None,
445
+ ink: str = "black",
446
+ paper: str = "white",
447
+ accent: str = "#3366FF",
448
+ ) -> Theme:
449
+ """A theme with only black lines of various widths on white backgrounds.
450
+
451
+ Parameters
452
+ ----------
453
+ base_size : float
454
+ Base font size in points.
455
+ base_family : str
456
+ Base font family.
457
+ header_family : str or None
458
+ Header font family.
459
+ base_line_size : float or None
460
+ Base line size.
461
+ base_rect_size : float or None
462
+ Base rect size.
463
+ ink : str
464
+ Foreground colour.
465
+ paper : str
466
+ Background colour.
467
+ accent : str
468
+ Accent colour.
469
+
470
+ Returns
471
+ -------
472
+ Theme
473
+ """
474
+ half_line = base_size / 2
475
+
476
+ base = theme_bw(
477
+ base_size=base_size,
478
+ base_family=base_family,
479
+ header_family=header_family,
480
+ base_line_size=base_line_size,
481
+ base_rect_size=base_rect_size,
482
+ ink=ink,
483
+ paper=paper,
484
+ accent=accent,
485
+ )
486
+ override = theme(
487
+ complete=True,
488
+ axis_text=element_text(colour=ink, size=rel(0.8)),
489
+ axis_ticks=element_line(colour=ink, linewidth=rel(0.5)),
490
+ panel_border=element_rect(colour=ink, linewidth=rel(1)),
491
+ panel_grid=element_line(colour=ink),
492
+ panel_grid_major=element_line(linewidth=rel(0.1)),
493
+ panel_grid_minor=element_line(linewidth=rel(0.05)),
494
+ strip_background=element_rect(fill=ink),
495
+ strip_text=element_text(
496
+ colour=paper,
497
+ size=rel(0.8),
498
+ margin=margin_auto(0.8 * half_line),
499
+ ),
500
+ )
501
+ return theme_replace_op(base, override)
502
+
503
+
504
+ # ---------------------------------------------------------------------------
505
+ # theme_light
506
+ # ---------------------------------------------------------------------------
507
+
508
+ def theme_light(
509
+ base_size: float = 11,
510
+ base_family: str = "",
511
+ header_family: Optional[str] = None,
512
+ base_line_size: Optional[float] = None,
513
+ base_rect_size: Optional[float] = None,
514
+ ink: str = "black",
515
+ paper: str = "white",
516
+ accent: str = "#3366FF",
517
+ ) -> Theme:
518
+ """A theme similar to ``theme_linedraw`` but with light grey lines.
519
+
520
+ Parameters
521
+ ----------
522
+ base_size : float
523
+ Base font size in points.
524
+ base_family : str
525
+ Base font family.
526
+ header_family : str or None
527
+ Header font family.
528
+ base_line_size : float or None
529
+ Base line size.
530
+ base_rect_size : float or None
531
+ Base rect size.
532
+ ink : str
533
+ Foreground colour.
534
+ paper : str
535
+ Background colour.
536
+ accent : str
537
+ Accent colour.
538
+
539
+ Returns
540
+ -------
541
+ Theme
542
+ """
543
+ half_line = base_size / 2
544
+
545
+ base = theme_grey(
546
+ base_size=base_size,
547
+ base_family=base_family,
548
+ header_family=header_family,
549
+ base_line_size=base_line_size,
550
+ base_rect_size=base_rect_size,
551
+ ink=ink,
552
+ paper=paper,
553
+ accent=accent,
554
+ )
555
+ override = theme(
556
+ complete=True,
557
+ panel_background=element_rect(fill=paper, colour=None),
558
+ panel_border=element_rect(
559
+ colour=_col_mix(ink, paper, 0.702),
560
+ linewidth=rel(1),
561
+ ),
562
+ panel_grid=element_line(colour=_col_mix(ink, paper, 0.871)),
563
+ panel_grid_major=element_line(linewidth=rel(0.5)),
564
+ panel_grid_minor=element_line(linewidth=rel(0.25)),
565
+ axis_ticks=element_line(
566
+ colour=_col_mix(ink, paper, 0.702),
567
+ linewidth=rel(0.5),
568
+ ),
569
+ strip_background=element_rect(
570
+ fill=_col_mix(ink, paper, 0.702),
571
+ colour=None,
572
+ ),
573
+ strip_text=element_text(
574
+ colour=paper,
575
+ size=rel(0.8),
576
+ margin=margin_auto(0.8 * half_line),
577
+ ),
578
+ )
579
+ return theme_replace_op(base, override)
580
+
581
+
582
+ # ---------------------------------------------------------------------------
583
+ # theme_dark
584
+ # ---------------------------------------------------------------------------
585
+
586
+ def theme_dark(
587
+ base_size: float = 11,
588
+ base_family: str = "",
589
+ header_family: Optional[str] = None,
590
+ base_line_size: Optional[float] = None,
591
+ base_rect_size: Optional[float] = None,
592
+ ink: str = "black",
593
+ paper: str = "white",
594
+ accent: str = "#3366FF",
595
+ ) -> Theme:
596
+ """The dark cousin of ``theme_light`` with a dark panel background.
597
+
598
+ Parameters
599
+ ----------
600
+ base_size : float
601
+ Base font size in points.
602
+ base_family : str
603
+ Base font family.
604
+ header_family : str or None
605
+ Header font family.
606
+ base_line_size : float or None
607
+ Base line size.
608
+ base_rect_size : float or None
609
+ Base rect size.
610
+ ink : str
611
+ Foreground colour.
612
+ paper : str
613
+ Background colour.
614
+ accent : str
615
+ Accent colour.
616
+
617
+ Returns
618
+ -------
619
+ Theme
620
+ """
621
+ half_line = base_size / 2
622
+
623
+ base = theme_grey(
624
+ base_size=base_size,
625
+ base_family=base_family,
626
+ header_family=header_family,
627
+ base_line_size=base_line_size,
628
+ base_rect_size=base_rect_size,
629
+ ink=ink,
630
+ paper=paper,
631
+ accent=accent,
632
+ )
633
+ override = theme(
634
+ complete=True,
635
+ panel_background=element_rect(
636
+ fill=_col_mix(ink, paper, 0.499),
637
+ colour=None,
638
+ ),
639
+ panel_grid=element_line(colour=_col_mix(ink, paper, 0.42)),
640
+ panel_grid_major=element_line(linewidth=rel(0.5)),
641
+ panel_grid_minor=element_line(linewidth=rel(0.25)),
642
+ axis_ticks=element_line(
643
+ colour=_col_mix(ink, paper, 0.2),
644
+ linewidth=rel(0.5),
645
+ ),
646
+ strip_background=element_rect(
647
+ fill=_col_mix(ink, paper, 0.15),
648
+ colour=None,
649
+ ),
650
+ strip_text=element_text(
651
+ colour=_col_mix(ink, paper, 0.899),
652
+ size=rel(0.8),
653
+ margin=margin_auto(0.8 * half_line),
654
+ ),
655
+ )
656
+ return theme_replace_op(base, override)
657
+
658
+
659
+ # ---------------------------------------------------------------------------
660
+ # theme_minimal
661
+ # ---------------------------------------------------------------------------
662
+
663
+ def theme_minimal(
664
+ base_size: float = 11,
665
+ base_family: str = "",
666
+ header_family: Optional[str] = None,
667
+ base_line_size: Optional[float] = None,
668
+ base_rect_size: Optional[float] = None,
669
+ ink: str = "black",
670
+ paper: str = "white",
671
+ accent: str = "#3366FF",
672
+ ) -> Theme:
673
+ """A minimalistic theme with no background annotations.
674
+
675
+ Parameters
676
+ ----------
677
+ base_size : float
678
+ Base font size in points.
679
+ base_family : str
680
+ Base font family.
681
+ header_family : str or None
682
+ Header font family.
683
+ base_line_size : float or None
684
+ Base line size.
685
+ base_rect_size : float or None
686
+ Base rect size.
687
+ ink : str
688
+ Foreground colour.
689
+ paper : str
690
+ Background colour.
691
+ accent : str
692
+ Accent colour.
693
+
694
+ Returns
695
+ -------
696
+ Theme
697
+ """
698
+ base = theme_bw(
699
+ base_size=base_size,
700
+ base_family=base_family,
701
+ header_family=header_family,
702
+ base_line_size=base_line_size,
703
+ base_rect_size=base_rect_size,
704
+ ink=ink,
705
+ paper=paper,
706
+ accent=accent,
707
+ )
708
+ override = theme(
709
+ complete=True,
710
+ axis_ticks=element_blank(),
711
+ axis_text_x_bottom=element_text(margin=margin(t=0.45 * base_size)),
712
+ axis_text_x_top=element_text(margin=margin(b=0.45 * base_size)),
713
+ axis_text_y_left=element_text(margin=margin(r=0.45 * base_size)),
714
+ axis_text_y_right=element_text(margin=margin(l=0.45 * base_size)),
715
+ legend_background=element_blank(),
716
+ legend_key=element_blank(),
717
+ panel_background=element_blank(),
718
+ panel_border=element_blank(),
719
+ strip_background=element_blank(),
720
+ plot_background=element_rect(fill=paper, colour=None),
721
+ )
722
+ return theme_replace_op(base, override)
723
+
724
+
725
+ # ---------------------------------------------------------------------------
726
+ # theme_classic
727
+ # ---------------------------------------------------------------------------
728
+
729
+ def theme_classic(
730
+ base_size: float = 11,
731
+ base_family: str = "",
732
+ header_family: Optional[str] = None,
733
+ base_line_size: Optional[float] = None,
734
+ base_rect_size: Optional[float] = None,
735
+ ink: str = "black",
736
+ paper: str = "white",
737
+ accent: str = "#3366FF",
738
+ ) -> Theme:
739
+ """A classic theme with axis lines and no gridlines.
740
+
741
+ Parameters
742
+ ----------
743
+ base_size : float
744
+ Base font size in points.
745
+ base_family : str
746
+ Base font family.
747
+ header_family : str or None
748
+ Header font family.
749
+ base_line_size : float or None
750
+ Base line size.
751
+ base_rect_size : float or None
752
+ Base rect size.
753
+ ink : str
754
+ Foreground colour.
755
+ paper : str
756
+ Background colour.
757
+ accent : str
758
+ Accent colour.
759
+
760
+ Returns
761
+ -------
762
+ Theme
763
+ """
764
+ base = theme_bw(
765
+ base_size=base_size,
766
+ base_family=base_family,
767
+ header_family=header_family,
768
+ base_line_size=base_line_size,
769
+ base_rect_size=base_rect_size,
770
+ ink=ink,
771
+ paper=paper,
772
+ accent=accent,
773
+ )
774
+ override = theme(
775
+ complete=True,
776
+ panel_border=element_blank(),
777
+ panel_grid=element_blank(),
778
+ axis_text=element_text(size=rel(0.8)),
779
+ axis_line=element_line(lineend="square"),
780
+ axis_ticks=element_line(),
781
+ strip_background=element_rect(linewidth=rel(2)),
782
+ )
783
+ return theme_replace_op(base, override)
784
+
785
+
786
+ # ---------------------------------------------------------------------------
787
+ # theme_void
788
+ # ---------------------------------------------------------------------------
789
+
790
+ def theme_void(
791
+ base_size: float = 11,
792
+ base_family: str = "",
793
+ header_family: Optional[str] = None,
794
+ base_line_size: Optional[float] = None,
795
+ base_rect_size: Optional[float] = None,
796
+ ink: str = "black",
797
+ paper: Optional[str] = None,
798
+ accent: str = "#3366FF",
799
+ ) -> Theme:
800
+ """A completely empty theme.
801
+
802
+ Parameters
803
+ ----------
804
+ base_size : float
805
+ Base font size in points.
806
+ base_family : str
807
+ Base font family.
808
+ header_family : str or None
809
+ Header font family.
810
+ base_line_size : float or None
811
+ Base line size.
812
+ base_rect_size : float or None
813
+ Base rect size.
814
+ ink : str
815
+ Foreground colour.
816
+ paper : str or None
817
+ Background colour (default is transparent).
818
+ accent : str
819
+ Accent colour.
820
+
821
+ Returns
822
+ -------
823
+ Theme
824
+ """
825
+ if base_line_size is None:
826
+ base_line_size = base_size / 22
827
+ if base_rect_size is None:
828
+ base_rect_size = base_size / 22
829
+ if paper is None:
830
+ # Transparent paper by default
831
+ paper = "#00000000"
832
+
833
+ half_line = base_size / 2
834
+
835
+ t = theme(
836
+ complete=True,
837
+ line=element_blank(),
838
+ rect=element_rect(
839
+ fill=paper,
840
+ colour=None,
841
+ linewidth=0,
842
+ linetype=1,
843
+ linejoin="round",
844
+ ),
845
+ polygon=element_blank(),
846
+ point=element_blank(),
847
+ text=element_text(
848
+ family=base_family,
849
+ face="plain",
850
+ colour=ink,
851
+ size=base_size,
852
+ lineheight=0.9,
853
+ hjust=0.5,
854
+ vjust=0.5,
855
+ angle=0,
856
+ margin=margin(),
857
+ debug=False,
858
+ ),
859
+ title=element_text(family=header_family),
860
+ spacing=Unit(half_line, "pt"),
861
+ margins=margin_auto(half_line),
862
+ geom=element_geom(
863
+ ink=ink,
864
+ paper=paper,
865
+ accent=accent,
866
+ linewidth=base_line_size,
867
+ borderwidth=base_line_size,
868
+ linetype=1,
869
+ bordertype=1,
870
+ family=base_family,
871
+ fontsize=base_size,
872
+ pointsize=(base_size / 11) * 1.5,
873
+ pointshape=19,
874
+ ),
875
+ axis_text=element_blank(),
876
+ axis_title=element_blank(),
877
+ axis_ticks_length=rel(0),
878
+ axis_ticks_length_x=None,
879
+ axis_ticks_length_x_top=None,
880
+ axis_ticks_length_x_bottom=None,
881
+ axis_ticks_length_y=None,
882
+ axis_ticks_length_y_left=None,
883
+ axis_ticks_length_y_right=None,
884
+ axis_minor_ticks_length=None,
885
+ legend_box=None,
886
+ legend_key_size=Unit(1.2, "lines"),
887
+ legend_position="right",
888
+ legend_text=element_text(size=rel(0.8)),
889
+ legend_title=element_text(hjust=0),
890
+ legend_key_spacing=rel(1),
891
+ legend_margin=margin_auto(0),
892
+ legend_box_margin=margin_auto(0),
893
+ legend_box_spacing=Unit(0.2, "cm"),
894
+ legend_ticks_length=rel(0.2),
895
+ legend_background=element_blank(),
896
+ legend_box_background=element_blank(),
897
+ strip_clip="on",
898
+ strip_text=element_text(size=rel(0.8)),
899
+ strip_switch_pad_grid=rel(0.5),
900
+ strip_switch_pad_wrap=rel(0.5),
901
+ strip_background=element_blank(),
902
+ panel_ontop=False,
903
+ panel_spacing=None,
904
+ panel_background=element_blank(),
905
+ panel_border=element_blank(),
906
+ plot_margin=margin_auto(0),
907
+ plot_title=element_text(
908
+ size=rel(1.2),
909
+ hjust=0,
910
+ vjust=1,
911
+ margin=margin(t=half_line),
912
+ ),
913
+ plot_title_position="panel",
914
+ plot_subtitle=element_text(
915
+ hjust=0,
916
+ vjust=1,
917
+ margin=margin(t=half_line),
918
+ ),
919
+ plot_caption=element_text(
920
+ size=rel(0.8),
921
+ hjust=1,
922
+ vjust=1,
923
+ margin=margin(t=half_line),
924
+ ),
925
+ plot_caption_position="panel",
926
+ plot_tag=element_text(
927
+ size=rel(1.2),
928
+ hjust=0.5,
929
+ vjust=0.5,
930
+ ),
931
+ plot_tag_position="topleft",
932
+ plot_background=element_rect(),
933
+ )
934
+
935
+ base = _theme_all_null()
936
+ return theme_replace_op(base, t)
937
+
938
+
939
+ # ---------------------------------------------------------------------------
940
+ # theme_test
941
+ # ---------------------------------------------------------------------------
942
+
943
+ def theme_test(
944
+ base_size: float = 11,
945
+ base_family: str = "",
946
+ header_family: Optional[str] = None,
947
+ base_line_size: Optional[float] = None,
948
+ base_rect_size: Optional[float] = None,
949
+ ink: str = "black",
950
+ paper: str = "white",
951
+ accent: str = "#3366FF",
952
+ ) -> Theme:
953
+ """A theme for visual unit tests.
954
+
955
+ Parameters
956
+ ----------
957
+ base_size : float
958
+ Base font size in points.
959
+ base_family : str
960
+ Base font family.
961
+ header_family : str or None
962
+ Header font family.
963
+ base_line_size : float or None
964
+ Base line size.
965
+ base_rect_size : float or None
966
+ Base rect size.
967
+ ink : str
968
+ Foreground colour.
969
+ paper : str
970
+ Background colour.
971
+ accent : str
972
+ Accent colour.
973
+
974
+ Returns
975
+ -------
976
+ Theme
977
+ """
978
+ if base_line_size is None:
979
+ base_line_size = base_size / 22
980
+ if base_rect_size is None:
981
+ base_rect_size = base_size / 22
982
+
983
+ half_line = base_size / 2
984
+
985
+ t = theme(
986
+ complete=True,
987
+ line=element_line(
988
+ colour=ink,
989
+ linewidth=base_line_size,
990
+ linetype=1,
991
+ lineend="butt",
992
+ linejoin="round",
993
+ ),
994
+ rect=element_rect(
995
+ fill=paper,
996
+ colour=ink,
997
+ linewidth=base_rect_size,
998
+ linetype=1,
999
+ linejoin="round",
1000
+ ),
1001
+ text=element_text(
1002
+ family=base_family,
1003
+ face="plain",
1004
+ colour=ink,
1005
+ size=base_size,
1006
+ lineheight=0.9,
1007
+ hjust=0.5,
1008
+ vjust=0.5,
1009
+ angle=0,
1010
+ margin=margin(),
1011
+ debug=False,
1012
+ ),
1013
+ point=element_point(
1014
+ colour=ink,
1015
+ shape=19,
1016
+ fill=paper,
1017
+ size=(base_size / 11) * 1.5,
1018
+ stroke=base_line_size,
1019
+ ),
1020
+ polygon=element_polygon(
1021
+ fill=paper,
1022
+ colour=ink,
1023
+ linewidth=base_rect_size,
1024
+ linetype=1,
1025
+ linejoin="round",
1026
+ ),
1027
+ title=element_text(family=header_family),
1028
+ spacing=Unit(half_line, "pt"),
1029
+ margins=margin_auto(half_line),
1030
+ geom=element_geom(
1031
+ ink=ink,
1032
+ paper=paper,
1033
+ accent=accent,
1034
+ linewidth=base_line_size,
1035
+ borderwidth=base_line_size,
1036
+ linetype=1,
1037
+ family=base_family,
1038
+ fontsize=base_size,
1039
+ pointsize=(base_size / 11) * 1.5,
1040
+ pointshape=19,
1041
+ ),
1042
+
1043
+ # Axis
1044
+ axis_line=element_blank(),
1045
+ axis_line_x=None,
1046
+ axis_line_y=None,
1047
+ axis_text=element_text(
1048
+ size=rel(0.8),
1049
+ colour=_col_mix(ink, paper, 0.302),
1050
+ ),
1051
+ axis_text_x=element_text(
1052
+ margin=margin(t=0.8 * half_line / 2),
1053
+ vjust=1,
1054
+ ),
1055
+ axis_text_x_top=element_text(
1056
+ margin=margin(b=0.8 * half_line / 2),
1057
+ vjust=0,
1058
+ ),
1059
+ axis_text_y=element_text(
1060
+ margin=margin(r=0.8 * half_line / 2),
1061
+ hjust=1,
1062
+ ),
1063
+ axis_text_y_right=element_text(
1064
+ margin=margin(l=0.8 * half_line / 2),
1065
+ hjust=0,
1066
+ ),
1067
+ axis_ticks=element_line(colour=_col_mix(ink, paper, 0.2)),
1068
+ axis_ticks_length=rel(0.5),
1069
+ axis_ticks_length_x=None,
1070
+ axis_ticks_length_x_top=None,
1071
+ axis_ticks_length_x_bottom=None,
1072
+ axis_ticks_length_y=None,
1073
+ axis_ticks_length_y_left=None,
1074
+ axis_ticks_length_y_right=None,
1075
+ axis_minor_ticks_length=rel(0.75),
1076
+ axis_title_x=element_text(
1077
+ margin=margin(t=half_line / 2),
1078
+ vjust=1,
1079
+ ),
1080
+ axis_title_x_top=element_text(
1081
+ margin=margin(b=half_line / 2),
1082
+ vjust=0,
1083
+ ),
1084
+ axis_title_y=element_text(
1085
+ angle=90,
1086
+ margin=margin(r=half_line / 2),
1087
+ vjust=1,
1088
+ ),
1089
+ axis_title_y_right=element_text(
1090
+ angle=-90,
1091
+ margin=margin(l=half_line / 2),
1092
+ vjust=1,
1093
+ ),
1094
+
1095
+ # Legend
1096
+ legend_background=element_rect(colour=None),
1097
+ legend_spacing=rel(2),
1098
+ legend_spacing_x=None,
1099
+ legend_spacing_y=None,
1100
+ legend_margin=margin_auto(0, unit="cm"),
1101
+ legend_key=None,
1102
+ legend_key_size=Unit(1.2, "lines"),
1103
+ legend_key_height=None,
1104
+ legend_key_width=None,
1105
+ legend_key_spacing=None,
1106
+ legend_key_spacing_x=None,
1107
+ legend_key_spacing_y=None,
1108
+ legend_text=element_text(size=rel(0.8)),
1109
+ legend_title=element_text(hjust=0),
1110
+ legend_ticks_length=rel(0.2),
1111
+ legend_position="right",
1112
+ legend_direction=None,
1113
+ legend_justification="center",
1114
+ legend_box=None,
1115
+ legend_box_margin=margin_auto(0, unit="cm"),
1116
+ legend_box_background=element_blank(),
1117
+ legend_box_spacing=rel(2),
1118
+
1119
+ # Panel
1120
+ panel_background=element_rect(fill=paper, colour=None),
1121
+ panel_border=element_rect(colour=_col_mix(ink, paper, 0.2)),
1122
+ panel_grid_major=element_blank(),
1123
+ panel_grid_minor=element_blank(),
1124
+ panel_spacing=None,
1125
+ panel_spacing_x=None,
1126
+ panel_spacing_y=None,
1127
+ panel_ontop=False,
1128
+
1129
+ # Strip
1130
+ strip_background=element_rect(
1131
+ fill=_col_mix(ink, paper, 0.85),
1132
+ colour=_col_mix(ink, paper, 0.2),
1133
+ ),
1134
+ strip_clip="on",
1135
+ strip_text=element_text(
1136
+ colour=_col_mix(ink, paper, 0.1),
1137
+ size=rel(0.8),
1138
+ margin=margin_auto(0.8 * half_line),
1139
+ ),
1140
+ strip_text_x=None,
1141
+ strip_text_y=element_text(angle=-90),
1142
+ strip_text_y_left=element_text(angle=90),
1143
+ strip_placement="inside",
1144
+ strip_placement_x=None,
1145
+ strip_placement_y=None,
1146
+ strip_switch_pad_grid=rel(0.5),
1147
+ strip_switch_pad_wrap=rel(0.5),
1148
+
1149
+ # Plot
1150
+ plot_background=element_rect(colour=paper),
1151
+ plot_title=element_text(
1152
+ size=rel(1.2),
1153
+ hjust=0,
1154
+ vjust=1,
1155
+ margin=margin(b=half_line),
1156
+ ),
1157
+ plot_title_position="panel",
1158
+ plot_subtitle=element_text(
1159
+ hjust=0,
1160
+ vjust=1,
1161
+ margin=margin(b=half_line),
1162
+ ),
1163
+ plot_caption=element_text(
1164
+ size=rel(0.8),
1165
+ hjust=1,
1166
+ vjust=1,
1167
+ margin=margin(t=half_line),
1168
+ ),
1169
+ plot_caption_position="panel",
1170
+ plot_tag=element_text(
1171
+ size=rel(1.2),
1172
+ hjust=0.5,
1173
+ vjust=0.5,
1174
+ ),
1175
+ plot_tag_position="topleft",
1176
+ plot_margin=None,
1177
+ )
1178
+
1179
+ base = _theme_all_null()
1180
+ return theme_replace_op(base, t)
1181
+
1182
+
1183
+ # ---------------------------------------------------------------------------
1184
+ # Sub-theme helpers
1185
+ # ---------------------------------------------------------------------------
1186
+
1187
+ def theme_sub_axis(**kwargs: Any) -> Theme:
1188
+ """Create a partial theme modifying axis elements.
1189
+
1190
+ Parameters
1191
+ ----------
1192
+ **kwargs
1193
+ Axis-related theme element overrides (e.g.
1194
+ ``axis_text=element_text(size=8)``).
1195
+
1196
+ Returns
1197
+ -------
1198
+ Theme
1199
+ """
1200
+ return theme(**kwargs)
1201
+
1202
+
1203
+ def theme_sub_axis_x(**kwargs: Any) -> Theme:
1204
+ """Create a partial theme modifying x-axis elements.
1205
+
1206
+ Parameters
1207
+ ----------
1208
+ **kwargs
1209
+ X-axis theme element overrides.
1210
+
1211
+ Returns
1212
+ -------
1213
+ Theme
1214
+ """
1215
+ return theme(**kwargs)
1216
+
1217
+
1218
+ def theme_sub_axis_y(**kwargs: Any) -> Theme:
1219
+ """Create a partial theme modifying y-axis elements.
1220
+
1221
+ Parameters
1222
+ ----------
1223
+ **kwargs
1224
+ Y-axis theme element overrides.
1225
+
1226
+ Returns
1227
+ -------
1228
+ Theme
1229
+ """
1230
+ return theme(**kwargs)
1231
+
1232
+
1233
+ def theme_sub_axis_top(**kwargs: Any) -> Theme:
1234
+ """Create a partial theme modifying top-axis elements.
1235
+
1236
+ Parameters
1237
+ ----------
1238
+ **kwargs
1239
+ Top-axis theme element overrides.
1240
+
1241
+ Returns
1242
+ -------
1243
+ Theme
1244
+ """
1245
+ return theme(**kwargs)
1246
+
1247
+
1248
+ def theme_sub_axis_bottom(**kwargs: Any) -> Theme:
1249
+ """Create a partial theme modifying bottom-axis elements.
1250
+
1251
+ Parameters
1252
+ ----------
1253
+ **kwargs
1254
+ Bottom-axis theme element overrides.
1255
+
1256
+ Returns
1257
+ -------
1258
+ Theme
1259
+ """
1260
+ return theme(**kwargs)
1261
+
1262
+
1263
+ def theme_sub_axis_left(**kwargs: Any) -> Theme:
1264
+ """Create a partial theme modifying left-axis elements.
1265
+
1266
+ Parameters
1267
+ ----------
1268
+ **kwargs
1269
+ Left-axis theme element overrides.
1270
+
1271
+ Returns
1272
+ -------
1273
+ Theme
1274
+ """
1275
+ return theme(**kwargs)
1276
+
1277
+
1278
+ def theme_sub_axis_right(**kwargs: Any) -> Theme:
1279
+ """Create a partial theme modifying right-axis elements.
1280
+
1281
+ Parameters
1282
+ ----------
1283
+ **kwargs
1284
+ Right-axis theme element overrides.
1285
+
1286
+ Returns
1287
+ -------
1288
+ Theme
1289
+ """
1290
+ return theme(**kwargs)
1291
+
1292
+
1293
+ def theme_sub_legend(**kwargs: Any) -> Theme:
1294
+ """Create a partial theme modifying legend elements.
1295
+
1296
+ Parameters
1297
+ ----------
1298
+ **kwargs
1299
+ Legend-related theme element overrides.
1300
+
1301
+ Returns
1302
+ -------
1303
+ Theme
1304
+ """
1305
+ return theme(**kwargs)
1306
+
1307
+
1308
+ def theme_sub_panel(**kwargs: Any) -> Theme:
1309
+ """Create a partial theme modifying panel elements.
1310
+
1311
+ Parameters
1312
+ ----------
1313
+ **kwargs
1314
+ Panel-related theme element overrides.
1315
+
1316
+ Returns
1317
+ -------
1318
+ Theme
1319
+ """
1320
+ return theme(**kwargs)
1321
+
1322
+
1323
+ def theme_sub_plot(**kwargs: Any) -> Theme:
1324
+ """Create a partial theme modifying plot elements.
1325
+
1326
+ Parameters
1327
+ ----------
1328
+ **kwargs
1329
+ Plot-related theme element overrides.
1330
+
1331
+ Returns
1332
+ -------
1333
+ Theme
1334
+ """
1335
+ return theme(**kwargs)
1336
+
1337
+
1338
+ def theme_sub_strip(**kwargs: Any) -> Theme:
1339
+ """Create a partial theme modifying strip elements.
1340
+
1341
+ Parameters
1342
+ ----------
1343
+ **kwargs
1344
+ Strip-related theme element overrides.
1345
+
1346
+ Returns
1347
+ -------
1348
+ Theme
1349
+ """
1350
+ return theme(**kwargs)