ararpy 0.0.1a1__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.
ararpy/smp/plots.py ADDED
@@ -0,0 +1,636 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: UTF-8 -*-
3
+ """
4
+ # ==========================================
5
+ # Copyright 2023 Yang
6
+ # ararpy - smp - plots
7
+ # ==========================================
8
+ #
9
+ #
10
+ #
11
+ """
12
+
13
+ import traceback
14
+ import numpy as np
15
+
16
+ from scipy.signal import find_peaks
17
+ import time
18
+
19
+
20
+ from .. import calc
21
+ from .sample import Sample, Info, Table, Plot
22
+ from . import basic, initial
23
+
24
+ Set = Plot.Set
25
+ Label = Plot.Label
26
+ Axis = Plot.Axis
27
+ Text = Plot.Text
28
+
29
+
30
+ ISOCHRON_INDEX_DICT = {
31
+ 'figure_2': {'data_index': [0, 5], 'name': 'Normal Isochron', 'figure_type': 1},
32
+ 'figure_3': {'data_index': [6, 11], 'name': 'Inverse Isochron', 'figure_type': 2},
33
+ 'figure_4': {'data_index': [12, 17], 'name': 'Cl Correlation 1', 'figure_type': 1},
34
+ 'figure_5': {'data_index': [18, 23], 'name': 'Cl Correlation 2', 'figure_type': 2},
35
+ 'figure_6': {'data_index': [24, 29], 'name': 'Cl Correlation 3', 'figure_type': 3},
36
+ 'figure_7': {'data_index': [30, 39], 'name': 'Cl Correlation 3D', 'figure_type': 0},
37
+ }
38
+
39
+
40
+ # =======================
41
+ # Reset plot data
42
+ # =======================
43
+ def set_plot_data(sample: Sample, isInit: bool = True, isIsochron: bool = True,
44
+ isPlateau: bool = True, **kwargs):
45
+ """
46
+ Parameters
47
+ ----------
48
+ sample
49
+ isInit
50
+ isIsochron
51
+ isPlateau
52
+ kwargs
53
+
54
+ Returns
55
+ -------
56
+
57
+ """
58
+ print(f"isInit: {isInit}, isIsochron: {isIsochron}, isPlateau: {isPlateau}")
59
+
60
+ # Initialization, apply age spectra data and isochron plot data
61
+ if isInit:
62
+ try:
63
+ initial_plot_data(sample)
64
+ except (Exception, BaseException):
65
+ print(traceback.format_exc())
66
+ pass
67
+
68
+ # Recalculate isochron lines
69
+ if isIsochron:
70
+ try:
71
+ t1 = time.time()
72
+ recalc_isochrons(sample)
73
+ reset_isochron_line_data(sample)
74
+ print(f"recalc_isochrons time = {time.time() - t1}")
75
+ except (Exception, BaseException):
76
+ print(traceback.format_exc())
77
+ pass
78
+
79
+ # Recalculate plateaus
80
+ if isPlateau:
81
+ try:
82
+ t1 = time.time()
83
+ recalc_plateaus(sample)
84
+ print(f"recalc_plateaus time = {time.time() - t1}")
85
+ except (Exception, BaseException):
86
+ print(traceback.format_exc())
87
+ pass
88
+
89
+
90
+ # =======================
91
+ # Initialize plot data
92
+ # =======================
93
+ def initial_plot_data(sample: Sample):
94
+ """
95
+ Assign initial data for plots
96
+ Parameters
97
+ ----------
98
+ sample : Sample instance
99
+
100
+ Returns
101
+ -------
102
+ None
103
+ """
104
+ for key, val in ISOCHRON_INDEX_DICT.items():
105
+ figure = basic.get_component_byid(sample, key)
106
+ try:
107
+ # data = [x, sx, y, sy, (z, sz,) r1, (r2, r3,), index from 1]
108
+ figure.data = sample.IsochronValues[val['data_index'][0]:val['data_index'][1]] + \
109
+ [[i + 1 for i in range(len(sample.SequenceName))]]
110
+ except (Exception, BaseException):
111
+ print(traceback.format_exc())
112
+ figure.data = [[]] * (val['data_index'][1] - val['data_index'][0]) + \
113
+ [[i + 1 for i in range(len(sample.SequenceName))]]
114
+ finally:
115
+ # Ellipse
116
+ if key != 'figure_7':
117
+ ellipse_data = []
118
+ for point in calc.arr.transpose(figure.data[:5]):
119
+ if '' not in point and None not in point:
120
+ ellipse_data.append(calc.isochron.get_ellipse(*point))
121
+ getattr(figure, 'ellipse', Set(id='ellipse')).data = ellipse_data
122
+
123
+ # Set age spectra lines
124
+ # Try to calculate total gas age
125
+ try:
126
+ a0, e0 = sum(sample.DegasValues[24]), pow(sum([i ** 2 for i in sample.DegasValues[25]]), 0.5)
127
+ a1, e1 = sum(sample.DegasValues[20]), pow(sum([i ** 2 for i in sample.DegasValues[21]]), 0.5)
128
+ total_f = [a0 / a1, calc.err.div((a0, e0), (a1, e1))]
129
+ total_age = basic.calc_age(total_f[:2], smp=sample)
130
+ except (Exception, BaseException):
131
+ print(traceback.format_exc())
132
+ total_age = [np.nan] * 4
133
+ sample.Info.results.age_spectra.update(dict(zip(['age', 's1', 's2', 's3'], total_age)))
134
+ try:
135
+ sample.AgeSpectraPlot.data = calc.spectra.get_data(
136
+ *sample.ApparentAgeValues[2:4], sample.ApparentAgeValues[7])
137
+ sample.AgeSpectraPlot.data = calc.arr.transpose(sample.AgeSpectraPlot.data)
138
+ except (Exception, BaseException):
139
+ print(traceback.format_exc())
140
+ sample.AgeSpectraPlot.data = []
141
+
142
+ # Degassing plot
143
+ try:
144
+ if not hasattr(sample, 'DegasPatternPlot'):
145
+ setattr(sample, 'DegasPatternPlot', Plot(id='figure_8', name='Degas Pattern Plot'))
146
+ isotope_percentage = lambda l: [e / sum(l) * 100 if sum(l) != 0 else 0 for e in l]
147
+ sample.DegasPatternPlot.data = [
148
+ isotope_percentage(sample.DegasValues[0]), # Ar36a
149
+ isotope_percentage(sample.DegasValues[8]), # Ar37Ca
150
+ isotope_percentage(sample.DegasValues[10]), # Ar38Cl
151
+ isotope_percentage(sample.DegasValues[20]), # Ar39K
152
+ isotope_percentage(sample.DegasValues[24]), # Ar40r
153
+ isotope_percentage(sample.CorrectedValues[0]), # Ar36
154
+ isotope_percentage(sample.CorrectedValues[2]), # Ar37
155
+ isotope_percentage(sample.CorrectedValues[4]), # Ar38
156
+ isotope_percentage(sample.CorrectedValues[6]), # Ar39
157
+ isotope_percentage(sample.CorrectedValues[8]), # Ar40
158
+ ]
159
+ sample.DegasPatternPlot.info = [True] * 10
160
+ except Exception as e:
161
+ print(traceback.format_exc())
162
+ pass
163
+
164
+ # Set age distribution plot data
165
+ try:
166
+ recalc_agedistribution(sample)
167
+ except Exception as e:
168
+ print(traceback.format_exc())
169
+
170
+
171
+ # =======================
172
+ # Isochron results
173
+ # =======================
174
+ def recalc_isochrons(sample: Sample, **kwargs):
175
+ """
176
+
177
+ Parameters
178
+ ----------
179
+ sample
180
+ kwargs
181
+
182
+ Returns
183
+ -------
184
+
185
+ """
186
+ for key, val in ISOCHRON_INDEX_DICT.items():
187
+ figure = basic.get_component_byid(sample, key)
188
+ figure.set3.data, figure.set1.data, figure.set2.data = \
189
+ sample.UnselectedSequence, sample.SelectedSequence1, sample.SelectedSequence2
190
+ for index, sequence in enumerate([figure.set1.data, figure.set2.data, figure.set3.data]):
191
+ set_data = calc.arr.partial(
192
+ sample.IsochronValues, rows=sequence, cols=list(range(*val['data_index'])))
193
+ if key != 'figure_7':
194
+ iso_res = get_isochron_results(
195
+ set_data, figure_type=val["figure_type"], sample=sample, sequence=sequence)
196
+ sample.Info.results.isochron[figure.id].update({index: iso_res})
197
+ else:
198
+ iso_res = get_3D_results(data=set_data, sequence=sequence, sample=sample)
199
+ sample.Info.results.isochron[figure.id].update({index: iso_res})
200
+
201
+
202
+ def get_isochron_results(data: list, sample, sequence, figure_type: int = 0):
203
+ """
204
+ Get isochron figure results based on figure type.
205
+ Parameters
206
+ ----------
207
+ data : isochron figure data, 5 columns list
208
+ sample : sample instance
209
+ sequence : data section index
210
+ figure_type : int, 0 for normal isochron, 1 for inverse isochron, 2 for K-Cl-Ar plot 3
211
+
212
+ Returns
213
+ -------
214
+ dict, isochron regression results, keys are [
215
+ 'k', 'sk', 'm1', 'sm1', 'MSWD', 'abs_conv', 'iter', 'mag', 'R2', 'Chisq', 'Pvalue',
216
+ 'rs', 'age', 's1', 's2', 's3', 'conv', 'initial', 'sinitial', 'F', 'sF'
217
+ ]
218
+ """
219
+ reg_res_index = [
220
+ 'k', 'sk', 'm1', 'sm1',
221
+ 'MSWD', 'abs_conv', 'iter', 'mag', 'R2', 'Chisq', 'Pvalue',
222
+ 'rs', # 'rs' means relative error of the total sum
223
+ ]
224
+ age_res_index = ['age', 's1', 's2', 's3', ]
225
+ iso_res = dict(zip(
226
+ [*reg_res_index, *age_res_index, 'conv', 'initial', 'sinitial', 'F', 'sF'],
227
+ [np.nan] * (len(reg_res_index + age_res_index) + 5)
228
+ ))
229
+
230
+ if len(sequence) < 3:
231
+ return iso_res
232
+
233
+ try:
234
+ york_res = calc.regression.york2(*data[0:5])
235
+ except (Exception, BaseException):
236
+ print(traceback.format_exc())
237
+ return iso_res
238
+ else:
239
+ iso_res.update(dict(zip(reg_res_index, calc.regression.york2(*data[0:5]))))
240
+ if figure_type == 1:
241
+ iso_res.update(zip(['initial', 'sinitial'], york_res[0:2]))
242
+ iso_res.update(zip(['F', 'sF'], york_res[2:4]))
243
+ elif figure_type == 2:
244
+ iso_res.update(zip(['initial', 'sinitial'], calc.arr.rec(york_res[0:2])))
245
+ k = calc.regression.york2(*data[2:4], *data[0:2], data[4])
246
+ iso_res.update(zip(['F', 'sF'], calc.arr.rec(k[0:2])))
247
+ elif figure_type == 3:
248
+ iso_res.update(zip(['initial', 'sinitial'], york_res[2:4]))
249
+ iso_res.update(zip(['F', 'sF'], york_res[0:2]))
250
+ # age, analytical err, internal err, full external err
251
+ age = basic.calc_age([iso_res['F'], iso_res['sF']], smp=sample)
252
+ iso_res.update(dict(zip(age_res_index, age)))
253
+ return iso_res
254
+
255
+
256
+ def get_3D_results(data: list, sequence: list, sample: Sample):
257
+ """
258
+ Get 3D regression results.
259
+ Parameters
260
+ ----------
261
+ data : 3D regression data with 9 columns.
262
+ sequence : list, data section index
263
+ sample : sample instance
264
+
265
+ Returns
266
+ -------
267
+ dict, isochron regression results, with keys = [
268
+ 'k', 'sk', 'm1', 'sm1', 'm2', 'sm2',
269
+ 'S', 'MSWD', 'R2', 'abs_conv', 'iter', 'mag', 'Chisq', 'Pvalue',
270
+ 'rs', 'age', 's1', 's2', 's3', 'conv', 'initial', 'sinitial', 'p_Cl', 'F', 'sF'
271
+ ]
272
+ """
273
+ reg_res_index = [
274
+ 'k', 'sk', 'm1', 'sm1', 'm2', 'sm2',
275
+ 'S', 'MSWD', 'R2', 'abs_conv', 'iter', 'mag', 'Chisq', 'Pvalue',
276
+ 'rs', # 'rs' means relative error of the total sum
277
+ ]
278
+ age_res_index = ['age', 's1', 's2', 's3', ]
279
+ iso_res = dict(zip(
280
+ [*reg_res_index, *age_res_index,
281
+ 'conv', 'initial', 'sinitial', 'p_Cl', 'F', 'sF'],
282
+ [np.nan] * (len(reg_res_index + age_res_index) + 8)
283
+ ))
284
+ try:
285
+ if len(sequence) < 4:
286
+ raise ValueError(f"Data points not enough.")
287
+ k = calc.regression.wtd_3D_regression(*data[:9])
288
+ ar38ar36 = sample.TotalParam[4][0]
289
+ sar38ar36 = sample.TotalParam[5][0] * sample.TotalParam[4][0] / 100
290
+ ar40ar36 = (k[2] + k[4] * ar38ar36) * -1 / k[0]
291
+ sar40ar36 = calc.err.div(
292
+ ((k[2] + k[4] * ar38ar36) * -1,
293
+ calc.err.add(k[3], calc.err.mul((k[4], k[5]), (ar38ar36, sar38ar36)))), (k[0], k[1]))
294
+ f = 1 / k[0]
295
+ sf = calc.err.div((1, 0), (k[0], k[1]))
296
+ try:
297
+ PQ = -1 * k[4] / k[2]
298
+ Q = 1 - np.exp(-1 * sample.TotalParam[46][0] * sum(sample.TotalParam[32]) / len(sample.TotalParam[32]))
299
+ P = PQ / Q
300
+ except:
301
+ print(traceback.format_exc())
302
+ P = 0
303
+ age = basic.calc_age([f, sf], smp=sample)
304
+ except:
305
+ print(traceback.format_exc())
306
+ k = [0] * 15
307
+ age = [0] * 4
308
+ ar40ar36, sar40ar36, P = 0, 0, 0
309
+ f, sf = 0, 0
310
+ iso_res.update(dict(zip(iso_res, [*k, *age, np.nan, ar40ar36, sar40ar36, P, f, sf])))
311
+ return iso_res
312
+
313
+
314
+ def reset_isochron_line_data(smp: Sample):
315
+ """
316
+ Set isochron regression lines
317
+ Parameters
318
+ ----------
319
+ smp : sample instance
320
+
321
+ Returns
322
+ -------
323
+ None, set regression lines data to sample instance.
324
+ """
325
+ for k, v in basic.get_components(smp).items():
326
+ if not isinstance(v, Plot):
327
+ continue
328
+ for index in [0, 1]:
329
+ try:
330
+ xscale, yscale = [v.xaxis.min, v.xaxis.max], [v.yaxis.min, v.yaxis.max]
331
+ coeffs = [smp.Info.results.isochron[k][index]['k'], smp.Info.results.isochron[k][index]['m1']]
332
+ line_point = calc.isochron.get_line_points(xscale, yscale, coeffs)
333
+ setattr(getattr(v, ['line1', 'line2'][index]), 'data', line_point)
334
+ except Exception:
335
+ # print(traceback.format_exc())
336
+ continue
337
+
338
+
339
+ def set_selection(smp: Sample, index: int, mark: int):
340
+ """
341
+ Parameters
342
+ ----------
343
+ smp : sample instance
344
+ index : int, data point index
345
+ mark : int, 0 for unselected, 1 for set1, 2 for set2
346
+
347
+ Returns
348
+ -------
349
+
350
+ """
351
+ if mark not in [1, 2]:
352
+ raise ValueError(f"{mark = }, mark must be 1 or 2.")
353
+
354
+ def seq(_i): return [smp.UnselectedSequence, smp.SelectedSequence1, smp.SelectedSequence2][_i]
355
+
356
+ if index in seq(mark):
357
+ seq(mark).remove(index)
358
+ smp.UnselectedSequence.append(index)
359
+ else:
360
+ for i in [0, [0, 2, 1][mark]]:
361
+ if index in seq(i):
362
+ seq(i).remove(index)
363
+ seq(mark).append(index)
364
+ smp.IsochronMark = [
365
+ 1 if i in smp.SelectedSequence1 else 2 if i in smp.SelectedSequence2 else '' for i in
366
+ range(len(smp.IsochronValues[2]))]
367
+
368
+
369
+ # =======================
370
+ # Age spectra results
371
+ # =======================
372
+ def recalc_plateaus(sample: Sample, **kwargs):
373
+ """
374
+ Calculate age plateaus results
375
+ Parameters
376
+ ----------
377
+ sample : sample instance
378
+ kwargs : optional args, keys in [r1, sr1, r2, sr2]
379
+
380
+ Returns
381
+ -------
382
+ None
383
+ """
384
+ params_initial_ratio = calc.arr.partial(sample.TotalParam, cols=list(range(115, 120)))
385
+ ratio_set1 = [[], []]
386
+ ratio_set2 = [[], []]
387
+ for row, item in enumerate(params_initial_ratio[0]):
388
+ if str(item) == '0':
389
+ ratio_set1[0].append(sample.Info.results.isochron['figure_3'][0]['initial'])
390
+ ratio_set1[1].append(sample.Info.results.isochron['figure_3'][0]['sinitial'])
391
+ ratio_set2[0].append(sample.Info.results.isochron['figure_3'][1]['initial'])
392
+ ratio_set2[1].append(sample.Info.results.isochron['figure_3'][1]['sinitial'])
393
+ elif str(item) == '1':
394
+ ratio_set1[0].append(sample.Info.results.isochron['figure_2'][0]['initial'])
395
+ ratio_set1[1].append(sample.Info.results.isochron['figure_2'][0]['sinitial'])
396
+ ratio_set2[0].append(sample.Info.results.isochron['figure_2'][1]['initial'])
397
+ ratio_set2[1].append(sample.Info.results.isochron['figure_2'][1]['sinitial'])
398
+ elif str(item) == '2':
399
+ ratio_set1[0].append(params_initial_ratio[1][row])
400
+ ratio_set1[1].append(params_initial_ratio[2][row])
401
+ ratio_set2[0].append(params_initial_ratio[3][row])
402
+ ratio_set2[1].append(params_initial_ratio[4][row])
403
+ else:
404
+ ratio_set1[0].append(298.56)
405
+ ratio_set1[1].append(0.31)
406
+ ratio_set2[0].append(298.56)
407
+ ratio_set2[1].append(0.31)
408
+
409
+ # Get ages and line data points for each set
410
+ try:
411
+ set1_res, set1_age, set1_data = \
412
+ get_plateau_results(sample, sample.SelectedSequence1, calc_ar40ar39(*ratio_set1, smp=sample))
413
+ except ValueError:
414
+ raise ValueError(f"Set 1 Plateau results calculation error.")
415
+ else:
416
+ sample.Info.results.age_plateau.update({0: set1_res})
417
+ sample.AgeSpectraPlot.set1.data = calc.arr.transpose(set1_data)
418
+ try:
419
+ set2_res, set2_age, set2_data = \
420
+ get_plateau_results(sample, sample.SelectedSequence2, calc_ar40ar39(*ratio_set2, smp=sample))
421
+ except ValueError:
422
+ raise ValueError(f"Set 2 Plateau results calculation error.")
423
+ else:
424
+ sample.Info.results.age_plateau.update({1: set2_res})
425
+ sample.AgeSpectraPlot.set2.data = calc.arr.transpose(set2_data)
426
+
427
+ # # """3D corrected plateaus"""
428
+ # # 3D ratio, 36Ar(a+cl)/40Ar(a+r), 38Ar(a+cl)/40Ar(a+r), 39Ar(k)/40Ar(a+r),
429
+ # ar40ar = calc_funcs.list_sub(*sample.CorrectedValues[8:10], *sample.DegasValues[30:32])
430
+ # # 36Ar deduct Ca, that is sum of 36Ara and 36ArCl
431
+ # ar36acl = calc_funcs.list_sub(*sample.CorrectedValues[0:2], *sample.DegasValues[4:6])
432
+ # # 38Ar deduct K and Ca, that is sum of 38Ara and 38ArCl
433
+ # ar38acl = calc_funcs.list_sub(*calc_funcs.list_sub(*sample.CorrectedValues[4:6], *sample.DegasValues[16:18]),
434
+ # *sample.DegasValues[18:20])
435
+ # # 39ArK
436
+ # ar39k = sample.DegasValues[20:22]
437
+ #
438
+ # # 40Arr
439
+ # def get_modified_f(c, sc, a, sa, b, sb):
440
+ # ar40r = list(map(lambda zi, xi, yi: zi - a * xi - b * yi, ar40ar[0], ar36acl[0], ar38acl[0]))
441
+ # sar40r = list(map(lambda zi, szi, xi, sxi, yi, syi:
442
+ # calc.err.add(szi, calc_funcs.error_mul((xi, sxi), (a, sa)),
443
+ # calc_funcs.error_mul((yi, syi), (b, sb))),
444
+ # *ar40ar, *ar36acl, *ar38acl))
445
+ # f = list(map(lambda ar40ri, ar39ki: ar40ri / ar39ki, ar40r, ar39k[0]))
446
+ # sf = list(map(lambda ar40ri, sar40ri, ar39ki, sar39ki:
447
+ # calc.err.div((ar40ri, sar40ri), (ar39ki, sar39ki)),
448
+ # ar40r, sar40r, *ar39k))
449
+ # return [f, sf]
450
+ #
451
+ # isochron_7 = calc_funcs.get_3D_isochron(*ar36acl, *ar38acl, *ar40ar, *ar39k)
452
+ # [set1_data, set2_data, set3_data] = basic_funcs.getIsochronSetData(
453
+ # isochron_7, sample.SelectedSequence1, sample.SelectedSequence2, sample.UnselectedSequence)
454
+ #
455
+ # __isochron_7 = calc_funcs.get_3D_isochron(*ar36acl, *ar38acl, *ar39k, *ar40ar)
456
+ # [__set1_data, __set2_data, __set3_data] = basic_funcs.getIsochronSetData(
457
+ # __isochron_7, sample.SelectedSequence1, sample.SelectedSequence2, sample.UnselectedSequence)
458
+ #
459
+ # def __get_modified_f(c, sc, a, sa, b, sb):
460
+ # f = list(
461
+ # map(lambda zi, xi, yi: 1 / (zi - a * xi - b * yi), __isochron_7[4], __isochron_7[0], __isochron_7[2]))
462
+ # sf = [0] * len(f)
463
+ # return [f, sf]
464
+ #
465
+ # # set 1:
466
+ # try:
467
+ # k = calc_funcs.wtd_3D_regression(*set1_data[:9])
468
+ # set1_ar40rar39k = get_modified_f(*k[:6])
469
+ #
470
+ # # __k = calc_funcs.wtd_3D_regression(*__set1_data[:9])
471
+ # # __set1_ar40rar39k = __get_modified_f(*__k[:6])
472
+ # #
473
+ # # for i in range(len(set1_ar40rar39k[0])):
474
+ # # print(f"{set1_ar40rar39k[0][i]} == {__set1_ar40rar39k[0][i]}")
475
+ # #
476
+ # # k = calc_funcs.wtd_3D_regression(*__set1_data[:9])
477
+ # # set1_ar40rar39k = __get_modified_f(*k[:6])
478
+ #
479
+ # except:
480
+ # print(traceback.format_exc())
481
+ # set1_ar40rar39k = [[0] * len(ar39k[0]), [0] * len(ar39k[0])]
482
+ # # set 2:
483
+ # try:
484
+ # k = calc_funcs.wtd_3D_regression(*set2_data[:9])
485
+ # set2_ar40rar39k = get_modified_f(*k[:6])
486
+ # except:
487
+ # set2_ar40rar39k = [[0] * len(ar39k[0]), [0] * len(ar39k[0])]
488
+ # set4_age, set4_data, set4_wmf, set4_wmage, set4_text = \
489
+ # get_plateau_results(sample, sample.SelectedSequence1, set1_ar40rar39k)
490
+ # set5_age, set5_data, set5_wmf, set5_wmage, set5_text = \
491
+ # get_plateau_results(sample, sample.SelectedSequence2, set2_ar40rar39k)
492
+ # # Set set4 and set5
493
+ # sample.AgeSpectraPlot.set4.data = calc.arr.transpose(set4_data)
494
+ # sample.AgeSpectraPlot.set5.data = calc.arr.transpose(set5_data)
495
+ # sample.AgeSpectraPlot.set4.info = [*set4_wmf, *set4_wmage] # Info = weighted mean f, sf, np, mswd, age, s, s, s
496
+ # sample.AgeSpectraPlot.set5.info = [*set5_wmf, *set5_wmage] # Info = weighted mean f, sf, np, mswd, age, s, s, s
497
+ # # """end"""
498
+
499
+
500
+ def calc_ar40ar39(r, sr, smp):
501
+ """
502
+ Calculate Ar40r / Ar39K based on passed initial ratio.
503
+ Parameters
504
+ ----------
505
+ r : ratio value, float or list
506
+ sr : error of the ratio, same type as r
507
+ smp : sample instance
508
+
509
+ Returns
510
+ -------
511
+ Two dimensional list, Ar40r / Ar39K values and errors
512
+ """
513
+ try:
514
+ ar36a = np.array(smp.DegasValues[0:2])
515
+ ar39k = smp.DegasValues[20:22]
516
+ ar40 = smp.CorrectedValues[8:10]
517
+ ar40k = smp.DegasValues[30:32]
518
+ size = ar36a.shape[-1]
519
+ if isinstance(r, float) and isinstance(sr, float):
520
+ ratio = np.array([[r] * size, [sr] * size])
521
+ elif isinstance(r, list) and isinstance(sr, list):
522
+ ratio = np.array([r, sr])
523
+ else:
524
+ raise ValueError(f"Initial ratio is unsupported.")
525
+ # print(f"{ratio = }")
526
+ # print(f"{ar36a = }")
527
+ ar40a = calc.arr.mul(ar36a, ratio)
528
+ ar40r = calc.arr.sub(ar40, ar40k, ar40a)
529
+ ar40rar39k: list = calc.arr.div(ar40r, ar39k)
530
+ except (IndexError, AttributeError, ValueError):
531
+ raise ValueError(f"Check tables of corrected values and degas values.")
532
+ else:
533
+ return ar40rar39k
534
+
535
+
536
+ def get_plateau_results(sample: Sample, sequence: list, ar40rar39k: list = None,
537
+ ar39k_percentage: list = None):
538
+ """
539
+ Get initial ratio re-corrected plateau results
540
+ Parameters
541
+ ----------
542
+ sample : sample instance
543
+ sequence : data slice index
544
+ ar40rar39k :
545
+ ar39k_percentage : Ar39K released
546
+
547
+ Returns
548
+ -------
549
+ three itmes tuple, result dict, age, and plot data, results keys = [
550
+ 'F', 'sF', 'Num', 'MSWD', 'Chisq', 'Pvalue',
551
+ 'age', 's1', 's2', 's3', 'Ar39', 'rs'
552
+ ]
553
+ """
554
+ plateau_res_keys = [
555
+ 'F', 'sF', 'Num', 'MSWD', 'Chisq', 'Pvalue', 'age', 's1', 's2', 's3', 'Ar39',
556
+ 'rs', # 'rs' means relative error of the total sum
557
+ ]
558
+ plateau_res = dict(zip(plateau_res_keys, [np.nan] * len(plateau_res_keys)))
559
+
560
+ def _get_partial(points, *args):
561
+ return [arg[min(points): max(points) + 1] for arg in args]
562
+
563
+ if len(sequence) == 0:
564
+ return plateau_res, [], []
565
+ if ar40rar39k is None:
566
+ ar40rar39k = sample.ApparentAgeValues[0:2]
567
+ if ar39k_percentage is None:
568
+ ar39k_percentage = sample.ApparentAgeValues[7]
569
+
570
+ age = basic.calc_age(ar40ar39=ar40rar39k, smp=sample)[0:2]
571
+ plot_data = calc.spectra.get_data(*age, ar39k_percentage, indices=sequence)
572
+ f_values = _get_partial(sequence, *ar40rar39k)
573
+ age = _get_partial(sequence, *age)
574
+ sum_ar39k = sum(_get_partial(sequence, ar39k_percentage)[0])
575
+ wmf = calc.arr.wtd_mean(*f_values)
576
+ wmage = basic.calc_age(wmf[0:2], smp=sample)
577
+
578
+ plateau_res.update(dict(zip(
579
+ plateau_res_keys, [*wmf, *wmage, sum_ar39k, np.nan]
580
+ )))
581
+ return plateau_res, age, plot_data
582
+
583
+
584
+ # =======================
585
+ # Age Distribution Plot
586
+ # =======================
587
+ def recalc_agedistribution(sample: Sample, **kwargs):
588
+ for i in range(2):
589
+ try:
590
+ # Age bars
591
+ sample.AgeDistributionPlot.set3.data = calc.arr.remove(sample.ApparentAgeValues[2:4], (None, np.nan))
592
+ # Set histogram data
593
+ s = getattr(sample.AgeDistributionPlot.set1, 'bin_start', None)
594
+ w = getattr(sample.AgeDistributionPlot.set1, 'bin_width', None)
595
+ c = getattr(sample.AgeDistributionPlot.set1, 'bin_count', None)
596
+ r = getattr(sample.AgeDistributionPlot.set1, 'bin_rule', None)
597
+ # print(f's = {s}, r = {r}, w = {w}, c = {c}')
598
+ histogram_data = calc.histogram.get_data(sample.ApparentAgeValues[2], s=s, r=r, w=w, c=c)
599
+ sample.AgeDistributionPlot.set1.data = [histogram_data[1], histogram_data[0], histogram_data[2]] # [half_bins, counts]
600
+ setattr(sample.AgeDistributionPlot.set1, 'bin_start', histogram_data[3])
601
+ setattr(sample.AgeDistributionPlot.set1, 'bin_rule', histogram_data[4])
602
+ setattr(sample.AgeDistributionPlot.set1, 'bin_width', histogram_data[5])
603
+ setattr(sample.AgeDistributionPlot.set1, 'bin_count', histogram_data[6])
604
+ h = getattr(sample.AgeDistributionPlot.set2, 'band_width', None)
605
+ k = getattr(sample.AgeDistributionPlot.set2, 'band_kernel', 'normal')
606
+ t = getattr(sample.AgeDistributionPlot.set2, 'band_extend', False)
607
+ a = getattr(sample.AgeDistributionPlot.set2, 'auto_width', 'Scott')
608
+ n = getattr(sample.AgeDistributionPlot.set2, 'band_points', 1000)
609
+ # print(f'h = {h}, k = {k}, a = {a}, n = {n}, extend = {t}')
610
+ kda_data = calc.histogram.get_kde(
611
+ sample.ApparentAgeValues[2], h=h, k=k, n=n, a=a,
612
+ s=float(getattr(sample.AgeDistributionPlot.xaxis, 'min')) if t else histogram_data[3],
613
+ e=float(getattr(sample.AgeDistributionPlot.xaxis, 'max')) if t else histogram_data[7],
614
+ )
615
+ sample.AgeDistributionPlot.set2.data = kda_data[0] # [values, kda]
616
+ setattr(sample.AgeDistributionPlot.set2, 'band_width', kda_data[1])
617
+ setattr(sample.AgeDistributionPlot.set2, 'band_kernel', kda_data[2])
618
+ setattr(sample.AgeDistributionPlot.set2, 'auto_width', kda_data[3])
619
+ # sorted_data = [i[0] for i in sorted(zipped_data, key=lambda x: x[1])]
620
+ text = f'n = {len(sample.ApparentAgeValues[2])}'
621
+ peaks = find_peaks(kda_data[0][1])
622
+ for index, peak in enumerate(peaks[0].tolist()):
623
+ text = text + f'\nPeak {index}: {kda_data[0][0][peak]:.2f}'
624
+ setattr(sample.AgeDistributionPlot.text1, 'text', text)
625
+ except AttributeError:
626
+ print(traceback.format_exc())
627
+ initial.re_set_smp(sample)
628
+ continue
629
+ except (Exception, BaseException):
630
+ print(traceback.format_exc())
631
+ sample.AgeDistributionPlot.data = [[], []]
632
+ sample.AgeDistributionPlot.set1.data = [[], []]
633
+ sample.AgeDistributionPlot.set2.data = [[], []]
634
+ break
635
+
636
+