plothist 1.5.0__py3-none-any.whl → 1.6.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.
- plothist/__init__.py +5 -5
- plothist/_version.py +2 -2
- plothist/comparison.py +61 -17
- plothist/examples/utility/uncertainty_types.py +120 -0
- plothist/plothist_style.py +2 -2
- plothist/plotters.py +3 -1
- {plothist-1.5.0.dist-info → plothist-1.6.0.dist-info}/METADATA +1 -1
- {plothist-1.5.0.dist-info → plothist-1.6.0.dist-info}/RECORD +11 -10
- {plothist-1.5.0.dist-info → plothist-1.6.0.dist-info}/WHEEL +0 -0
- {plothist-1.5.0.dist-info → plothist-1.6.0.dist-info}/licenses/AUTHORS.md +0 -0
- {plothist-1.5.0.dist-info → plothist-1.6.0.dist-info}/licenses/LICENSE +0 -0
plothist/__init__.py
CHANGED
|
@@ -85,18 +85,19 @@ __all__ = [
|
|
|
85
85
|
]
|
|
86
86
|
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
from importlib import resources
|
|
89
89
|
from importlib.resources import files
|
|
90
90
|
|
|
91
|
+
import boost_histogram as bh
|
|
92
|
+
import matplotlib.font_manager as fm
|
|
91
93
|
import matplotlib.pyplot as plt
|
|
92
94
|
|
|
95
|
+
# Get style file and use it
|
|
96
|
+
|
|
93
97
|
style_file = files("plothist").joinpath("default_style.mplstyle")
|
|
94
98
|
plt.style.use(style_file)
|
|
95
99
|
|
|
96
100
|
# Install fonts
|
|
97
|
-
from importlib import resources
|
|
98
|
-
|
|
99
|
-
import matplotlib.font_manager as fm
|
|
100
101
|
|
|
101
102
|
with resources.as_file(resources.files("plothist_utils") / "fonts") as font_path:
|
|
102
103
|
font_files = fm.findSystemFonts(fontpaths=[str(font_path)])
|
|
@@ -104,7 +105,6 @@ with resources.as_file(resources.files("plothist_utils") / "fonts") as font_path
|
|
|
104
105
|
fm.fontManager.addfont(font)
|
|
105
106
|
|
|
106
107
|
# Check version of boost_histogram
|
|
107
|
-
import boost_histogram as bh
|
|
108
108
|
|
|
109
109
|
if tuple(int(part) for part in bh.__version__.split(".")) < (1, 4, 0):
|
|
110
110
|
raise ImportError(
|
plothist/_version.py
CHANGED
plothist/comparison.py
CHANGED
|
@@ -22,9 +22,16 @@ def _check_uncertainty_type(uncertainty_type: str) -> None:
|
|
|
22
22
|
If the uncertainty type is not valid.
|
|
23
23
|
|
|
24
24
|
"""
|
|
25
|
-
|
|
25
|
+
_valid_uncertainty_types = [
|
|
26
|
+
"symmetrical",
|
|
27
|
+
"asymmetrical",
|
|
28
|
+
"asymmetrical_double_sided_zeros",
|
|
29
|
+
"asymmetrical_one_sided_zeros",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
if uncertainty_type not in _valid_uncertainty_types:
|
|
26
33
|
raise ValueError(
|
|
27
|
-
f"Uncertainty type {uncertainty_type} not valid. Must be
|
|
34
|
+
f"Uncertainty type {uncertainty_type} not valid. Must be in {_valid_uncertainty_types}."
|
|
28
35
|
)
|
|
29
36
|
|
|
30
37
|
|
|
@@ -42,11 +49,12 @@ def _is_unweighted(hist: bh.Histogram) -> bool:
|
|
|
42
49
|
bool
|
|
43
50
|
True if the histogram is unweighted, False otherwise.
|
|
44
51
|
"""
|
|
45
|
-
return np.allclose(hist.variances(), hist.values())
|
|
52
|
+
return np.allclose(hist.variances(), hist.values(), equal_nan=True)
|
|
46
53
|
|
|
47
54
|
|
|
48
55
|
def get_asymmetrical_uncertainties(
|
|
49
56
|
hist: bh.Histogram,
|
|
57
|
+
uncertainty_type: str = "asymmetrical",
|
|
50
58
|
) -> tuple[np.ndarray, np.ndarray]:
|
|
51
59
|
"""
|
|
52
60
|
Get Poisson asymmetrical uncertainties for a histogram via a frequentist approach based on a confidence-interval computation.
|
|
@@ -57,6 +65,8 @@ def get_asymmetrical_uncertainties(
|
|
|
57
65
|
----------
|
|
58
66
|
hist : bh.Histogram
|
|
59
67
|
The histogram.
|
|
68
|
+
uncertainty_type : str, optional
|
|
69
|
+
The type of uncertainty to compute for bins with 0 entry. Default is "asymmetrical" (= "asymmetrical_one_sided_zeros"). Use "asymmetrical_double_sided_zeros" to have the double-sided definition. More information in :ref:`documentation-statistics-label`.
|
|
60
70
|
|
|
61
71
|
Returns
|
|
62
72
|
-------
|
|
@@ -72,16 +82,44 @@ def get_asymmetrical_uncertainties(
|
|
|
72
82
|
|
|
73
83
|
"""
|
|
74
84
|
_check_counting_histogram(hist)
|
|
85
|
+
_check_uncertainty_type(uncertainty_type)
|
|
75
86
|
|
|
76
87
|
if not _is_unweighted(hist):
|
|
77
88
|
raise ValueError(
|
|
78
89
|
"Asymmetrical uncertainties can only be computed for an unweighted histogram."
|
|
79
90
|
)
|
|
80
|
-
|
|
81
|
-
alpha = 1.0 -
|
|
91
|
+
|
|
92
|
+
alpha = 1.0 - 0.682689492
|
|
93
|
+
tail_probability = alpha / 2
|
|
94
|
+
|
|
82
95
|
n = hist.values()
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
|
|
97
|
+
lower_bound = np.zeros_like(n, dtype=float)
|
|
98
|
+
upper_bound = np.zeros_like(n, dtype=float)
|
|
99
|
+
|
|
100
|
+
# Two-sided Garwood intervals for n > 0
|
|
101
|
+
lower_bound[n > 0] = stats.gamma.ppf(q=tail_probability, a=n[n > 0], scale=1)
|
|
102
|
+
upper_bound[n > 0] = stats.gamma.ppf(
|
|
103
|
+
q=1 - tail_probability, a=n[n > 0] + 1, scale=1
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if uncertainty_type == "asymmetrical_double_sided_zeros":
|
|
107
|
+
# Two-sided Garwood intervals for n == 0
|
|
108
|
+
upper_bound[n == 0] = stats.gamma.ppf(q=1 - tail_probability, a=1, scale=1)
|
|
109
|
+
elif uncertainty_type in ["asymmetrical_one_sided_zeros", "asymmetrical"]:
|
|
110
|
+
# One-sided upper limit for n == 0
|
|
111
|
+
upper_bound[n == 0] = stats.gamma.ppf(q=1 - 2 * tail_probability, a=1, scale=1)
|
|
112
|
+
else:
|
|
113
|
+
raise ValueError(
|
|
114
|
+
f"Invalid uncertainty type '{uncertainty_type}' for asymmetrical uncertainties."
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Compute asymmetric uncertainties
|
|
118
|
+
uncertainties_low = n - lower_bound
|
|
119
|
+
uncertainties_high = upper_bound - n
|
|
120
|
+
|
|
121
|
+
uncertainties_low = np.nan_to_num(uncertainties_low, nan=0.0)
|
|
122
|
+
uncertainties_high = np.nan_to_num(uncertainties_high, nan=0.0)
|
|
85
123
|
|
|
86
124
|
return uncertainties_low, uncertainties_high
|
|
87
125
|
|
|
@@ -174,8 +212,10 @@ def get_pull(
|
|
|
174
212
|
_check_counting_histogram(h1)
|
|
175
213
|
_check_counting_histogram(h2)
|
|
176
214
|
|
|
177
|
-
if
|
|
178
|
-
uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
|
|
215
|
+
if "asymmetrical" in h1_uncertainty_type:
|
|
216
|
+
uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
|
|
217
|
+
h1, h1_uncertainty_type
|
|
218
|
+
)
|
|
179
219
|
h1_variances = np.where(
|
|
180
220
|
h1.values() >= h2.values(),
|
|
181
221
|
uncertainties_low**2,
|
|
@@ -232,8 +272,10 @@ def get_difference(
|
|
|
232
272
|
|
|
233
273
|
difference_values = h1.values() - h2.values()
|
|
234
274
|
|
|
235
|
-
if
|
|
236
|
-
uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
|
|
275
|
+
if "asymmetrical" in h1_uncertainty_type:
|
|
276
|
+
uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
|
|
277
|
+
h1, h1_uncertainty_type
|
|
278
|
+
)
|
|
237
279
|
|
|
238
280
|
difference_uncertainties_low = np.sqrt(uncertainties_low**2 + h2.variances())
|
|
239
281
|
difference_uncertainties_high = np.sqrt(uncertainties_high**2 + h2.variances())
|
|
@@ -390,11 +432,13 @@ def get_ratio(
|
|
|
390
432
|
|
|
391
433
|
ratio_values = np.where(h2.values() != 0, h1.values() / h2.values(), np.nan)
|
|
392
434
|
|
|
393
|
-
if
|
|
394
|
-
uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
|
|
435
|
+
if "asymmetrical" in h1_uncertainty_type:
|
|
436
|
+
uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
|
|
437
|
+
h1, h1_uncertainty_type
|
|
438
|
+
)
|
|
395
439
|
|
|
396
440
|
if ratio_uncertainty_type == "uncorrelated":
|
|
397
|
-
if
|
|
441
|
+
if "asymmetrical" in h1_uncertainty_type:
|
|
398
442
|
h1_high = h1.copy()
|
|
399
443
|
h1_high[:] = np.c_[h1_high.values(), uncertainties_high**2]
|
|
400
444
|
h1_low = h1.copy()
|
|
@@ -405,7 +449,7 @@ def get_ratio(
|
|
|
405
449
|
ratio_uncertainties_low = np.sqrt(get_ratio_variances(h1, h2))
|
|
406
450
|
ratio_uncertainties_high = ratio_uncertainties_low
|
|
407
451
|
elif ratio_uncertainty_type == "split":
|
|
408
|
-
if
|
|
452
|
+
if "asymmetrical" in h1_uncertainty_type:
|
|
409
453
|
ratio_uncertainties_low = uncertainties_low / h2.values()
|
|
410
454
|
ratio_uncertainties_high = uncertainties_high / h2.values()
|
|
411
455
|
else:
|
|
@@ -493,7 +537,7 @@ def get_comparison(
|
|
|
493
537
|
h1, h2, h1_uncertainty_type
|
|
494
538
|
)
|
|
495
539
|
elif comparison == "asymmetry":
|
|
496
|
-
if
|
|
540
|
+
if "asymmetrical" in h1_uncertainty_type:
|
|
497
541
|
raise ValueError(
|
|
498
542
|
"Asymmetrical uncertainties are not supported for the asymmetry comparison."
|
|
499
543
|
)
|
|
@@ -501,7 +545,7 @@ def get_comparison(
|
|
|
501
545
|
lower_uncertainties = uncertainties
|
|
502
546
|
upper_uncertainties = uncertainties
|
|
503
547
|
elif comparison == "efficiency":
|
|
504
|
-
if
|
|
548
|
+
if "asymmetrical" in h1_uncertainty_type:
|
|
505
549
|
raise ValueError(
|
|
506
550
|
"Asymmetrical uncertainties are not supported in an efficiency computation."
|
|
507
551
|
)
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Representation of different uncertainty types.
|
|
3
|
+
==============================================
|
|
4
|
+
|
|
5
|
+
This example demonstrates how to use the `plot_error_hist` function with different uncertainty types
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import boost_histogram as bh
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
from plothist import add_text, plot_error_hist
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def shifted_array(values, offset: int, size: int = 15) -> np.ndarray:
|
|
16
|
+
"""
|
|
17
|
+
Create an array of a given size with NaNs and fill it with values at specified offsets.
|
|
18
|
+
The values are inserted at every offset starting from the given offset.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
arr = np.full(size, np.nan)
|
|
22
|
+
indices = range(offset, size, len(values))
|
|
23
|
+
|
|
24
|
+
for i, idx in enumerate(indices):
|
|
25
|
+
if i >= len(values):
|
|
26
|
+
break
|
|
27
|
+
arr[idx] = values[i]
|
|
28
|
+
|
|
29
|
+
return arr
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def make_grouped_edges(
|
|
33
|
+
n_groups, group_size=4, inner_spacing=0.1, inter_spacing=0.2
|
|
34
|
+
) -> np.ndarray:
|
|
35
|
+
"""
|
|
36
|
+
Create a set of edges for a histogram with grouped categories.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
edges = [
|
|
40
|
+
group_start + i * inner_spacing
|
|
41
|
+
for group in range(n_groups)
|
|
42
|
+
for i in range(group_size)
|
|
43
|
+
for group_start in [
|
|
44
|
+
group * (group_size * inner_spacing + inter_spacing - inner_spacing)
|
|
45
|
+
]
|
|
46
|
+
]
|
|
47
|
+
return np.array(edges)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Create a category axis with explicit locations
|
|
51
|
+
edges = make_grouped_edges(4)
|
|
52
|
+
axis = bh.axis.Variable(edges)
|
|
53
|
+
|
|
54
|
+
hists = []
|
|
55
|
+
entries = [0, 0.5, 3, 500]
|
|
56
|
+
|
|
57
|
+
for k in range(3):
|
|
58
|
+
hist = bh.Histogram(axis, storage=bh.storage.Weight())
|
|
59
|
+
values = shifted_array(entries, k)
|
|
60
|
+
hist[:] = np.c_[values, values]
|
|
61
|
+
hists.append(hist)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
fig, (ax_top, ax_bot) = plt.subplots(
|
|
65
|
+
2, 1, gridspec_kw={"height_ratios": [1, 3], "hspace": 0.05}
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
for ax in (ax_top, ax_bot):
|
|
69
|
+
plot_error_hist(
|
|
70
|
+
hists[0], ax=ax, label="symmetrical", uncertainty_type="symmetrical"
|
|
71
|
+
)
|
|
72
|
+
plot_error_hist(
|
|
73
|
+
hists[1], ax=ax, label="asymmetrical", uncertainty_type="asymmetrical"
|
|
74
|
+
)
|
|
75
|
+
plot_error_hist(
|
|
76
|
+
hists[2],
|
|
77
|
+
ax=ax,
|
|
78
|
+
label="asymmetrical_double_sided_zeros",
|
|
79
|
+
uncertainty_type="asymmetrical_double_sided_zeros",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
add_text("plot_error_hist() with different uncertainty type", ax=ax_top, x="right")
|
|
83
|
+
|
|
84
|
+
# Set axis limits
|
|
85
|
+
ax_top.set_ylim(465, 530)
|
|
86
|
+
ax_bot.set_ylim(-0.5, 6.9)
|
|
87
|
+
ax_bot.set_xlim(xmin=-0.05)
|
|
88
|
+
|
|
89
|
+
# Format bottom ticks and labels
|
|
90
|
+
ax_bot.set_xticks(edges[1::4] + 0.05)
|
|
91
|
+
ax_bot.set_xlabel("Entry category")
|
|
92
|
+
ax_bot.set_xticklabels(entries)
|
|
93
|
+
ax_bot.set_ylabel("Entries")
|
|
94
|
+
ax_bot.yaxis.label.set_horizontalalignment("left")
|
|
95
|
+
ax_bot.spines.top.set_visible(False)
|
|
96
|
+
ax_bot.xaxis.set_minor_locator(plt.NullLocator()) # Hide x-axis minor ticks
|
|
97
|
+
|
|
98
|
+
# Format top ticks and labels
|
|
99
|
+
ax_top.xaxis.tick_top()
|
|
100
|
+
ax_top.spines.bottom.set_visible(False)
|
|
101
|
+
ax_top.set_xticklabels([])
|
|
102
|
+
ax_top.set_xticks([])
|
|
103
|
+
|
|
104
|
+
# Draw break marks
|
|
105
|
+
d = 0.5 # proportion of vertical to horizontal extent of the slanted line
|
|
106
|
+
kwargs = {
|
|
107
|
+
"marker": [(-1, -d), (1, d)],
|
|
108
|
+
"markersize": 12,
|
|
109
|
+
"linestyle": "none",
|
|
110
|
+
"color": "k",
|
|
111
|
+
"mec": "k",
|
|
112
|
+
"mew": 1,
|
|
113
|
+
"clip_on": False,
|
|
114
|
+
}
|
|
115
|
+
ax_top.plot([0, 1], [0, 0], transform=ax_top.transAxes, **kwargs)
|
|
116
|
+
ax_bot.plot([0, 1], [1, 1], transform=ax_bot.transAxes, **kwargs)
|
|
117
|
+
|
|
118
|
+
ax_top.legend(loc="upper left")
|
|
119
|
+
|
|
120
|
+
fig.savefig("uncertainty_types.svg", bbox_inches="tight")
|
plothist/plothist_style.py
CHANGED
|
@@ -112,7 +112,7 @@ def cubehelix_palette(
|
|
|
112
112
|
pal = cmap(x)[:, :3].tolist()
|
|
113
113
|
if reverse:
|
|
114
114
|
pal = pal[::-1]
|
|
115
|
-
return pal
|
|
115
|
+
return [tuple(c) for c in pal]
|
|
116
116
|
|
|
117
117
|
|
|
118
118
|
def get_color_palette(
|
|
@@ -170,7 +170,7 @@ def get_color_palette(
|
|
|
170
170
|
)
|
|
171
171
|
|
|
172
172
|
plt_cmap = plt.get_cmap(cmap)
|
|
173
|
-
return plt_cmap(np.linspace(0, 1, N))
|
|
173
|
+
return [tuple(k) for k in plt_cmap(np.linspace(0, 1, N))]
|
|
174
174
|
|
|
175
175
|
|
|
176
176
|
def set_fitting_ylabel_fontsize(ax: plt.Axes) -> float:
|
plothist/plotters.py
CHANGED
|
@@ -406,7 +406,9 @@ def plot_error_hist(
|
|
|
406
406
|
if uncertainty_type == "symmetrical":
|
|
407
407
|
kwargs.setdefault("yerr", np.sqrt(hist.variances()))
|
|
408
408
|
else:
|
|
409
|
-
uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
|
|
409
|
+
uncertainties_low, uncertainties_high = get_asymmetrical_uncertainties(
|
|
410
|
+
hist, uncertainty_type
|
|
411
|
+
)
|
|
410
412
|
kwargs.setdefault("yerr", [uncertainties_low, uncertainties_high])
|
|
411
413
|
|
|
412
414
|
kwargs.setdefault("fmt", ".")
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
plothist/__init__.py,sha256=
|
|
2
|
-
plothist/_version.py,sha256=
|
|
1
|
+
plothist/__init__.py,sha256=ikcYOZqMs4WKAJ2rM-3BnHu_CQxLlQCuc-iFo_a-Mns,2760
|
|
2
|
+
plothist/_version.py,sha256=5FGJNp9Lkk9uOxeCjXpoCGBF79Ar6LGPOR7-atBqb_4,511
|
|
3
3
|
plothist/_version.pyi,sha256=o7uNL6MhuJoiqpEnriU7rBT6TmkJZA-i2qMoNz9YcgQ,82
|
|
4
|
-
plothist/comparison.py,sha256=
|
|
4
|
+
plothist/comparison.py,sha256=jkONOiCp8RNBk8V_VvwACdfJJqo89rK9NQW71XxJscc,19623
|
|
5
5
|
plothist/default_style.mplstyle,sha256=7MmB2uiXmD_DSqFHeH1xxC-lTctBD_EASxMdSOsPep0,1574
|
|
6
6
|
plothist/histogramming.py,sha256=o0RLdoEhxHA7Ws0bvK3DewsbQEu-QOtJNw5Md5AckHM,11474
|
|
7
|
-
plothist/plothist_style.py,sha256=
|
|
8
|
-
plothist/plotters.py,sha256=
|
|
7
|
+
plothist/plothist_style.py,sha256=bbYFc-qsrTfdbacCBAAzmiHJoRIh3toBomFfxtTRNMs,13255
|
|
8
|
+
plothist/plotters.py,sha256=ncPZa34Fo1mbFxv0guFc2zEciX_JXGKJxeIfcUDaP6w,46336
|
|
9
9
|
plothist/test_helpers.py,sha256=JXhxUdqMszkawxkU8cDPqipkSXNHfsKSfe3K-4frDrM,1379
|
|
10
10
|
plothist/variable_registry.py,sha256=usVLoDLbIMzjeRDazIH0OIjQIUsh9RSJ9Ncnhn1V9qw,10783
|
|
11
11
|
plothist/examples/README.rst,sha256=PVzkOQzVnNeWORxEv3NNv5XoSN2Y71D7SYzRkCqirfA,151
|
|
@@ -56,8 +56,9 @@ plothist/examples/utility/add_text_example.py,sha256=EB7ZUStt2E8GawjWNmVbSV34NIN
|
|
|
56
56
|
plothist/examples/utility/color_palette_hists.py,sha256=uIc6TrmjTj8EUif1Yj1wq4nXoY1sgJpS15yPe3-FpTw,2383
|
|
57
57
|
plothist/examples/utility/color_palette_squares.py,sha256=pNasgvZZApu-sCqhi5FTJAH3l6Px2cgB5RwJcQ1eF1U,2689
|
|
58
58
|
plothist/examples/utility/matplotlib_vs_plothist_style.py,sha256=iEIfbFKmAN-PcDCzw_sBuhrfpes4I2wUVfC0r1vUHEw,2006
|
|
59
|
-
plothist
|
|
60
|
-
plothist-1.
|
|
61
|
-
plothist-1.
|
|
62
|
-
plothist-1.
|
|
63
|
-
plothist-1.
|
|
59
|
+
plothist/examples/utility/uncertainty_types.py,sha256=r1yxzEvxn5Clv0ZIok9JjVh3RB-YQ_usWhFnpvl1els,3259
|
|
60
|
+
plothist-1.6.0.dist-info/METADATA,sha256=WsoMGQrcmUasAx0UxEP9aGEw7LAk1eHQCrjUz6228fY,4737
|
|
61
|
+
plothist-1.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
62
|
+
plothist-1.6.0.dist-info/licenses/AUTHORS.md,sha256=02x3_8PNyTsXcRs0IlJeCTOmpGNRqymcJ71-2QtR37E,111
|
|
63
|
+
plothist-1.6.0.dist-info/licenses/LICENSE,sha256=bfaEdGehofQDaw-zDdVMHNUKo1FrOm6oGUEF-ltrp6w,1523
|
|
64
|
+
plothist-1.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|