publiplots 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.
publiplots/__init__.py ADDED
@@ -0,0 +1,110 @@
1
+ """
2
+ PubliPlots: Publication-ready plotting with a clean, modular API.
3
+
4
+ PubliPlots provides a seaborn-like interface for creating beautiful,
5
+ publication-ready visualizations with sensible defaults and extensive
6
+ customization options.
7
+
8
+ Basic usage:
9
+ >>> import publiplots as pp
10
+ >>> pp.set_publication_style()
11
+ >>> fig, ax = pp.barplot(data=df, x='category', y='value')
12
+ >>> pp.savefig(fig, 'output.png')
13
+ """
14
+
15
+ __version__ = "0.1.0"
16
+ __author__ = "Jorge Botas"
17
+
18
+ # Core plotting functions (base)
19
+ from publiplots.base.bar import barplot
20
+ from publiplots.base.scatter import scatterplot
21
+
22
+ # Advanced plotting functions
23
+ from publiplots.advanced.venn import venn
24
+
25
+ # Utilities
26
+ from publiplots.utils.io import savefig, save_multiple, close_all
27
+ from publiplots.utils.axes import (
28
+ adjust_spines,
29
+ add_grid,
30
+ set_axis_labels,
31
+ add_reference_line,
32
+ )
33
+ from publiplots.utils.legend import (
34
+ HandlerCircle,
35
+ HandlerRectangle,
36
+ get_legend_handler_map,
37
+ create_legend_handles,
38
+ LegendBuilder,
39
+ create_legend_builder,
40
+ )
41
+
42
+ # Theming
43
+ from publiplots.themes.colors import get_palette, list_palettes, show_palette, resolve_palette, DEFAULT_COLOR
44
+ from publiplots.themes.styles import (
45
+ set_publication_style,
46
+ set_minimal_style,
47
+ set_poster_style,
48
+ reset_style,
49
+ )
50
+ from publiplots.themes.markers import (
51
+ get_marker_cycle,
52
+ get_hatch_cycle,
53
+ STANDARD_MARKERS,
54
+ HATCH_PATTERNS,
55
+ )
56
+ from publiplots.themes.hatches import (
57
+ set_hatch_mode,
58
+ get_hatch_mode,
59
+ get_hatch_patterns,
60
+ list_hatch_patterns,
61
+ )
62
+
63
+ __all__ = [
64
+ "__version__",
65
+ "__author__",
66
+ # Base plots
67
+ "barplot",
68
+ "scatterplot",
69
+ # Advanced plots
70
+ "venn",
71
+ # I/O utilities
72
+ "savefig",
73
+ "save_multiple",
74
+ "close_all",
75
+ # Axes utilities
76
+ "adjust_spines",
77
+ "add_grid",
78
+ "set_axis_labels",
79
+ "add_reference_line",
80
+ # Legend utilities
81
+ "HandlerCircle",
82
+ "HandlerRectangle",
83
+ "get_legend_handler_map",
84
+ "create_legend_handles",
85
+ "LegendBuilder",
86
+ "create_legend_builder",
87
+ # Color/palette functions
88
+ "get_palette",
89
+ "list_palettes",
90
+ "show_palette",
91
+ "resolve_palette",
92
+ # Color constants
93
+ "DEFAULT_COLOR",
94
+ # Style functions
95
+ "set_publication_style",
96
+ "set_minimal_style",
97
+ "set_poster_style",
98
+ "reset_style",
99
+ # Marker functions
100
+ "get_marker_cycle",
101
+ "get_hatch_cycle",
102
+ # Hatch functions
103
+ "set_hatch_mode",
104
+ "get_hatch_mode",
105
+ "get_hatch_patterns",
106
+ "list_hatch_patterns",
107
+ # Constants
108
+ "STANDARD_MARKERS",
109
+ "HATCH_PATTERNS",
110
+ ]
@@ -0,0 +1,8 @@
1
+ """
2
+ Advanced plotting functions for publiplots.
3
+
4
+ This module provides specialized plotting functions that compose
5
+ base functions with additional features for specific use cases.
6
+ """
7
+
8
+ __all__ = []
@@ -0,0 +1,374 @@
1
+ """
2
+ Venn diagram visualizations for publiplots.
3
+
4
+ This module provides functions for creating 2-way and 3-way Venn diagrams
5
+ with optional statistical analysis.
6
+ """
7
+
8
+ from typing import Optional, Dict, List, Union, Tuple
9
+ import matplotlib.pyplot as plt
10
+ from matplotlib.axes import Axes
11
+ from matplotlib_venn import venn2, venn2_circles, venn3, venn3_circles
12
+ from matplotlib_venn.layout.venn2 import DefaultLayoutAlgorithm as Venn2LayoutAlgorithm
13
+ from matplotlib_venn.layout.venn3 import DefaultLayoutAlgorithm as Venn3LayoutAlgorithm
14
+ from scipy.stats import hypergeom
15
+ import numpy as np
16
+ import seaborn as sns
17
+
18
+ from publiplots.config import DEFAULT_ALPHA, DEFAULT_FIGSIZE
19
+ from publiplots.themes.colors import get_palette
20
+
21
+
22
+ def venn(
23
+ sets: Union[List[set], Dict[str, set]],
24
+ labels: Optional[List[str]] = None,
25
+ colors: Optional[List[str]] = None,
26
+ universe_size: Optional[int] = None,
27
+ weighted: bool = False,
28
+ include_size_in_label: bool = True,
29
+ alpha: float = DEFAULT_ALPHA,
30
+ figsize: Tuple[float, float] = DEFAULT_FIGSIZE,
31
+ ax: Optional[Axes] = None,
32
+ ) -> Tuple[plt.Figure, Axes, Dict]:
33
+ """
34
+ Create a Venn diagram for 2 or 3 sets with optional overlap statistics.
35
+
36
+ Parameters
37
+ ----------
38
+ sets : list of sets or dict
39
+ Either a list of 2-3 sets, or a dictionary mapping labels to sets.
40
+ Example: [set1, set2] or {'Group A': set1, 'Group B': set2}
41
+ labels : list, optional
42
+ Labels for each set. If sets is a dict, labels are taken from keys.
43
+ Default: ['Set A', 'Set B', 'Set C']
44
+ colors : list, optional
45
+ Colors for each set. If None, uses pastel_categorical palette.
46
+ universe_size : int, optional
47
+ Total number of elements in the universe for statistical tests.
48
+ If None, no statistical analysis is performed.
49
+ weighted : bool, default=False
50
+ If False, uses unweighted layout where all regions have equal area.
51
+ If True, region sizes are proportional to set sizes.
52
+ include_size_in_label : bool, default=True
53
+ If True, appends set size to labels.
54
+ alpha : float, default=0.3
55
+ Transparency of set regions (0-1).
56
+ figsize : tuple, default=(10, 6)
57
+ Figure size (width, height).
58
+ ax : Axes, optional
59
+ Matplotlib axes object. If None, creates new figure.
60
+
61
+ Returns
62
+ -------
63
+ fig : Figure
64
+ Matplotlib figure object.
65
+ ax : Axes
66
+ Matplotlib axes object.
67
+ stats : dict
68
+ Dictionary containing overlap statistics and p-values if universe_size
69
+ is provided.
70
+
71
+ Examples
72
+ --------
73
+ Simple 2-way Venn diagram:
74
+ >>> set1 = {1, 2, 3, 4, 5}
75
+ >>> set2 = {4, 5, 6, 7, 8}
76
+ >>> fig, ax, stats = pp.venn([set1, set2],
77
+ ... labels=['Group A', 'Group B'])
78
+
79
+ 3-way Venn with custom colors:
80
+ >>> sets_dict = {'A': set1, 'B': set2, 'C': set3}
81
+ >>> colors = pp.get_palette('pastel_categorical', n_colors=3)
82
+ >>> fig, ax, stats = pp.venn(sets_dict, colors=colors)
83
+
84
+ With statistical testing:
85
+ >>> fig, ax, stats = pp.venn([set1, set2], universe_size=1000)
86
+ >>> print(f"P-value: {stats['p_value']:.4f}")
87
+
88
+ Notes
89
+ -----
90
+ - For 2-way Venn diagrams, uses hypergeometric test for overlap significance
91
+ - For 3-way Venn diagrams, tests significance of triple intersection
92
+ - Statistical tests require universe_size to be specified
93
+ """
94
+ # Parse input sets
95
+ if isinstance(sets, dict):
96
+ labels = list(sets.keys())
97
+ sets = [set(s) for s in sets.values()]
98
+ else:
99
+ sets = [set(s) for s in sets]
100
+ if labels is None:
101
+ labels = [f"Set {chr(65+i)}" for i in range(len(sets))]
102
+
103
+ # Validate number of sets
104
+ if len(sets) not in [2, 3]:
105
+ raise ValueError("Venn diagram supports only 2 or 3 sets")
106
+
107
+ # Get colors
108
+ if colors is None:
109
+ colors = get_palette('pastel_categorical', n_colors=len(sets))
110
+
111
+ # Set up seaborn style
112
+ sns.set_theme("paper", style="white", font="Arial", font_scale=2)
113
+
114
+ # Create figure if not provided
115
+ if ax is None:
116
+ fig, ax = plt.subplots(figsize=figsize)
117
+ else:
118
+ fig = ax.get_figure()
119
+
120
+ # Decide on layout algorithm
121
+ if not weighted:
122
+ if len(sets) == 3:
123
+ layout_algorithm = Venn3LayoutAlgorithm(fixed_subset_sizes=(1,) * 7)
124
+ else:
125
+ layout_algorithm = Venn2LayoutAlgorithm(fixed_subset_sizes=(1, 1, 1))
126
+ else:
127
+ layout_algorithm = None
128
+
129
+ # Create Venn diagram based on number of sets
130
+ if len(sets) == 2:
131
+ stats = _create_venn2(
132
+ sets, labels, colors, universe_size, include_size_in_label,
133
+ alpha, layout_algorithm, weighted, ax
134
+ )
135
+ else:
136
+ stats = _create_venn3(
137
+ sets, labels, colors, universe_size, include_size_in_label,
138
+ alpha, layout_algorithm, weighted, ax
139
+ )
140
+
141
+ plt.tight_layout()
142
+ return fig, ax, stats
143
+
144
+
145
+ def _create_venn2(
146
+ sets: List[set],
147
+ labels: List[str],
148
+ colors: List[str],
149
+ universe_size: Optional[int],
150
+ include_size_in_label: bool,
151
+ alpha: float,
152
+ layout_algorithm,
153
+ weighted: bool,
154
+ ax: Axes
155
+ ) -> Dict:
156
+ """Create 2-way Venn diagram."""
157
+ A, B = sets
158
+ labelA, labelB = labels[:2]
159
+ colorA, colorB = colors[:2]
160
+
161
+ if include_size_in_label:
162
+ labelA, labelB = f"{labelA} ({len(A)})", f"{labelB} ({len(B)})"
163
+
164
+ size_A = len(A)
165
+ size_B = len(B)
166
+ overlap = len(A.intersection(B))
167
+
168
+ # Prepare data for venn2
169
+ subsets = (size_A - overlap, size_B - overlap, overlap)
170
+
171
+ # Create Venn diagram
172
+ v = venn2(
173
+ subsets=subsets,
174
+ set_labels=(labelA, labelB),
175
+ set_colors=(colorA, colorB),
176
+ layout_algorithm=layout_algorithm,
177
+ ax=ax
178
+ )
179
+
180
+ # Increase transparency
181
+ for patch in v.patches:
182
+ if patch is not None:
183
+ patch.set_alpha(alpha)
184
+
185
+ # Add circles for clarity
186
+ circles = venn2_circles(
187
+ subsets=subsets if weighted else [1, 1, 1],
188
+ linestyle="solid",
189
+ linewidth=2,
190
+ color="black",
191
+ layout_algorithm=layout_algorithm,
192
+ ax=ax
193
+ )
194
+
195
+ # Override circle edge colors
196
+ for i, color in enumerate([colorA, colorB]):
197
+ if circles[i] is not None:
198
+ circles[i].set_edgecolor(color)
199
+
200
+ # Statistical test if universe_size provided
201
+ if universe_size is None:
202
+ return {
203
+ "set_sizes": [size_A, size_B],
204
+ "overlap": overlap,
205
+ "expected_overlap": None,
206
+ "fold_enrichment": None,
207
+ "log2_fold_enrichment": None,
208
+ "p_value": None,
209
+ "significant": None
210
+ }
211
+
212
+ # Hypergeometric test for overlap
213
+ p_value = hypergeom.sf(overlap - 1, universe_size, size_A, size_B)
214
+ expected_overlap = (size_A * size_B) / universe_size
215
+ fold_enrichment = overlap / expected_overlap if expected_overlap > 0 else float("inf")
216
+ log2_fold_enrichment = np.log2(fold_enrichment) if fold_enrichment > 0 else float("inf")
217
+
218
+ # Show stats
219
+ ax.text(
220
+ 0.5, -0.12,
221
+ f"P-value: {p_value:.2e}",
222
+ horizontalalignment="center",
223
+ transform=ax.transAxes
224
+ )
225
+ ax.text(
226
+ 0.5, -0.17,
227
+ f"Expected overlap: {expected_overlap:.2f}, "
228
+ f"Fold enrichment: {fold_enrichment:.2f}x (log2: {log2_fold_enrichment:.2f})",
229
+ horizontalalignment="center",
230
+ transform=ax.transAxes,
231
+ )
232
+
233
+ return {
234
+ "set_sizes": [size_A, size_B],
235
+ "overlap": overlap,
236
+ "expected_overlap": expected_overlap,
237
+ "fold_enrichment": fold_enrichment,
238
+ "log2_fold_enrichment": log2_fold_enrichment,
239
+ "p_value": p_value,
240
+ "significant": p_value < 0.05
241
+ }
242
+
243
+
244
+ def _create_venn3(
245
+ sets: List[set],
246
+ labels: List[str],
247
+ colors: List[str],
248
+ universe_size: Optional[int],
249
+ include_size_in_label: bool,
250
+ alpha: float,
251
+ layout_algorithm,
252
+ weighted: bool,
253
+ ax: Axes
254
+ ) -> Dict:
255
+ """Create 3-way Venn diagram."""
256
+ A, B, C = sets
257
+ labelA, labelB, labelC = labels[:3]
258
+ colorA, colorB, colorC = colors[:3]
259
+
260
+ if include_size_in_label:
261
+ labelA = f"{labelA} ({len(A)})"
262
+ labelB = f"{labelB} ({len(B)})"
263
+ labelC = f"{labelC} ({len(C)})"
264
+
265
+ # Compute all subset sizes for 3-set Venn
266
+ onlyA = len(A - B - C)
267
+ onlyB = len(B - A - C)
268
+ onlyC = len(C - A - B)
269
+ AB_only = len((A & B) - C)
270
+ AC_only = len((A & C) - B)
271
+ BC_only = len((B & C) - A)
272
+ ABC = len(A & B & C)
273
+
274
+ size_A = len(A)
275
+ size_B = len(B)
276
+ size_C = len(C)
277
+
278
+ # Prepare data for venn3
279
+ subsets = (onlyA, onlyB, AB_only, onlyC, AC_only, BC_only, ABC)
280
+
281
+ # Create Venn diagram
282
+ v = venn3(
283
+ subsets=subsets,
284
+ set_labels=(labelA, labelB, labelC),
285
+ set_colors=(colorA, colorB, colorC),
286
+ layout_algorithm=layout_algorithm,
287
+ ax=ax
288
+ )
289
+
290
+ # Increase transparency
291
+ for patch in v.patches:
292
+ if patch is not None:
293
+ patch.set_alpha(alpha)
294
+
295
+ # Add circles
296
+ circles = venn3_circles(
297
+ subsets=subsets if weighted else [1]*7,
298
+ linestyle="solid",
299
+ linewidth=2,
300
+ color="black",
301
+ layout_algorithm=layout_algorithm,
302
+ ax=ax
303
+ )
304
+
305
+ # Override circle edge colors
306
+ for i, color in enumerate([colorA, colorB, colorC]):
307
+ if circles[i] is not None:
308
+ circles[i].set_edgecolor(color)
309
+
310
+ if universe_size is None:
311
+ return {
312
+ "set_sizes": [size_A, size_B, size_C],
313
+ "unique_counts": {
314
+ f"{labelA} only": onlyA,
315
+ f"{labelB} only": onlyB,
316
+ f"{labelC} only": onlyC
317
+ },
318
+ "pairwise_overlaps": {
319
+ f"{labelA}&{labelB} only": AB_only,
320
+ f"{labelA}&{labelC} only": AC_only,
321
+ f"{labelB}&{labelC} only": BC_only
322
+ },
323
+ "triple_overlap": ABC,
324
+ "expected_triple_overlap": None,
325
+ "fold_enrichment": None,
326
+ "log2_fold_enrichment": None,
327
+ "p_value": None,
328
+ "significant": None
329
+ }
330
+
331
+ # Hypergeometric test on triple intersection
332
+ BC = B & C
333
+ size_BC = len(BC)
334
+ p_value = hypergeom.sf(ABC - 1, universe_size, size_A, size_BC)
335
+
336
+ # Expected triple intersection
337
+ expected_abc = (size_A * size_B * size_C) / (universe_size**2)
338
+ fold_enrichment = (ABC / expected_abc) if expected_abc > 0 else float("inf")
339
+ log2_fold_enrichment = np.log2(fold_enrichment) if fold_enrichment > 0 else float("inf")
340
+
341
+ # Show p-value and enrichment
342
+ ax.text(
343
+ 0.5, -0.10,
344
+ f"P-value (for triple intersection): {p_value:.2e}",
345
+ horizontalalignment="center",
346
+ transform=ax.transAxes
347
+ )
348
+ ax.text(
349
+ 0.5, -0.15,
350
+ f"Expected triple intersection: {expected_abc:.2f}, "
351
+ f"Fold enrichment: {fold_enrichment:.2f}x (log2: {log2_fold_enrichment:.2f})",
352
+ horizontalalignment="center",
353
+ transform=ax.transAxes,
354
+ )
355
+
356
+ return {
357
+ "set_sizes": [size_A, size_B, size_C],
358
+ "unique_counts": {
359
+ f"{labelA} only": onlyA,
360
+ f"{labelB} only": onlyB,
361
+ f"{labelC} only": onlyC
362
+ },
363
+ "pairwise_overlaps": {
364
+ f"{labelA}&{labelB} only": AB_only,
365
+ f"{labelA}&{labelC} only": AC_only,
366
+ f"{labelB}&{labelC} only": BC_only
367
+ },
368
+ "triple_overlap": ABC,
369
+ "expected_triple_overlap": expected_abc,
370
+ "fold_enrichment": fold_enrichment,
371
+ "log2_fold_enrichment": log2_fold_enrichment,
372
+ "p_value": p_value,
373
+ "significant": p_value < 0.05
374
+ }
@@ -0,0 +1,8 @@
1
+ """
2
+ Base plotting functions for publiplots.
3
+
4
+ This module provides fundamental plotting functions that serve as
5
+ building blocks for more advanced visualizations.
6
+ """
7
+
8
+ __all__ = []