multipers 2.3.3b6__cp311-cp311-macosx_11_0_arm64.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.

Potentially problematic release.


This version of multipers might be problematic. Click here for more details.

Files changed (183) hide show
  1. multipers/.dylibs/libc++.1.0.dylib +0 -0
  2. multipers/.dylibs/libtbb.12.16.dylib +0 -0
  3. multipers/__init__.py +33 -0
  4. multipers/_signed_measure_meta.py +453 -0
  5. multipers/_slicer_meta.py +211 -0
  6. multipers/array_api/__init__.py +45 -0
  7. multipers/array_api/numpy.py +41 -0
  8. multipers/array_api/torch.py +58 -0
  9. multipers/data/MOL2.py +458 -0
  10. multipers/data/UCR.py +18 -0
  11. multipers/data/__init__.py +1 -0
  12. multipers/data/graphs.py +466 -0
  13. multipers/data/immuno_regions.py +27 -0
  14. multipers/data/minimal_presentation_to_st_bf.py +0 -0
  15. multipers/data/pytorch2simplextree.py +91 -0
  16. multipers/data/shape3d.py +101 -0
  17. multipers/data/synthetic.py +113 -0
  18. multipers/distances.py +202 -0
  19. multipers/filtration_conversions.pxd +229 -0
  20. multipers/filtration_conversions.pxd.tp +84 -0
  21. multipers/filtrations/__init__.py +18 -0
  22. multipers/filtrations/density.py +574 -0
  23. multipers/filtrations/filtrations.py +361 -0
  24. multipers/filtrations.pxd +224 -0
  25. multipers/function_rips.cpython-311-darwin.so +0 -0
  26. multipers/function_rips.pyx +105 -0
  27. multipers/grids.cpython-311-darwin.so +0 -0
  28. multipers/grids.pyx +433 -0
  29. multipers/gudhi/Persistence_slices_interface.h +132 -0
  30. multipers/gudhi/Simplex_tree_interface.h +239 -0
  31. multipers/gudhi/Simplex_tree_multi_interface.h +551 -0
  32. multipers/gudhi/cubical_to_boundary.h +59 -0
  33. multipers/gudhi/gudhi/Bitmap_cubical_complex.h +450 -0
  34. multipers/gudhi/gudhi/Bitmap_cubical_complex_base.h +1070 -0
  35. multipers/gudhi/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h +579 -0
  36. multipers/gudhi/gudhi/Debug_utils.h +45 -0
  37. multipers/gudhi/gudhi/Fields/Multi_field.h +484 -0
  38. multipers/gudhi/gudhi/Fields/Multi_field_operators.h +455 -0
  39. multipers/gudhi/gudhi/Fields/Multi_field_shared.h +450 -0
  40. multipers/gudhi/gudhi/Fields/Multi_field_small.h +531 -0
  41. multipers/gudhi/gudhi/Fields/Multi_field_small_operators.h +507 -0
  42. multipers/gudhi/gudhi/Fields/Multi_field_small_shared.h +531 -0
  43. multipers/gudhi/gudhi/Fields/Z2_field.h +355 -0
  44. multipers/gudhi/gudhi/Fields/Z2_field_operators.h +376 -0
  45. multipers/gudhi/gudhi/Fields/Zp_field.h +420 -0
  46. multipers/gudhi/gudhi/Fields/Zp_field_operators.h +400 -0
  47. multipers/gudhi/gudhi/Fields/Zp_field_shared.h +418 -0
  48. multipers/gudhi/gudhi/Flag_complex_edge_collapser.h +337 -0
  49. multipers/gudhi/gudhi/Matrix.h +2107 -0
  50. multipers/gudhi/gudhi/Multi_critical_filtration.h +1038 -0
  51. multipers/gudhi/gudhi/Multi_persistence/Box.h +174 -0
  52. multipers/gudhi/gudhi/Multi_persistence/Line.h +282 -0
  53. multipers/gudhi/gudhi/Off_reader.h +173 -0
  54. multipers/gudhi/gudhi/One_critical_filtration.h +1441 -0
  55. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix.h +769 -0
  56. multipers/gudhi/gudhi/Persistence_matrix/Base_matrix_with_column_compression.h +686 -0
  57. multipers/gudhi/gudhi/Persistence_matrix/Boundary_matrix.h +842 -0
  58. multipers/gudhi/gudhi/Persistence_matrix/Chain_matrix.h +1350 -0
  59. multipers/gudhi/gudhi/Persistence_matrix/Id_to_index_overlay.h +1105 -0
  60. multipers/gudhi/gudhi/Persistence_matrix/Position_to_index_overlay.h +859 -0
  61. multipers/gudhi/gudhi/Persistence_matrix/RU_matrix.h +910 -0
  62. multipers/gudhi/gudhi/Persistence_matrix/allocators/entry_constructors.h +139 -0
  63. multipers/gudhi/gudhi/Persistence_matrix/base_pairing.h +230 -0
  64. multipers/gudhi/gudhi/Persistence_matrix/base_swap.h +211 -0
  65. multipers/gudhi/gudhi/Persistence_matrix/boundary_cell_position_to_id_mapper.h +60 -0
  66. multipers/gudhi/gudhi/Persistence_matrix/boundary_face_position_to_id_mapper.h +60 -0
  67. multipers/gudhi/gudhi/Persistence_matrix/chain_pairing.h +136 -0
  68. multipers/gudhi/gudhi/Persistence_matrix/chain_rep_cycles.h +190 -0
  69. multipers/gudhi/gudhi/Persistence_matrix/chain_vine_swap.h +616 -0
  70. multipers/gudhi/gudhi/Persistence_matrix/columns/chain_column_extra_properties.h +150 -0
  71. multipers/gudhi/gudhi/Persistence_matrix/columns/column_dimension_holder.h +106 -0
  72. multipers/gudhi/gudhi/Persistence_matrix/columns/column_utilities.h +219 -0
  73. multipers/gudhi/gudhi/Persistence_matrix/columns/entry_types.h +327 -0
  74. multipers/gudhi/gudhi/Persistence_matrix/columns/heap_column.h +1140 -0
  75. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_list_column.h +934 -0
  76. multipers/gudhi/gudhi/Persistence_matrix/columns/intrusive_set_column.h +934 -0
  77. multipers/gudhi/gudhi/Persistence_matrix/columns/list_column.h +980 -0
  78. multipers/gudhi/gudhi/Persistence_matrix/columns/naive_vector_column.h +1092 -0
  79. multipers/gudhi/gudhi/Persistence_matrix/columns/row_access.h +192 -0
  80. multipers/gudhi/gudhi/Persistence_matrix/columns/set_column.h +921 -0
  81. multipers/gudhi/gudhi/Persistence_matrix/columns/small_vector_column.h +1093 -0
  82. multipers/gudhi/gudhi/Persistence_matrix/columns/unordered_set_column.h +1012 -0
  83. multipers/gudhi/gudhi/Persistence_matrix/columns/vector_column.h +1244 -0
  84. multipers/gudhi/gudhi/Persistence_matrix/matrix_dimension_holders.h +186 -0
  85. multipers/gudhi/gudhi/Persistence_matrix/matrix_row_access.h +164 -0
  86. multipers/gudhi/gudhi/Persistence_matrix/ru_pairing.h +156 -0
  87. multipers/gudhi/gudhi/Persistence_matrix/ru_rep_cycles.h +376 -0
  88. multipers/gudhi/gudhi/Persistence_matrix/ru_vine_swap.h +540 -0
  89. multipers/gudhi/gudhi/Persistent_cohomology/Field_Zp.h +118 -0
  90. multipers/gudhi/gudhi/Persistent_cohomology/Multi_field.h +173 -0
  91. multipers/gudhi/gudhi/Persistent_cohomology/Persistent_cohomology_column.h +128 -0
  92. multipers/gudhi/gudhi/Persistent_cohomology.h +745 -0
  93. multipers/gudhi/gudhi/Points_off_io.h +171 -0
  94. multipers/gudhi/gudhi/Simple_object_pool.h +69 -0
  95. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_iterators.h +463 -0
  96. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h +83 -0
  97. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_siblings.h +106 -0
  98. multipers/gudhi/gudhi/Simplex_tree/Simplex_tree_star_simplex_iterators.h +277 -0
  99. multipers/gudhi/gudhi/Simplex_tree/hooks_simplex_base.h +62 -0
  100. multipers/gudhi/gudhi/Simplex_tree/indexing_tag.h +27 -0
  101. multipers/gudhi/gudhi/Simplex_tree/serialization_utils.h +62 -0
  102. multipers/gudhi/gudhi/Simplex_tree/simplex_tree_options.h +157 -0
  103. multipers/gudhi/gudhi/Simplex_tree.h +2794 -0
  104. multipers/gudhi/gudhi/Simplex_tree_multi.h +152 -0
  105. multipers/gudhi/gudhi/distance_functions.h +62 -0
  106. multipers/gudhi/gudhi/graph_simplicial_complex.h +104 -0
  107. multipers/gudhi/gudhi/persistence_interval.h +253 -0
  108. multipers/gudhi/gudhi/persistence_matrix_options.h +170 -0
  109. multipers/gudhi/gudhi/reader_utils.h +367 -0
  110. multipers/gudhi/mma_interface_coh.h +256 -0
  111. multipers/gudhi/mma_interface_h0.h +223 -0
  112. multipers/gudhi/mma_interface_matrix.h +293 -0
  113. multipers/gudhi/naive_merge_tree.h +536 -0
  114. multipers/gudhi/scc_io.h +310 -0
  115. multipers/gudhi/truc.h +1403 -0
  116. multipers/io.cpython-311-darwin.so +0 -0
  117. multipers/io.pyx +644 -0
  118. multipers/ml/__init__.py +0 -0
  119. multipers/ml/accuracies.py +90 -0
  120. multipers/ml/invariants_with_persistable.py +79 -0
  121. multipers/ml/kernels.py +176 -0
  122. multipers/ml/mma.py +713 -0
  123. multipers/ml/one.py +472 -0
  124. multipers/ml/point_clouds.py +352 -0
  125. multipers/ml/signed_measures.py +1589 -0
  126. multipers/ml/sliced_wasserstein.py +461 -0
  127. multipers/ml/tools.py +113 -0
  128. multipers/mma_structures.cpython-311-darwin.so +0 -0
  129. multipers/mma_structures.pxd +128 -0
  130. multipers/mma_structures.pyx +2786 -0
  131. multipers/mma_structures.pyx.tp +1094 -0
  132. multipers/multi_parameter_rank_invariant/diff_helpers.h +84 -0
  133. multipers/multi_parameter_rank_invariant/euler_characteristic.h +97 -0
  134. multipers/multi_parameter_rank_invariant/function_rips.h +322 -0
  135. multipers/multi_parameter_rank_invariant/hilbert_function.h +769 -0
  136. multipers/multi_parameter_rank_invariant/persistence_slices.h +148 -0
  137. multipers/multi_parameter_rank_invariant/rank_invariant.h +369 -0
  138. multipers/multiparameter_edge_collapse.py +41 -0
  139. multipers/multiparameter_module_approximation/approximation.h +2330 -0
  140. multipers/multiparameter_module_approximation/combinatory.h +129 -0
  141. multipers/multiparameter_module_approximation/debug.h +107 -0
  142. multipers/multiparameter_module_approximation/euler_curves.h +0 -0
  143. multipers/multiparameter_module_approximation/format_python-cpp.h +286 -0
  144. multipers/multiparameter_module_approximation/heap_column.h +238 -0
  145. multipers/multiparameter_module_approximation/images.h +79 -0
  146. multipers/multiparameter_module_approximation/list_column.h +174 -0
  147. multipers/multiparameter_module_approximation/list_column_2.h +232 -0
  148. multipers/multiparameter_module_approximation/ru_matrix.h +347 -0
  149. multipers/multiparameter_module_approximation/set_column.h +135 -0
  150. multipers/multiparameter_module_approximation/structure_higher_dim_barcode.h +36 -0
  151. multipers/multiparameter_module_approximation/unordered_set_column.h +166 -0
  152. multipers/multiparameter_module_approximation/utilities.h +403 -0
  153. multipers/multiparameter_module_approximation/vector_column.h +223 -0
  154. multipers/multiparameter_module_approximation/vector_matrix.h +331 -0
  155. multipers/multiparameter_module_approximation/vineyards.h +464 -0
  156. multipers/multiparameter_module_approximation/vineyards_trajectories.h +649 -0
  157. multipers/multiparameter_module_approximation.cpython-311-darwin.so +0 -0
  158. multipers/multiparameter_module_approximation.pyx +235 -0
  159. multipers/pickle.py +90 -0
  160. multipers/plots.py +456 -0
  161. multipers/point_measure.cpython-311-darwin.so +0 -0
  162. multipers/point_measure.pyx +395 -0
  163. multipers/simplex_tree_multi.cpython-311-darwin.so +0 -0
  164. multipers/simplex_tree_multi.pxd +134 -0
  165. multipers/simplex_tree_multi.pyx +10840 -0
  166. multipers/simplex_tree_multi.pyx.tp +2009 -0
  167. multipers/slicer.cpython-311-darwin.so +0 -0
  168. multipers/slicer.pxd +3034 -0
  169. multipers/slicer.pxd.tp +234 -0
  170. multipers/slicer.pyx +20481 -0
  171. multipers/slicer.pyx.tp +1088 -0
  172. multipers/tensor/tensor.h +672 -0
  173. multipers/tensor.pxd +13 -0
  174. multipers/test.pyx +44 -0
  175. multipers/tests/__init__.py +62 -0
  176. multipers/torch/__init__.py +1 -0
  177. multipers/torch/diff_grids.py +240 -0
  178. multipers/torch/rips_density.py +310 -0
  179. multipers-2.3.3b6.dist-info/METADATA +128 -0
  180. multipers-2.3.3b6.dist-info/RECORD +183 -0
  181. multipers-2.3.3b6.dist-info/WHEEL +6 -0
  182. multipers-2.3.3b6.dist-info/licenses/LICENSE +21 -0
  183. multipers-2.3.3b6.dist-info/top_level.txt +1 -0
multipers/plots.py ADDED
@@ -0,0 +1,456 @@
1
+ from typing import Optional
2
+ from warnings import warn
3
+
4
+ import matplotlib.colors as mcolors
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+ from matplotlib.colors import ListedColormap
8
+ from numpy.typing import ArrayLike
9
+
10
+ from multipers.array_api import to_numpy
11
+
12
+ _custom_colors = [
13
+ "#03045e",
14
+ "#0077b6",
15
+ "#00b4d8",
16
+ "#90e0ef",
17
+ ]
18
+ _cmap_ = ListedColormap(_custom_colors)
19
+ _cmap = mcolors.LinearSegmentedColormap.from_list(
20
+ "continuous_cmap", _cmap_.colors, N=256
21
+ )
22
+
23
+
24
+ def _plot_rectangle(rectangle: np.ndarray, weight, **plt_kwargs):
25
+ rectangle = np.asarray(rectangle)
26
+ x_axis = rectangle[[0, 2]]
27
+ y_axis = rectangle[[1, 3]]
28
+ color = "blue" if weight > 0 else "red"
29
+ plt.plot(x_axis, y_axis, c=color, **plt_kwargs)
30
+
31
+
32
+ def _plot_signed_measure_2(
33
+ pts, weights, temp_alpha=0.7, threshold=(np.inf, np.inf), **plt_kwargs
34
+ ):
35
+ import matplotlib.colors
36
+
37
+ pts = np.clip(pts, a_min=-np.inf, a_max=np.asarray(threshold)[None, :])
38
+ weights = np.asarray(weights)
39
+ color_weights = np.array(weights, dtype=float)
40
+ neg_idx = weights < 0
41
+ pos_idx = weights > 0
42
+ if np.any(neg_idx):
43
+ current_weights = -weights[neg_idx]
44
+ min_weight = np.max(current_weights)
45
+ color_weights[neg_idx] /= min_weight
46
+ color_weights[neg_idx] -= 1
47
+ else:
48
+ min_weight = 0
49
+
50
+ if np.any(pos_idx):
51
+ current_weights = weights[pos_idx]
52
+ max_weight = np.max(current_weights)
53
+ color_weights[pos_idx] /= max_weight
54
+ color_weights[pos_idx] += 1
55
+ else:
56
+ max_weight = 1
57
+
58
+ bordeaux = np.array([0.70567316, 0.01555616, 0.15023281, 1])
59
+ light_bordeaux = np.array([0.70567316, 0.01555616, 0.15023281, temp_alpha])
60
+ bleu = np.array([0.2298057, 0.29871797, 0.75368315, 1])
61
+ light_bleu = np.array([0.2298057, 0.29871797, 0.75368315, temp_alpha])
62
+ norm = plt.Normalize(-2, 2)
63
+ cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
64
+ "", [bordeaux, light_bordeaux, "white", light_bleu, bleu]
65
+ )
66
+ plt.scatter(
67
+ pts[:, 0], pts[:, 1], c=color_weights, cmap=cmap, norm=norm, **plt_kwargs
68
+ )
69
+ plt.scatter([], [], color=bleu, label="positive mass", **plt_kwargs)
70
+ plt.scatter([], [], color=bordeaux, label="negative mass", **plt_kwargs)
71
+ plt.legend()
72
+
73
+
74
+ def _plot_signed_measure_4(
75
+ pts,
76
+ weights,
77
+ x_smoothing: float = 1,
78
+ area_alpha: bool = True,
79
+ threshold=(np.inf, np.inf),
80
+ alpha=None,
81
+ **plt_kwargs, # ignored ftm
82
+ ):
83
+ # compute the maximal rectangle area
84
+ pts = np.clip(pts, a_min=-np.inf, a_max=np.array((*threshold, *threshold))[None, :])
85
+ alpha_rescaling = 0
86
+ for rectangle, weight in zip(pts, weights):
87
+ if rectangle[2] >= x_smoothing * rectangle[0]:
88
+ alpha_rescaling = max(
89
+ alpha_rescaling,
90
+ (rectangle[2] / x_smoothing - rectangle[0])
91
+ * (rectangle[3] - rectangle[1]),
92
+ )
93
+ # draw the rectangles
94
+ for rectangle, weight in zip(pts, weights):
95
+ # draw only the rectangles that have not been reduced to the empty set
96
+ if rectangle[2] >= x_smoothing * rectangle[0]:
97
+ # make the alpha channel proportional to the rectangle's area
98
+ if area_alpha:
99
+ _plot_rectangle(
100
+ rectangle=[
101
+ rectangle[0],
102
+ rectangle[1],
103
+ rectangle[2] / x_smoothing,
104
+ rectangle[3],
105
+ ],
106
+ weight=weight,
107
+ alpha=(
108
+ (rectangle[2] / x_smoothing - rectangle[0])
109
+ * (rectangle[3] - rectangle[1])
110
+ / alpha_rescaling
111
+ if alpha is None
112
+ else alpha
113
+ ),
114
+ **plt_kwargs,
115
+ )
116
+ else:
117
+ _plot_rectangle(
118
+ rectangle=[
119
+ rectangle[0],
120
+ rectangle[1],
121
+ rectangle[2] / x_smoothing,
122
+ rectangle[3],
123
+ ],
124
+ weight=weight,
125
+ alpha=1 if alpha is None else alpha,
126
+ **plt_kwargs,
127
+ )
128
+
129
+
130
+ def plot_signed_measure(signed_measure, threshold=None, ax=None, **plt_kwargs):
131
+ if ax is None:
132
+ ax = plt.gca()
133
+ else:
134
+ plt.sca(ax)
135
+ pts, weights = signed_measure
136
+ pts = to_numpy(pts)
137
+ weights = to_numpy(weights)
138
+ num_pts = pts.shape[0]
139
+ num_parameters = pts.shape[1]
140
+ if threshold is None:
141
+ if num_pts == 0:
142
+ threshold = (np.inf, np.inf)
143
+ else:
144
+ if num_parameters == 4:
145
+ pts_ = np.concatenate([pts[:, :2], pts[:, 2:]], axis=0)
146
+ else:
147
+ pts_ = pts
148
+ threshold = np.max(np.ma.masked_invalid(pts_), axis=0)
149
+ threshold = np.max(
150
+ [threshold, [plt.gca().get_xlim()[1], plt.gca().get_ylim()[1]]], axis=0
151
+ )
152
+
153
+ assert num_parameters in (2, 4)
154
+ if num_parameters == 2:
155
+ _plot_signed_measure_2(
156
+ pts=pts, weights=weights, threshold=threshold, **plt_kwargs
157
+ )
158
+ else:
159
+ _plot_signed_measure_4(
160
+ pts=pts, weights=weights, threshold=threshold, **plt_kwargs
161
+ )
162
+
163
+
164
+ def plot_signed_measures(signed_measures, threshold=None, size=4):
165
+ num_degrees = len(signed_measures)
166
+ if num_degrees <= 1:
167
+ axes = [plt.gca()]
168
+ else:
169
+ fig, axes = plt.subplots(
170
+ nrows=1, ncols=num_degrees, figsize=(num_degrees * size, size)
171
+ )
172
+ for ax, signed_measure in zip(axes, signed_measures):
173
+ plot_signed_measure(signed_measure=signed_measure, ax=ax, threshold=threshold)
174
+ plt.tight_layout()
175
+
176
+
177
+ def plot_surface(
178
+ grid,
179
+ hf,
180
+ fig=None,
181
+ ax=None,
182
+ cmap: Optional[str] = None,
183
+ discrete_surface: bool = False,
184
+ has_negative_values: bool = False,
185
+ contour: bool = True,
186
+ **plt_args,
187
+ ):
188
+ import matplotlib
189
+
190
+ if ax is None:
191
+ ax = plt.gca()
192
+ else:
193
+ plt.sca(ax)
194
+ if hf.ndim == 3 and hf.shape[0] == 1:
195
+ hf = hf[0]
196
+ assert hf.ndim == 2, "Can only plot a 2d surface"
197
+ fig = plt.gcf() if fig is None else fig
198
+ if cmap is None:
199
+ if discrete_surface:
200
+ cmap = matplotlib.colormaps["gray_r"]
201
+ else:
202
+ cmap = _cmap
203
+ if discrete_surface:
204
+ if has_negative_values:
205
+ bounds = np.arange(-5, 6, 1, dtype=int)
206
+ else:
207
+ bounds = np.arange(0, 11, 1, dtype=int)
208
+ norm = matplotlib.colors.BoundaryNorm(bounds, cmap.N, extend="max")
209
+ im = ax.pcolormesh(grid[0], grid[1], hf.T, cmap=cmap, norm=norm, **plt_args)
210
+ cbar = fig.colorbar(
211
+ matplotlib.cm.ScalarMappable(cmap=cmap, norm=norm),
212
+ spacing="proportional",
213
+ ax=ax,
214
+ )
215
+ cbar.set_ticks(ticks=bounds, labels=bounds)
216
+ return im
217
+
218
+ if contour:
219
+ levels = plt_args.pop("levels", 20)
220
+ im = ax.contourf(grid[0], grid[1], hf.T, cmap=cmap, levels=levels, **plt_args)
221
+ else:
222
+ im = ax.pcolormesh(grid[0], grid[1], hf.T, cmap=cmap, **plt_args)
223
+ return im
224
+
225
+
226
+ def plot_surfaces(HF, size=4, **plt_args):
227
+ grid, hf = HF
228
+ assert (
229
+ hf.ndim == 3
230
+ ), f"Found hf.shape = {hf.shape}, expected ndim = 3 : degree, 2-parameter surface."
231
+ num_degrees = hf.shape[0]
232
+ fig, axes = plt.subplots(
233
+ nrows=1, ncols=num_degrees, figsize=(num_degrees * size, size)
234
+ )
235
+ if num_degrees == 1:
236
+ axes = [axes]
237
+ for ax, hf_of_degree in zip(axes, hf):
238
+ plot_surface(grid=grid, hf=hf_of_degree, fig=fig, ax=ax, **plt_args)
239
+ plt.tight_layout()
240
+
241
+
242
+ def _rectangle(x, y, color, alpha):
243
+ """
244
+ Defines a rectangle patch in the format {z | x  ≤ z ≤ y} with color and alpha
245
+ """
246
+ from matplotlib.patches import Rectangle as RectanglePatch
247
+
248
+ return RectanglePatch(
249
+ x, max(y[0] - x[0], 0), max(y[1] - x[1], 0), color=color, alpha=alpha
250
+ )
251
+
252
+
253
+ def _d_inf(a, b):
254
+ a = np.asarray(a)
255
+ b = np.asarray(b)
256
+ return np.min(np.abs(b - a))
257
+
258
+
259
+ def plot2d_PyModule(
260
+ corners,
261
+ box,
262
+ *,
263
+ dimension=-1,
264
+ separated=False,
265
+ min_persistence=0,
266
+ alpha=None,
267
+ verbose=False,
268
+ save=False,
269
+ dpi=200,
270
+ shapely=True,
271
+ xlabel=None,
272
+ ylabel=None,
273
+ cmap=None,
274
+ ):
275
+ import matplotlib
276
+
277
+ try:
278
+ from shapely import union_all
279
+ from shapely.geometry import Polygon as _Polygon
280
+ from shapely.geometry import box as _rectangle_box
281
+
282
+ shapely = True and shapely
283
+ except ImportError:
284
+ shapely = False
285
+ warn(
286
+ "Shapely not installed. Fallbacking to matplotlib. The plots may be inacurate."
287
+ )
288
+ if alpha is None:
289
+ alpha = 0.8 if shapely else 1
290
+ if not shapely and alpha != 1:
291
+ warn("Opacity without shapely will lead to incorect plots.")
292
+ cmap = (
293
+ matplotlib.colormaps["Spectral"] if cmap is None else matplotlib.colormaps[cmap]
294
+ )
295
+ box = list(box)
296
+ if not (separated):
297
+ # fig, ax = plt.subplots()
298
+ ax = plt.gca()
299
+ ax.set(xlim=[box[0][0], box[1][0]], ylim=[box[0][1], box[1][1]])
300
+ n_summands = len(corners)
301
+ for i in range(n_summands):
302
+ trivial_summand = True
303
+ list_of_rect = []
304
+ for birth in corners[i][0]:
305
+ if len(birth) == 1:
306
+ birth = np.asarray([birth[0]] * 2)
307
+ birth = np.asarray(birth).clip(min=box[0])
308
+ for death in corners[i][1]:
309
+ if len(death) == 1:
310
+ death = np.asarray([death[0]] * 2)
311
+ death = np.asarray(death).clip(max=box[1])
312
+ if death[1] > birth[1] and death[0] > birth[0]:
313
+ if trivial_summand and _d_inf(birth, death) > min_persistence:
314
+ trivial_summand = False
315
+ if shapely:
316
+ list_of_rect.append(
317
+ _rectangle_box(birth[0], birth[1], death[0], death[1])
318
+ )
319
+ else:
320
+ list_of_rect.append(
321
+ _rectangle(birth, death, cmap(i / n_summands), alpha)
322
+ )
323
+ if not (trivial_summand):
324
+ if separated:
325
+ fig, ax = plt.subplots()
326
+ ax.set(xlim=[box[0][0], box[1][0]], ylim=[box[0][1], box[1][1]])
327
+ if shapely:
328
+ summand_shape = union_all(list_of_rect)
329
+ if type(summand_shape) is _Polygon:
330
+ xs, ys = summand_shape.exterior.xy
331
+ ax.fill(xs, ys, alpha=alpha, fc=cmap(i / n_summands), ec="None")
332
+ else:
333
+ for polygon in summand_shape.geoms:
334
+ xs, ys = polygon.exterior.xy
335
+ ax.fill(xs, ys, alpha=alpha, fc=cmap(i / n_summands), ec="None")
336
+ else:
337
+ for rectangle in list_of_rect:
338
+ ax.add_patch(rectangle)
339
+ if separated:
340
+ if xlabel:
341
+ plt.xlabel(xlabel)
342
+ if ylabel:
343
+ plt.ylabel(ylabel)
344
+ if dimension >= 0:
345
+ plt.title(rf"$H_{dimension}$ $2$-persistence")
346
+ if not (separated):
347
+ if xlabel is not None:
348
+ plt.xlabel(xlabel)
349
+ if ylabel is not None:
350
+ plt.ylabel(ylabel)
351
+ if dimension >= 0:
352
+ plt.title(rf"$H_{dimension}$ $2$-persistence")
353
+ return
354
+
355
+
356
+ def plot_simplicial_complex(
357
+ st, pts: ArrayLike, x: float, y: float, mma=None, degree=None
358
+ ):
359
+ """
360
+ Scatters the points, with the simplices in the filtration at coordinates (x,y).
361
+ if an mma module is given, plots it in a second axis
362
+ """
363
+ if mma is not None:
364
+ fig, (a, b) = plt.subplots(ncols=2, figsize=(15, 5))
365
+ plt.sca(a)
366
+ plot_simplicial_complex(st, pts, x, y)
367
+ plt.sca(b)
368
+ mma.plot(degree=degree)
369
+ box = mma.get_box()
370
+ a, b, c, d = box.ravel()
371
+ mma.plot(degree=1, min_persistence=0.01)
372
+ plt.vlines(x, b, d, color="k", linestyle="--")
373
+ plt.hlines(y, a, c, color="k", linestyle="--")
374
+ plt.scatter([x], [y], c="r", zorder=10)
375
+ plt.text(x + 0.01 * (b - a), y + 0.01 * (d - c), f"({x},{y})")
376
+ return
377
+
378
+ pts = np.asarray(pts)
379
+ values = np.array([-f[1] for s, f in st.get_skeleton(0)])
380
+ qs = np.quantile(values, np.linspace(0, 1, 100))
381
+
382
+ def color_idx(d):
383
+ return np.searchsorted(qs, d) / 100
384
+
385
+ from matplotlib.pyplot import get_cmap
386
+
387
+ def color(d):
388
+ return get_cmap("viridis")([0, color_idx(d), 1])[1]
389
+
390
+ cols_pc = np.asarray([color(v) for v in values])
391
+ ax = plt.gca()
392
+ for s, f in st: # simplexe, filtration
393
+ density = -f[1]
394
+ if len(s) <= 1 or f[0] > x or density < -y: # simplexe = point
395
+ continue
396
+ if len(s) == 2: # simplexe = segment
397
+ xx = np.array([pts[a, 0] for a in s])
398
+ yy = np.array([pts[a, 1] for a in s])
399
+ plt.plot(xx, yy, c=color(density), alpha=1, zorder=10 * density, lw=1.5)
400
+ if len(s) == 3: # simplexe = triangle
401
+ xx = np.array([pts[a, 0] for a in s])
402
+ yy = np.array([pts[a, 1] for a in s])
403
+ _c = color(density)
404
+ ax.fill(xx, yy, c=_c, alpha=0.3, zorder=0)
405
+ out = plt.scatter(pts[:, 0], pts[:, 1], c=cols_pc, zorder=10, s=10)
406
+ ax.set_aspect(1)
407
+ return out
408
+
409
+
410
+ def plot_point_cloud(
411
+ pts,
412
+ function,
413
+ x,
414
+ y,
415
+ mma=None,
416
+ degree=None,
417
+ ball_alpha=0.3,
418
+ point_cmap="viridis",
419
+ color_bias=1,
420
+ ball_color=None,
421
+ point_size=20,
422
+ ):
423
+ if mma is not None:
424
+ fig, (a, b) = plt.subplots(ncols=2, figsize=(15, 5))
425
+ plt.sca(a)
426
+ plot_point_cloud(pts, function, x, y)
427
+ plt.sca(b)
428
+ mma.plot(degree=degree)
429
+ box = mma.get_box()
430
+ a, b, c, d = box.ravel()
431
+ mma.plot(degree=1, min_persistence=0.01)
432
+ plt.vlines(x, b, d, color="k", linestyle="--")
433
+ plt.hlines(y, a, c, color="k", linestyle="--")
434
+ plt.scatter([x], [y], c="r", zorder=10)
435
+ plt.text(x + 0.01 * (b - a), y + 0.01 * (d - c), f"({x},{y})")
436
+ return
437
+ values = -function
438
+ qs = np.quantile(values, np.linspace(0, 1, 100))
439
+
440
+ def color_idx(d):
441
+ return np.searchsorted(qs, d * color_bias) / 100
442
+
443
+ from matplotlib.collections import PatchCollection
444
+ from matplotlib.pyplot import get_cmap
445
+
446
+ def color(d):
447
+ return get_cmap(point_cmap)([0, color_idx(d), 1])[1]
448
+
449
+ _colors = np.array([color(v) for v in values])
450
+ ax = plt.gca()
451
+ idx = function <= y
452
+ circles = [plt.Circle(pt, x) for pt, c in zip(pts[idx], function)]
453
+ pc = PatchCollection(circles, alpha=ball_alpha, color=ball_color)
454
+ ax.add_collection(pc)
455
+ plt.scatter(*pts.T, c=_colors, s=point_size)
456
+ ax.set_aspect(1)