plotlp 0.1.16__tar.gz → 0.1.18__tar.gz
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.
- {plotlp-0.1.16 → plotlp-0.1.18}/PKG-INFO +1 -1
- {plotlp-0.1.16 → plotlp-0.1.18}/pyproject.toml +1 -1
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/__init__.py +1 -0
- plotlp-0.1.18/src/plotlp/modules/compare_distributions_LP/compare_distributions.py +326 -0
- plotlp-0.1.18/src/plotlp/modules/compare_distributions_LP/test_compare_distributions.py +52 -0
- plotlp-0.1.18/src/plotlp/modules/subplots_LP/_doctype.txt +1 -0
- plotlp-0.1.18/src/plotlp/modules/subplots_LP/_functions/__template__.py +19 -0
- plotlp-0.1.18/src/plotlp/py.typed +0 -0
- plotlp-0.1.18/src/plotlp/routines/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/README.md +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/.docignore +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledAxes_LP/StyledAxes.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledAxes_LP/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledAxes_LP/_doctype.txt +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledAxes_LP/_functions/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledAxes_LP/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledAxes_LP/_functions/scalebar.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledAxes_LP/test_StyledAxes.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledFigure_LP/StyledFigure.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledFigure_LP/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledFigure_LP/_doctype.txt +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledFigure_LP/_functions/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledFigure_LP/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledFigure_LP/test_StyledFigure.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/cmap_LP/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/cmap_LP/_doctype.txt +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/cmap_LP/_functions/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/cmap_LP/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/cmap_LP/cmap.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/cmap_LP/test_cmap.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/color_LP/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/color_LP/_doctype.txt +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/color_LP/_functions/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/color_LP/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/color_LP/color.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/color_LP/test_color.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/figure_LP → plotlp-0.1.18/src/plotlp/modules/compare_distributions_LP}/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/figure_LP → plotlp-0.1.18/src/plotlp/modules/compare_distributions_LP}/_doctype.txt +0 -0
- {plotlp-0.1.16/src/plotlp/modules/figure_LP → plotlp-0.1.18/src/plotlp/modules/compare_distributions_LP}/_functions/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/figure_LP → plotlp-0.1.18/src/plotlp/modules/compare_distributions_LP}/_functions/__template__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/gridsubplots_LP → plotlp-0.1.18/src/plotlp/modules/figure_LP}/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/gridsubplots_LP → plotlp-0.1.18/src/plotlp/modules/figure_LP}/_doctype.txt +0 -0
- {plotlp-0.1.16/src/plotlp/modules/gridsubplots_LP → plotlp-0.1.18/src/plotlp/modules/figure_LP}/_functions/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/gridsubplots_LP → plotlp-0.1.18/src/plotlp/modules/figure_LP}/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/figure_LP/figure.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/figure_LP/test_figure.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/imgfigure_LP → plotlp-0.1.18/src/plotlp/modules/gridsubplots_LP}/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/imgfigure_LP → plotlp-0.1.18/src/plotlp/modules/gridsubplots_LP}/_doctype.txt +0 -0
- {plotlp-0.1.16/src/plotlp/modules/imgfigure_LP → plotlp-0.1.18/src/plotlp/modules/gridsubplots_LP}/_functions/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/imgfigure_LP → plotlp-0.1.18/src/plotlp/modules/gridsubplots_LP}/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/gridsubplots_LP/gridsubplots.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/gridsubplots_LP/test_gridsubplots.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/make_animation_LP → plotlp-0.1.18/src/plotlp/modules/imgfigure_LP}/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/make_animation_LP → plotlp-0.1.18/src/plotlp/modules/imgfigure_LP}/_doctype.txt +0 -0
- {plotlp-0.1.16/src/plotlp/modules/make_animation_LP → plotlp-0.1.18/src/plotlp/modules/imgfigure_LP}/_functions/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/make_animation_LP → plotlp-0.1.18/src/plotlp/modules/imgfigure_LP}/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/imgfigure_LP/imgfigure.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/imgfigure_LP/test_imgfigure.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/plt_LP → plotlp-0.1.18/src/plotlp/modules/make_animation_LP}/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/plt_LP → plotlp-0.1.18/src/plotlp/modules/make_animation_LP}/_doctype.txt +0 -0
- {plotlp-0.1.16/src/plotlp/modules/plt_LP → plotlp-0.1.18/src/plotlp/modules/make_animation_LP}/_functions/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/plt_LP → plotlp-0.1.18/src/plotlp/modules/make_animation_LP}/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/make_animation_LP/make_animation.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/make_animation_LP/test_make_animation.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/style_LP → plotlp-0.1.18/src/plotlp/modules/plt_LP}/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/style_LP → plotlp-0.1.18/src/plotlp/modules/plt_LP}/_doctype.txt +0 -0
- {plotlp-0.1.16/src/plotlp/modules/style_LP → plotlp-0.1.18/src/plotlp/modules/plt_LP}/_functions/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/style_LP → plotlp-0.1.18/src/plotlp/modules/plt_LP}/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/plt_LP/plt.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/plt_LP/test_plt.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/subplots_LP → plotlp-0.1.18/src/plotlp/modules/style_LP}/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/subplots_LP → plotlp-0.1.18/src/plotlp/modules/style_LP}/_doctype.txt +0 -0
- {plotlp-0.1.16/src/plotlp/modules/subplots_LP → plotlp-0.1.18/src/plotlp/modules/style_LP}/_functions/__init__.py +0 -0
- {plotlp-0.1.16/src/plotlp/modules/subplots_LP → plotlp-0.1.18/src/plotlp/modules/style_LP}/_functions/__template__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/style_LP/_functions/_darkLP.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/style_LP/_functions/_default.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/style_LP/_functions/_lightLP.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/style_LP/_functions/_styleLP.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/style_LP/style.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/style_LP/test_style.py +0 -0
- {plotlp-0.1.16/src/plotlp/routines → plotlp-0.1.18/src/plotlp/modules/subplots_LP}/__init__.py +0 -0
- /plotlp-0.1.16/src/plotlp/py.typed → /plotlp-0.1.18/src/plotlp/modules/subplots_LP/_functions/__init__.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/subplots_LP/subplots.py +0 -0
- {plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/subplots_LP/test_subplots.py +0 -0
|
@@ -17,6 +17,7 @@ sources = {
|
|
|
17
17
|
'StyledFigure': 'plotlp.modules.StyledFigure_LP.StyledFigure',
|
|
18
18
|
'cmap': 'plotlp.modules.cmap_LP.cmap',
|
|
19
19
|
'color': 'plotlp.modules.color_LP.color',
|
|
20
|
+
'compare_distributions': 'plotlp.modules.compare_distributions_LP.compare_distributions',
|
|
20
21
|
'figure': 'plotlp.modules.figure_LP.figure',
|
|
21
22
|
'gridsubplots': 'plotlp.modules.gridsubplots_LP.gridsubplots',
|
|
22
23
|
'imgfigure': 'plotlp.modules.imgfigure_LP.imgfigure',
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Date : 2026-05-28
|
|
4
|
+
# Author : Lancelot PINCET
|
|
5
|
+
# GitHub : https://github.com/LancelotPincet
|
|
6
|
+
# Library : plotLP
|
|
7
|
+
# Module : compare_distributions
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
This function create a figure which compares distributions via histograms and scatterplots.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# %% Libraries
|
|
16
|
+
import numpy as np
|
|
17
|
+
from plotlp import subplots
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# %% Function
|
|
22
|
+
def compare_distributions(
|
|
23
|
+
*vectors,
|
|
24
|
+
labels=None,
|
|
25
|
+
hue=None,
|
|
26
|
+
npoints=1000,
|
|
27
|
+
bins=64,
|
|
28
|
+
percentile=99,
|
|
29
|
+
bissectrice=False,
|
|
30
|
+
title=None,
|
|
31
|
+
):
|
|
32
|
+
"""Compare distributions with pairwise scatterplots and diagonal histograms."""
|
|
33
|
+
if len(vectors) < 2:
|
|
34
|
+
raise ValueError("compare_distributions requires at least two vectors")
|
|
35
|
+
|
|
36
|
+
vectors = [np.asarray(vector, dtype=np.float32).ravel() for vector in vectors]
|
|
37
|
+
n = len(vectors)
|
|
38
|
+
|
|
39
|
+
if labels is None:
|
|
40
|
+
labels = [f"Vector {index + 1}" for index in range(n)]
|
|
41
|
+
labels = list(labels)
|
|
42
|
+
if len(labels) != n:
|
|
43
|
+
raise ValueError("labels length must match the number of vectors")
|
|
44
|
+
|
|
45
|
+
if hue is not None:
|
|
46
|
+
hue = np.asarray(hue).ravel()
|
|
47
|
+
expected_size = vectors[0].size
|
|
48
|
+
if any(vector.size != expected_size for vector in vectors):
|
|
49
|
+
raise ValueError("all vectors must have the same size when hue is provided")
|
|
50
|
+
if hue.size != expected_size:
|
|
51
|
+
raise ValueError("hue length must match vector length")
|
|
52
|
+
categories = list(dict.fromkeys(hue.tolist()))
|
|
53
|
+
else:
|
|
54
|
+
categories = [None]
|
|
55
|
+
|
|
56
|
+
npoints = int(npoints)
|
|
57
|
+
if npoints < 1:
|
|
58
|
+
raise ValueError("npoints must be >= 1")
|
|
59
|
+
|
|
60
|
+
percentile = float(percentile)
|
|
61
|
+
if percentile <= 0 or percentile > 100:
|
|
62
|
+
raise ValueError("percentile must be in (0, 100]")
|
|
63
|
+
q_low = (100 - percentile) / 2
|
|
64
|
+
q_high = 100 - q_low
|
|
65
|
+
|
|
66
|
+
global_scatter_limits = None
|
|
67
|
+
if bissectrice:
|
|
68
|
+
finite_all = [values[np.isfinite(values)] for values in vectors]
|
|
69
|
+
finite_all = [values for values in finite_all if values.size]
|
|
70
|
+
if finite_all:
|
|
71
|
+
limits_values = np.concatenate(finite_all)
|
|
72
|
+
low = float(np.nanpercentile(limits_values, q_low))
|
|
73
|
+
high = float(np.nanpercentile(limits_values, q_high))
|
|
74
|
+
if high <= low:
|
|
75
|
+
high = low + 1.0
|
|
76
|
+
global_scatter_limits = (low, high)
|
|
77
|
+
|
|
78
|
+
color_map = {category: f"C{index % 10}" for index, category in enumerate(categories)}
|
|
79
|
+
|
|
80
|
+
if n == 2:
|
|
81
|
+
figure, axes = subplots(
|
|
82
|
+
2,
|
|
83
|
+
2,
|
|
84
|
+
figsize_ratio=1,
|
|
85
|
+
dpi=100,
|
|
86
|
+
sharex="col",
|
|
87
|
+
gridspec_kw={"width_ratios": [3, 1], "height_ratios": [1, 3]},
|
|
88
|
+
)
|
|
89
|
+
ax_hist_x = axes[0, 0]
|
|
90
|
+
ax_scatter = axes[1, 0]
|
|
91
|
+
ax_hist_y = axes[1, 1]
|
|
92
|
+
axes[0, 1].axis("off")
|
|
93
|
+
|
|
94
|
+
x_values, y_values = vectors
|
|
95
|
+
pair_mask = np.isfinite(x_values) & np.isfinite(y_values)
|
|
96
|
+
if hue is None:
|
|
97
|
+
category_masks = [(None, pair_mask)]
|
|
98
|
+
else:
|
|
99
|
+
category_masks = [
|
|
100
|
+
(category, pair_mask & (hue == category)) for category in categories
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
x_finite = x_values[np.isfinite(x_values)]
|
|
104
|
+
y_finite = y_values[np.isfinite(y_values)]
|
|
105
|
+
if x_finite.size:
|
|
106
|
+
if bissectrice and global_scatter_limits is not None:
|
|
107
|
+
_low, _high = global_scatter_limits
|
|
108
|
+
x_bins = np.linspace(_low, _high, int(bins) + 1, dtype=np.float32)
|
|
109
|
+
else:
|
|
110
|
+
x_bins = np.histogram_bin_edges(x_finite, bins=bins)
|
|
111
|
+
for category, mask in category_masks:
|
|
112
|
+
x_mask = mask if hue is None else np.isfinite(x_values) & (hue == category)
|
|
113
|
+
x_cat = x_values[x_mask]
|
|
114
|
+
x_cat = x_cat[np.isfinite(x_cat)]
|
|
115
|
+
if x_cat.size:
|
|
116
|
+
ax_hist_x.hist(
|
|
117
|
+
x_cat,
|
|
118
|
+
bins=x_bins,
|
|
119
|
+
alpha=0.45,
|
|
120
|
+
edgecolor=color_map[category],
|
|
121
|
+
linewidth=0.8,
|
|
122
|
+
color=color_map[category],
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if y_finite.size:
|
|
126
|
+
if bissectrice and global_scatter_limits is not None:
|
|
127
|
+
_low, _high = global_scatter_limits
|
|
128
|
+
y_bins = np.linspace(_low, _high, int(bins) + 1, dtype=np.float32)
|
|
129
|
+
else:
|
|
130
|
+
y_bins = np.histogram_bin_edges(y_finite, bins=bins)
|
|
131
|
+
for category, mask in category_masks:
|
|
132
|
+
y_mask = mask if hue is None else np.isfinite(y_values) & (hue == category)
|
|
133
|
+
y_cat = y_values[y_mask]
|
|
134
|
+
y_cat = y_cat[np.isfinite(y_cat)]
|
|
135
|
+
if y_cat.size:
|
|
136
|
+
ax_hist_y.hist(
|
|
137
|
+
y_cat,
|
|
138
|
+
bins=y_bins,
|
|
139
|
+
alpha=0.45,
|
|
140
|
+
edgecolor=color_map[category],
|
|
141
|
+
linewidth=0.8,
|
|
142
|
+
color=color_map[category],
|
|
143
|
+
orientation="horizontal",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
rng = np.random.default_rng(0)
|
|
147
|
+
points_drawn = 0
|
|
148
|
+
for category, mask in category_masks:
|
|
149
|
+
indices = np.flatnonzero(mask)
|
|
150
|
+
if indices.size == 0:
|
|
151
|
+
continue
|
|
152
|
+
sample_size = min(npoints, indices.size)
|
|
153
|
+
sample_indices = rng.choice(indices, size=sample_size, replace=False)
|
|
154
|
+
points_drawn += sample_size
|
|
155
|
+
ax_scatter.scatter(
|
|
156
|
+
x_values[sample_indices],
|
|
157
|
+
y_values[sample_indices],
|
|
158
|
+
s=6,
|
|
159
|
+
alpha=0.35,
|
|
160
|
+
color=color_map[category],
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if points_drawn == 0:
|
|
164
|
+
ax_scatter.text(0.5, 0.5, "No finite paired values", ha="center", va="center")
|
|
165
|
+
|
|
166
|
+
ax_scatter.set_xlabel(labels[0])
|
|
167
|
+
ax_scatter.set_ylabel(labels[1])
|
|
168
|
+
ax_scatter.polish_equiscale = True
|
|
169
|
+
ax_hist_x.set_ylabel("Counts")
|
|
170
|
+
ax_hist_y.set_xlabel("Counts")
|
|
171
|
+
ax_hist_x.tick_params(axis="x", labelbottom=False)
|
|
172
|
+
ax_hist_y.tick_params(axis="y", labelleft=False)
|
|
173
|
+
ax_hist_x.polish_grids = True
|
|
174
|
+
ax_hist_y.polish_grids = True
|
|
175
|
+
|
|
176
|
+
if bissectrice and np.any(pair_mask):
|
|
177
|
+
low, high = global_scatter_limits
|
|
178
|
+
ax_scatter.plot([low, high], [low, high], "k--", linewidth=1.2)
|
|
179
|
+
ax_scatter.set_xlim(low, high)
|
|
180
|
+
ax_scatter.set_ylim(low, high)
|
|
181
|
+
ax_hist_x.set_xlim(low, high)
|
|
182
|
+
ax_hist_y.set_ylim(low, high)
|
|
183
|
+
elif np.any(pair_mask):
|
|
184
|
+
x_pair = x_values[pair_mask]
|
|
185
|
+
y_pair = y_values[pair_mask]
|
|
186
|
+
x_low = float(np.nanpercentile(x_pair, q_low))
|
|
187
|
+
x_high = float(np.nanpercentile(x_pair, q_high))
|
|
188
|
+
y_low = float(np.nanpercentile(y_pair, q_low))
|
|
189
|
+
y_high = float(np.nanpercentile(y_pair, q_high))
|
|
190
|
+
if x_high <= x_low:
|
|
191
|
+
x_high = x_low + 1.0
|
|
192
|
+
if y_high <= y_low:
|
|
193
|
+
y_high = y_low + 1.0
|
|
194
|
+
ax_scatter.set_xlim(x_low, x_high)
|
|
195
|
+
ax_scatter.set_ylim(y_low, y_high)
|
|
196
|
+
|
|
197
|
+
if title is not None:
|
|
198
|
+
figure.title = title
|
|
199
|
+
return figure
|
|
200
|
+
|
|
201
|
+
figure, axes = subplots(
|
|
202
|
+
n,
|
|
203
|
+
n,
|
|
204
|
+
figsize_fact=(n / 2, n / 2),
|
|
205
|
+
figsize_ratio=1,
|
|
206
|
+
dpi=100,
|
|
207
|
+
sharex="col",
|
|
208
|
+
)
|
|
209
|
+
rng = np.random.default_rng(0)
|
|
210
|
+
|
|
211
|
+
for i in range(n):
|
|
212
|
+
for j in range(n):
|
|
213
|
+
axis = axes[i, j]
|
|
214
|
+
if i < j:
|
|
215
|
+
axis.axis("off")
|
|
216
|
+
continue
|
|
217
|
+
|
|
218
|
+
if i == j:
|
|
219
|
+
values = vectors[i]
|
|
220
|
+
finite = values[np.isfinite(values)]
|
|
221
|
+
axis.set_box_aspect(1)
|
|
222
|
+
if finite.size == 0:
|
|
223
|
+
axis.text(0.5, 0.5, "No finite values", ha="center", va="center")
|
|
224
|
+
else:
|
|
225
|
+
if bissectrice and global_scatter_limits is not None:
|
|
226
|
+
_low, _high = global_scatter_limits
|
|
227
|
+
edges = np.linspace(_low, _high, int(bins) + 1, dtype=np.float32)
|
|
228
|
+
else:
|
|
229
|
+
edges = np.histogram_bin_edges(finite, bins=bins)
|
|
230
|
+
for category in categories:
|
|
231
|
+
if hue is None:
|
|
232
|
+
category_values = finite
|
|
233
|
+
else:
|
|
234
|
+
category_mask = np.isfinite(values) & (hue == category)
|
|
235
|
+
category_values = values[category_mask]
|
|
236
|
+
if category_values.size:
|
|
237
|
+
axis.hist(
|
|
238
|
+
category_values,
|
|
239
|
+
bins=edges,
|
|
240
|
+
alpha=0.45,
|
|
241
|
+
edgecolor=color_map[category],
|
|
242
|
+
linewidth=0.8,
|
|
243
|
+
color=color_map[category],
|
|
244
|
+
)
|
|
245
|
+
axis.set_ylabel("Counts")
|
|
246
|
+
axis.polish_grids = True
|
|
247
|
+
if bissectrice and global_scatter_limits is not None:
|
|
248
|
+
_low, _high = global_scatter_limits
|
|
249
|
+
axis.set_xlim(_low, _high)
|
|
250
|
+
if i == n - 1:
|
|
251
|
+
axis.set_xlabel(labels[j])
|
|
252
|
+
else:
|
|
253
|
+
axis.set_xlabel("")
|
|
254
|
+
axis.tick_params(axis="x", labelbottom=False)
|
|
255
|
+
continue
|
|
256
|
+
|
|
257
|
+
x_values = vectors[j]
|
|
258
|
+
y_values = vectors[i]
|
|
259
|
+
pair_mask = np.isfinite(x_values) & np.isfinite(y_values)
|
|
260
|
+
if hue is None:
|
|
261
|
+
category_masks = [(None, pair_mask)]
|
|
262
|
+
else:
|
|
263
|
+
category_masks = [
|
|
264
|
+
(category, pair_mask & (hue == category)) for category in categories
|
|
265
|
+
]
|
|
266
|
+
|
|
267
|
+
points_drawn = 0
|
|
268
|
+
for category, mask in category_masks:
|
|
269
|
+
indices = np.flatnonzero(mask)
|
|
270
|
+
if indices.size == 0:
|
|
271
|
+
continue
|
|
272
|
+
sample_size = min(npoints, indices.size)
|
|
273
|
+
sample_indices = rng.choice(indices, size=sample_size, replace=False)
|
|
274
|
+
points_drawn += sample_size
|
|
275
|
+
axis.scatter(
|
|
276
|
+
x_values[sample_indices],
|
|
277
|
+
y_values[sample_indices],
|
|
278
|
+
s=5,
|
|
279
|
+
alpha=0.35,
|
|
280
|
+
color=color_map[category],
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
if points_drawn == 0:
|
|
284
|
+
axis.text(0.5, 0.5, "No finite paired values", ha="center", va="center")
|
|
285
|
+
|
|
286
|
+
axis.polish_equiscale = True
|
|
287
|
+
if i == n - 1:
|
|
288
|
+
axis.set_xlabel(labels[j])
|
|
289
|
+
else:
|
|
290
|
+
axis.set_xlabel("")
|
|
291
|
+
axis.tick_params(axis="x", labelbottom=False)
|
|
292
|
+
if j == 0:
|
|
293
|
+
axis.set_ylabel(labels[i])
|
|
294
|
+
else:
|
|
295
|
+
axis.set_ylabel("")
|
|
296
|
+
axis.tick_params(axis="y", labelleft=False)
|
|
297
|
+
|
|
298
|
+
if bissectrice and np.any(pair_mask):
|
|
299
|
+
low, high = global_scatter_limits
|
|
300
|
+
axis.plot([low, high], [low, high], "k--", linewidth=1.0)
|
|
301
|
+
axis.set_xlim(low, high)
|
|
302
|
+
axis.set_ylim(low, high)
|
|
303
|
+
elif np.any(pair_mask):
|
|
304
|
+
x_pair = x_values[pair_mask]
|
|
305
|
+
y_pair = y_values[pair_mask]
|
|
306
|
+
x_low = float(np.nanpercentile(x_pair, q_low))
|
|
307
|
+
x_high = float(np.nanpercentile(x_pair, q_high))
|
|
308
|
+
y_low = float(np.nanpercentile(y_pair, q_low))
|
|
309
|
+
y_high = float(np.nanpercentile(y_pair, q_high))
|
|
310
|
+
if x_high <= x_low:
|
|
311
|
+
x_high = x_low + 1.0
|
|
312
|
+
if y_high <= y_low:
|
|
313
|
+
y_high = y_low + 1.0
|
|
314
|
+
axis.set_xlim(x_low, x_high)
|
|
315
|
+
axis.set_ylim(y_low, y_high)
|
|
316
|
+
|
|
317
|
+
if title is not None:
|
|
318
|
+
figure.title = title
|
|
319
|
+
return figure
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
# %% Test function run
|
|
324
|
+
if __name__ == "__main__":
|
|
325
|
+
from corelp import test
|
|
326
|
+
test(__file__)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Date : 2026-05-28
|
|
4
|
+
# Author : Lancelot PINCET
|
|
5
|
+
# GitHub : https://github.com/LancelotPincet
|
|
6
|
+
# Library : plotLP
|
|
7
|
+
# Module : compare_distributions
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
This file allows to test compare_distributions
|
|
11
|
+
|
|
12
|
+
compare_distributions : This function create a figure which compares distributions via histograms and scatterplots.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# %% Libraries
|
|
18
|
+
import numpy as np
|
|
19
|
+
import pytest
|
|
20
|
+
from plotlp import compare_distributions
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# %% Function test
|
|
25
|
+
def test_two_vectors_returns_figure():
|
|
26
|
+
"""Two vectors should return a figure."""
|
|
27
|
+
x = np.arange(20, dtype=np.float32)
|
|
28
|
+
y = x + 1
|
|
29
|
+
figure = compare_distributions(x, y)
|
|
30
|
+
assert figure is not None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_multiple_vectors_returns_figure():
|
|
34
|
+
"""Three vectors should return a pairwise-plot figure."""
|
|
35
|
+
x = np.arange(30, dtype=np.float32)
|
|
36
|
+
y = x * 2
|
|
37
|
+
z = x * 3
|
|
38
|
+
figure = compare_distributions(x, y, z, bissectrice=True)
|
|
39
|
+
assert figure is not None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_requires_at_least_two_vectors():
|
|
43
|
+
"""One vector should raise an error."""
|
|
44
|
+
with pytest.raises(ValueError, match="at least two vectors"):
|
|
45
|
+
compare_distributions(np.arange(10))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# %% Test function run
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
from corelp import test
|
|
52
|
+
test(__file__)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
default
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Author : Lancelot PINCET
|
|
4
|
+
# GitHub : https://github.com/LancelotPincet
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# %% Libraries
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# %% Function
|
|
14
|
+
def temp(**kwargs) :
|
|
15
|
+
'''
|
|
16
|
+
TODO
|
|
17
|
+
'''
|
|
18
|
+
|
|
19
|
+
print('Hello world!')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plotlp-0.1.16 → plotlp-0.1.18}/src/plotlp/modules/StyledFigure_LP/_functions/__template__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plotlp-0.1.16/src/plotlp/modules/style_LP → plotlp-0.1.18/src/plotlp/modules/plt_LP}/__init__.py
RENAMED
|
File without changes
|
{plotlp-0.1.16/src/plotlp/modules/style_LP → plotlp-0.1.18/src/plotlp/modules/plt_LP}/_doctype.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{plotlp-0.1.16/src/plotlp/routines → plotlp-0.1.18/src/plotlp/modules/subplots_LP}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|