ararpy 0.1.11__py3-none-any.whl → 0.1.13__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/calc/arr.py +4 -1
- ararpy/calc/basic.py +36 -14
- ararpy/calc/corr.py +15 -30
- ararpy/calc/isochron.py +4 -2
- ararpy/calc/raw_funcs.py +2 -2
- ararpy/calc/regression.py +3 -1
- ararpy/examples/WHA.pdf +2863 -0
- ararpy/files/calc_file.py +1 -1
- ararpy/files/raw_file.py +84 -82
- ararpy/smp/EXPORT_TO_PDF_DATA_PROPERTIES.py +95 -0
- ararpy/smp/basic.py +9 -7
- ararpy/smp/calculation.py +4 -0
- ararpy/smp/corr.py +104 -56
- ararpy/smp/diffusion_funcs.py +285 -124
- ararpy/smp/export.py +464 -1
- ararpy/smp/json.py +12 -1
- ararpy/smp/plots.py +10 -6
- ararpy/smp/raw.py +9 -2
- ararpy/smp/sample.py +28 -12
- ararpy/smp/table.py +8 -0
- ararpy/test.py +63 -0
- {ararpy-0.1.11.dist-info → ararpy-0.1.13.dist-info}/METADATA +1 -1
- {ararpy-0.1.11.dist-info → ararpy-0.1.13.dist-info}/RECORD +26 -24
- {ararpy-0.1.11.dist-info → ararpy-0.1.13.dist-info}/WHEEL +1 -1
- {ararpy-0.1.11.dist-info → ararpy-0.1.13.dist-info}/LICENSE +0 -0
- {ararpy-0.1.11.dist-info → ararpy-0.1.13.dist-info}/top_level.txt +0 -0
ararpy/smp/export.py
CHANGED
|
@@ -17,9 +17,11 @@ import sys
|
|
|
17
17
|
import pickle
|
|
18
18
|
import traceback
|
|
19
19
|
import pdf_maker as pm
|
|
20
|
+
import numpy as np
|
|
20
21
|
from decimal import Decimal
|
|
21
22
|
|
|
22
|
-
from ..calc import arr, isochron
|
|
23
|
+
from ..calc import arr, isochron, spectra
|
|
24
|
+
from ..calc.basic import get_random_digits
|
|
23
25
|
from . import basic, sample, consts
|
|
24
26
|
|
|
25
27
|
Sample = sample.Sample
|
|
@@ -41,6 +43,467 @@ def to_pdf(file_path: str, figure: str, smp: Sample):
|
|
|
41
43
|
pdf.save(figure=figure)
|
|
42
44
|
|
|
43
45
|
|
|
46
|
+
def get_cv_from_dict(data: dict):
|
|
47
|
+
# create a canvas
|
|
48
|
+
cv = pm.Canvas(width=17, height=12, unit="cm", show_frame=True, clip_outside_plot_areas=False)
|
|
49
|
+
# change frame outline style
|
|
50
|
+
cv.show_frame(color="grey", line_width=0.5)
|
|
51
|
+
axis_num = min([len(data['xAxis']), len(data['yAxis'])])
|
|
52
|
+
# draw axis
|
|
53
|
+
plots = []
|
|
54
|
+
for i in range(axis_num):
|
|
55
|
+
scale = [*data['xAxis'][i]['extent'], *data['yAxis'][i]['extent']]
|
|
56
|
+
scale = (*scale,)
|
|
57
|
+
# create plot area based on axis scale
|
|
58
|
+
pt = cv.add_plot_area(name=f"PlotArea{i}", plot_area=(0.15, 0.15, 0.8, 0.8), plot_scale=scale, show_frame=True)
|
|
59
|
+
for stick in data['xAxis'][i]['interval']:
|
|
60
|
+
start = pt.scale_to_points(stick, scale[2])
|
|
61
|
+
end = pt.scale_to_points(stick, scale[2])
|
|
62
|
+
end = (end[0], end[1] - 5)
|
|
63
|
+
if pt.line(start=start, end=end, width=1, line_style="solid", y_clip=False, coordinate="pt", z_index=100):
|
|
64
|
+
pt.text(x=start[0], y=end[1] - 15, text=f"{stick}", clip=False,
|
|
65
|
+
coordinate="pt", h_align="middle", z_index=150)
|
|
66
|
+
for stick in data['yAxis'][i]['interval']:
|
|
67
|
+
start = pt.scale_to_points(scale[0], stick)
|
|
68
|
+
end = pt.scale_to_points(scale[0], stick)
|
|
69
|
+
end = (end[0] - 5, end[1])
|
|
70
|
+
if pt.line(start=start, end=end, width=1, line_style="solid", x_clip=False, coordinate="pt", z_index=100):
|
|
71
|
+
pt.text(x=end[0] - 5, y=end[1], text=f"{stick}", clip=False,
|
|
72
|
+
coordinate="pt", h_align="right", v_align="center", z_index=150)
|
|
73
|
+
# axis titles
|
|
74
|
+
nloc = pt.scale_to_points(sum(scale[:2]) / 2, scale[2])
|
|
75
|
+
pt.text(x=nloc[0], y=nloc[1] - 30, text=data['xAxis'][i]['title'], clip=False, coordinate="pt",
|
|
76
|
+
h_align="middle", v_align="top", z_index=150)
|
|
77
|
+
nloc = pt.scale_to_points(scale[0], sum(scale[2:4]) / 2)
|
|
78
|
+
pt.text(x=nloc[0] - 50, y=nloc[1], text=data['yAxis'][i]['title'], clip=False, coordinate="pt",
|
|
79
|
+
h_align="middle", v_align="bottom", rotate=90, z_index=150)
|
|
80
|
+
plots.append(pt)
|
|
81
|
+
# draw series
|
|
82
|
+
for se in data['series']:
|
|
83
|
+
data = se.get('data', [])
|
|
84
|
+
try:
|
|
85
|
+
pt = plots[se.get('axis_index', 0)]
|
|
86
|
+
except IndexError:
|
|
87
|
+
continue
|
|
88
|
+
if 'line' in se['type']:
|
|
89
|
+
for index in range(1, len(data)):
|
|
90
|
+
pt.line(
|
|
91
|
+
start=data[index - 1], end=data[index], width=se.get('line_width', 1),
|
|
92
|
+
line_style=se.get('line_style', 'solid'), name=se['name'],
|
|
93
|
+
color=se.get('color', 'black'), clip=True, line_caps=se.get('line_caps', 'none'),
|
|
94
|
+
z_index=se.get('z_index', 9))
|
|
95
|
+
if 'scatter' in se['type'] and se['name'] != 'Text':
|
|
96
|
+
for each in data:
|
|
97
|
+
pt.scatter(
|
|
98
|
+
each[0], each[1], fill_color=se.get('fill_color', 'black'), size=se.get('size', 5),
|
|
99
|
+
stroke_color=se.get('stroke_color', se.get('color', 'black')),
|
|
100
|
+
z_index=se.get('z_index', 9)
|
|
101
|
+
)
|
|
102
|
+
if 'scatter' in se['type'] and se['name'] == 'Text' or 'text' in se['type']:
|
|
103
|
+
for each in data:
|
|
104
|
+
pt.text(*each[:2], **se)
|
|
105
|
+
if 'rect' in se['type']:
|
|
106
|
+
for each in data:
|
|
107
|
+
lb = each[:2]; width, height = each[2:4]
|
|
108
|
+
pt.rect(lb, width, height, **se)
|
|
109
|
+
|
|
110
|
+
return cv
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def export_chart_to_pdf(data: dict, filepath: str = "", **kwargs):
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
filepath: str
|
|
119
|
+
data: dict
|
|
120
|
+
- file_name: string
|
|
121
|
+
file name, like "24WHA0001"
|
|
122
|
+
- data: list of dicts
|
|
123
|
+
properties:
|
|
124
|
+
- name: string
|
|
125
|
+
diagram name, like "Age spectra"
|
|
126
|
+
|
|
127
|
+
- xAxis: list
|
|
128
|
+
properties:
|
|
129
|
+
- extend: list
|
|
130
|
+
limits of values of axis, like [0, 100]
|
|
131
|
+
- interval: list
|
|
132
|
+
sticks location, like [0, 20, 40, 60, 80, 100]
|
|
133
|
+
- title: string
|
|
134
|
+
- name_location: string
|
|
135
|
+
axis title location, 'middle'
|
|
136
|
+
|
|
137
|
+
- yAxis: same as xAxis
|
|
138
|
+
|
|
139
|
+
- series: list
|
|
140
|
+
properties:
|
|
141
|
+
- type: string
|
|
142
|
+
series type, 'line', 'scatter', 'text', and any string contains these characters
|
|
143
|
+
- id: string
|
|
144
|
+
- name: string
|
|
145
|
+
- color: string or list
|
|
146
|
+
color for outlines, color name | RGB triplet | Hex color code
|
|
147
|
+
- fill_color: string or list
|
|
148
|
+
color for filling markers, format is similar to that of color
|
|
149
|
+
- data: 2-dimensional array
|
|
150
|
+
[[x1, y1], [x2, y2], ...]
|
|
151
|
+
- axis_index: int
|
|
152
|
+
index of axis to combine with, which is useful for plotting on different scales.
|
|
153
|
+
|
|
154
|
+
optional:
|
|
155
|
+
- line_caps: string
|
|
156
|
+
for lines only, 'square', 'none', 'butt'
|
|
157
|
+
- text: string
|
|
158
|
+
for texts only
|
|
159
|
+
- size: int
|
|
160
|
+
for scatters only
|
|
161
|
+
**kwargs:
|
|
162
|
+
author, producer, creator, page_size, ppi, ...
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
|
|
167
|
+
"""
|
|
168
|
+
title = data.get('file_name', '')
|
|
169
|
+
# write pdf
|
|
170
|
+
file = pm.NewPDF(filepath=filepath, title=f"{title}", **kwargs)
|
|
171
|
+
plot_data = data.get('data', [])
|
|
172
|
+
for index, each in enumerate(plot_data):
|
|
173
|
+
# rich text tags should follow this priority: color > script > break
|
|
174
|
+
file.text(
|
|
175
|
+
page=index, x=50, y=780, line_space=1.2, size=12, base=0, h_align="left",
|
|
176
|
+
text=f"{each.get('name', '')}"
|
|
177
|
+
)
|
|
178
|
+
cv = get_cv_from_dict(each)
|
|
179
|
+
file.canvas(page=index, base=0, margin_top=5, canvas=cv, unit="cm", h_align="middle")
|
|
180
|
+
if index + 1 < len(plot_data):
|
|
181
|
+
file.add_page()
|
|
182
|
+
|
|
183
|
+
# save pdf
|
|
184
|
+
file.save()
|
|
185
|
+
|
|
186
|
+
return filepath
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def get_plot_data(smp: Sample, diagram: str = 'age spectra', **options):
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
Parameters
|
|
193
|
+
----------
|
|
194
|
+
smp
|
|
195
|
+
diagram
|
|
196
|
+
color
|
|
197
|
+
options
|
|
198
|
+
|
|
199
|
+
Returns
|
|
200
|
+
-------
|
|
201
|
+
|
|
202
|
+
"""
|
|
203
|
+
if diagram.lower() == "age spectra":
|
|
204
|
+
xAxis, yAxis, series = _get_plot_data_age_spectra(smp, **options)
|
|
205
|
+
elif diagram.lower() == "inverse isochron":
|
|
206
|
+
xAxis, yAxis, series = _get_plot_data_inv_isochron(smp, **options)
|
|
207
|
+
elif "degas spectra" in diagram.lower():
|
|
208
|
+
xAxis, yAxis, series = _get_plot_data_degas_spectra(smp, diagram_name = diagram.lower(), **options)
|
|
209
|
+
elif "degas curve" in diagram.lower():
|
|
210
|
+
xAxis, yAxis, series = _get_plot_data_degas_curve(smp, diagram_name = diagram.lower(), **options)
|
|
211
|
+
else:
|
|
212
|
+
raise KeyError
|
|
213
|
+
|
|
214
|
+
data = {
|
|
215
|
+
'name': smp.name(), 'xAxis': xAxis, 'yAxis': yAxis, 'series': series
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
print(data)
|
|
219
|
+
|
|
220
|
+
return data
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _get_plot_data_age_spectra(smp: sample, **options):
|
|
224
|
+
color = options.get('color', 'black')
|
|
225
|
+
xAxis, yAxis, series = [], [], []
|
|
226
|
+
age = smp.ApparentAgeValues[2:4]
|
|
227
|
+
ar = smp.DegasValues[20]
|
|
228
|
+
data = spectra.get_data(*age, ar, cumulative=False)
|
|
229
|
+
series.append({
|
|
230
|
+
'type': 'series.line', 'id': f'line-{get_random_digits()}', 'name': f'line-{get_random_digits()}',
|
|
231
|
+
'color': color, 'fill_color': color, 'line_width': 1, 'line_style': 'solid', 'z_index': 9,
|
|
232
|
+
'data': np.transpose([data[0], data[1]]).tolist(), 'line_caps': 'square',
|
|
233
|
+
'axis_index': 0,
|
|
234
|
+
})
|
|
235
|
+
series.append({
|
|
236
|
+
'type': 'series.line', 'id': f'line-{get_random_digits()}', 'name': f'line-{get_random_digits()}',
|
|
237
|
+
'color': color, 'fill_color': color, 'line_width': 1, 'line_style': 'solid', 'z_index': 9,
|
|
238
|
+
'data': np.transpose([data[0], data[2]]).tolist(), 'line_caps': 'square',
|
|
239
|
+
'axis_index': 0,
|
|
240
|
+
})
|
|
241
|
+
text1 = smp.AgeSpectraPlot.text1
|
|
242
|
+
text2 = smp.AgeSpectraPlot.text2
|
|
243
|
+
for text in [text1, text2]:
|
|
244
|
+
series.append({
|
|
245
|
+
'type': 'text', 'id': f'text-{get_random_digits()}', 'name': f'text-{get_random_digits()}',
|
|
246
|
+
'color': color, 'fill_color': color,
|
|
247
|
+
'text': smp.name() + '<r>' + text.text.replace("\n", "<r>"), 'size': int(text.font_size / 1.5),
|
|
248
|
+
'data': [text.pos],
|
|
249
|
+
'axis_index': 1,
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
xAxis.append({
|
|
253
|
+
'extent': [0, 100], 'interval': [0, 20, 40, 60, 80, 100], 'id': 0, 'show_frame': True,
|
|
254
|
+
'title': 'Cumulative <sup>39</sup>Ar Released (%)', 'name_location': 'middle',
|
|
255
|
+
'line_width': 1, 'line_style': 'solid', 'z_index': 9,
|
|
256
|
+
})
|
|
257
|
+
xAxis.append({
|
|
258
|
+
'extent': [0, 100], 'interval': [], 'id': 1, 'show_frame': False,
|
|
259
|
+
'title': '', 'name_location': 'middle',
|
|
260
|
+
'line_width': 1, 'line_style': 'solid', 'z_index': 0,
|
|
261
|
+
})
|
|
262
|
+
yAxis.append({
|
|
263
|
+
'extent': [0, 25], 'interval': [0, 5, 10, 15, 20, 25], 'id': 0, 'show_frame': True,
|
|
264
|
+
'title': 'Apparent Age (Ma)', 'name_location': 'middle',
|
|
265
|
+
'line_width': 1, 'line_style': 'solid', 'z_index': 9,
|
|
266
|
+
})
|
|
267
|
+
yAxis.append({
|
|
268
|
+
'extent': [0, 100], 'interval': [], 'id': 1, 'show_frame': False,
|
|
269
|
+
'title': '', 'name_location': 'middle',
|
|
270
|
+
'line_width': 1, 'line_style': 'solid', 'z_index': 0,
|
|
271
|
+
})
|
|
272
|
+
return xAxis, yAxis, series
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _get_plot_data_inv_isochron(smp: sample, **options):
|
|
276
|
+
color = options.get('color', 'black')
|
|
277
|
+
xAxis, yAxis, series = [], [], []
|
|
278
|
+
age = smp.ApparentAgeValues[2:4]
|
|
279
|
+
ar = smp.DegasValues[20]
|
|
280
|
+
data = np.array(smp.InvIsochronPlot.data)
|
|
281
|
+
set1 = smp.InvIsochronPlot.set1.data
|
|
282
|
+
set2 = smp.InvIsochronPlot.set2.data
|
|
283
|
+
set3 = smp.InvIsochronPlot.set3.data
|
|
284
|
+
# set 1
|
|
285
|
+
series.append({
|
|
286
|
+
'type': 'series.scatter', 'id': f'scatter-{get_random_digits()}', 'name': f'scattter-{get_random_digits()}',
|
|
287
|
+
'stroke_color': 'red', 'fill_color': 'red', 'myType': 'scatter', 'size': 4, 'line_width': 1,
|
|
288
|
+
'data': (data[[0, 2], :][:, set1]).transpose().tolist(),
|
|
289
|
+
'axis_index': 0, 'z_index': 99
|
|
290
|
+
})
|
|
291
|
+
# set 2
|
|
292
|
+
series.append({
|
|
293
|
+
'type': 'series.scatter', 'id': f'scatter-{get_random_digits()}', 'name': f'scattter-{get_random_digits()}',
|
|
294
|
+
'stroke_color': 'blue', 'fill_color': 'blue', 'myType': 'scatter', 'size': 4, 'line_width': 1,
|
|
295
|
+
'data': (data[[0, 2], :][:, set2]).transpose().tolist(),
|
|
296
|
+
'axis_index': 0, 'z_index': 99
|
|
297
|
+
})
|
|
298
|
+
# set 3
|
|
299
|
+
series.append({
|
|
300
|
+
'type': 'series.scatter', 'id': f'scatter-{get_random_digits()}', 'name': f'scattter-{get_random_digits()}',
|
|
301
|
+
'stroke_color': 'black', 'fill_color': 'none', 'myType': 'scatter', 'size': 4, 'line_width': 1,
|
|
302
|
+
'data': (data[[0, 2], :][:, set3]).transpose().tolist(),
|
|
303
|
+
'axis_index': 0, 'z_index': 0
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
text1 = smp.InvIsochronPlot.text1
|
|
307
|
+
text2 = smp.InvIsochronPlot.text2
|
|
308
|
+
|
|
309
|
+
series.append({
|
|
310
|
+
'type': 'text', 'id': f'text-{get_random_digits()}', 'name': f'text-{get_random_digits()}',
|
|
311
|
+
'color': 'red', 'fill_color': 'red',
|
|
312
|
+
'text': smp.name() + '<r>' + text1.text.replace("\n", "<r>"), 'size': int(text1.font_size / 1.5),
|
|
313
|
+
'data': [text1.pos],
|
|
314
|
+
'axis_index': 1,
|
|
315
|
+
})
|
|
316
|
+
series.append({
|
|
317
|
+
'type': 'text', 'id': f'text-{get_random_digits()}', 'name': f'text-{get_random_digits()}',
|
|
318
|
+
'color': 'blue', 'fill_color': 'blue',
|
|
319
|
+
'text': smp.name() + '<r>' + text2.text.replace("\n", "<r>"), 'size': int(text2.font_size / 1.5),
|
|
320
|
+
'data': [text2.pos],
|
|
321
|
+
'axis_index': 1,
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
xaxis = smp.InvIsochronPlot.xaxis
|
|
325
|
+
yaxis = smp.InvIsochronPlot.yaxis
|
|
326
|
+
|
|
327
|
+
xAxis.append({
|
|
328
|
+
'extent': [float(xaxis.min), float(xaxis.max)],
|
|
329
|
+
'interval': [float("{:g}".format(float(xaxis.min) + i * float(xaxis.interval))) for i in range(int(xaxis.split_number) + 1)],
|
|
330
|
+
'id': 0, 'show_frame': True, 'z_index': 9,
|
|
331
|
+
'title': 'XXXX', 'name_location': 'middle',
|
|
332
|
+
})
|
|
333
|
+
xAxis.append({
|
|
334
|
+
'extent': [0, 100], 'interval': [], 'id': 1, 'show_frame': False,
|
|
335
|
+
'title': '', 'name_location': 'middle', 'z_index': 0,
|
|
336
|
+
})
|
|
337
|
+
yAxis.append({
|
|
338
|
+
'extent': [float(yaxis.min), float(yaxis.max)],
|
|
339
|
+
'interval': [float("{:g}".format(float(yaxis.min) + i * float(yaxis.interval))) for i in range(int(yaxis.split_number) + 1)],
|
|
340
|
+
'id': 0, 'show_frame': True, 'z_index': 9,
|
|
341
|
+
'title': 'YYYY', 'name_location': 'middle',
|
|
342
|
+
})
|
|
343
|
+
yAxis.append({
|
|
344
|
+
'extent': [0, 100], 'interval': [], 'id': 1, 'show_frame': False,
|
|
345
|
+
'title': '', 'name_location': 'middle', 'z_index': 0,
|
|
346
|
+
})
|
|
347
|
+
return xAxis, yAxis, series
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _get_plot_data_degas_pattern(smp: sample, **options):
|
|
351
|
+
color = options.get('color', 'black')
|
|
352
|
+
plot = smp.DegasPatternPlot
|
|
353
|
+
xAxis, yAxis, series = [], [], []
|
|
354
|
+
argon = smp.DegasValues[20] # Ar39K as default
|
|
355
|
+
while argon[-1] == 0:
|
|
356
|
+
argon = argon[:-1]
|
|
357
|
+
y = [argon[i] / sum(argon[i:]) * 100 for i in range(len(argon))]
|
|
358
|
+
x = list(range(1, len(argon) + 1))
|
|
359
|
+
data = np.array([x, y])
|
|
360
|
+
# set 1
|
|
361
|
+
series.append({
|
|
362
|
+
'type': 'series.scatter', 'id': f'scatter-{get_random_digits()}', 'name': f'scattter-{get_random_digits()}',
|
|
363
|
+
'stroke_color': color, 'fill_color': 'white', 'myType': 'scatter', 'size': 4, 'line_width': 1,
|
|
364
|
+
'data': data.transpose().tolist(), 'axis_index': 0, 'z_index': 99
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
xaxis = plot.xaxis
|
|
368
|
+
yaxis = plot.yaxis
|
|
369
|
+
|
|
370
|
+
xaxis.min = 0
|
|
371
|
+
xaxis.max = 100
|
|
372
|
+
xaxis.interval = 20
|
|
373
|
+
xaxis.split_number = 5
|
|
374
|
+
yaxis.min = 0
|
|
375
|
+
yaxis.max = 20
|
|
376
|
+
yaxis.interval = 5
|
|
377
|
+
yaxis.split_number = 4
|
|
378
|
+
|
|
379
|
+
xAxis.append({
|
|
380
|
+
'extent': [float(xaxis.min), float(xaxis.max)],
|
|
381
|
+
'interval': [float("{:g}".format(float(xaxis.min) + i * float(xaxis.interval))) for i in range(int(xaxis.split_number) + 1)],
|
|
382
|
+
'id': 0, 'show_frame': True, 'z_index': 9,
|
|
383
|
+
'title': 'XXXX', 'name_location': 'middle',
|
|
384
|
+
})
|
|
385
|
+
yAxis.append({
|
|
386
|
+
'extent': [float(yaxis.min), float(yaxis.max)],
|
|
387
|
+
'interval': [float("{:g}".format(float(yaxis.min) + i * float(yaxis.interval))) for i in range(int(yaxis.split_number) + 1)],
|
|
388
|
+
'id': 0, 'show_frame': True, 'z_index': 9,
|
|
389
|
+
'title': 'YYYY', 'name_location': 'middle',
|
|
390
|
+
})
|
|
391
|
+
return xAxis, yAxis, series
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def _get_plot_data_degas_spectra(smp: sample, **options):
|
|
395
|
+
name = options.get('diagram_name', '39Ar')
|
|
396
|
+
color = options.get('color', 'black')
|
|
397
|
+
plot = smp.DegasPatternPlot
|
|
398
|
+
xAxis, yAxis, series = [], [], []
|
|
399
|
+
nindex = {"40": 24, "39": 20, "38": 10, "37": 8, "36": 0}
|
|
400
|
+
if name[:2] in list(nindex.keys()):
|
|
401
|
+
ar = np.array(smp.DegasValues[nindex[name[:2]]], dtype=np.float64) # 20-21 Ar39
|
|
402
|
+
sar = np.array(smp.DegasValues[nindex[name[:2]] + 1], dtype=np.float64)
|
|
403
|
+
elif 'total' in name:
|
|
404
|
+
all_ar = np.array(smp.CorrectedValues, dtype=np.float64) # 20-21 Ar39
|
|
405
|
+
ar, sar = arr.add(*all_ar.reshape(5, 2, len(all_ar[0])))
|
|
406
|
+
ar = np.array(ar); sar = np.array(sar)
|
|
407
|
+
else:
|
|
408
|
+
raise KeyError
|
|
409
|
+
|
|
410
|
+
while ar[-1] == 0:
|
|
411
|
+
ar = ar[:-1]
|
|
412
|
+
x = list(range(0, len(ar)))
|
|
413
|
+
y = [0 for i in range(len(ar))]
|
|
414
|
+
width = [1 for i in range(len(ar))]
|
|
415
|
+
height = [ar[i] / sum(ar) * 100 for i in range(len(ar))]
|
|
416
|
+
data = np.array([x, y, width, height])
|
|
417
|
+
|
|
418
|
+
xaxis = plot.xaxis
|
|
419
|
+
yaxis = plot.yaxis
|
|
420
|
+
|
|
421
|
+
xaxis.min = 0
|
|
422
|
+
xaxis.max = 100
|
|
423
|
+
xaxis.interval = 20
|
|
424
|
+
xaxis.split_number = 5
|
|
425
|
+
yaxis.min = 0
|
|
426
|
+
yaxis.max = 20
|
|
427
|
+
yaxis.interval = 5
|
|
428
|
+
yaxis.split_number = 4
|
|
429
|
+
|
|
430
|
+
# set 1
|
|
431
|
+
series.append({
|
|
432
|
+
'type': 'rect', 'id': f'rect-{get_random_digits()}', 'name': f'rect-{get_random_digits()}',
|
|
433
|
+
'color': color, 'myType': 'rect', 'line_width': 1,
|
|
434
|
+
'data': data.transpose().tolist(),
|
|
435
|
+
'axis_index': 0, 'z_index': 99
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
xAxis.append({
|
|
439
|
+
'extent': [float(xaxis.min), float(xaxis.max)],
|
|
440
|
+
'interval': [float("{:g}".format(float(xaxis.min) + i * float(xaxis.interval))) for i in range(int(xaxis.split_number) + 1)],
|
|
441
|
+
'id': 0, 'show_frame': True, 'z_index': 9,
|
|
442
|
+
'title': 'Steps [n]', 'name_location': 'middle',
|
|
443
|
+
})
|
|
444
|
+
yAxis.append({
|
|
445
|
+
'extent': [float(yaxis.min), float(yaxis.max)],
|
|
446
|
+
'interval': [float("{:g}".format(float(yaxis.min) + i * float(yaxis.interval))) for i in range(int(yaxis.split_number) + 1)],
|
|
447
|
+
'id': 0, 'show_frame': True, 'z_index': 9,
|
|
448
|
+
'title': 'Argon Released [%]', 'name_location': 'middle',
|
|
449
|
+
})
|
|
450
|
+
return xAxis, yAxis, series
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def _get_plot_data_degas_curve(smp: sample, **options):
|
|
454
|
+
name = options.get('diagram_name', '39Ar')
|
|
455
|
+
color = options.get('color', 'black')
|
|
456
|
+
xAxis, yAxis, series = [], [], []
|
|
457
|
+
nindex = {"40": 24, "39": 20, "38": 10, "37": 8, "36": 0}
|
|
458
|
+
if name[:2] in list(nindex.keys()):
|
|
459
|
+
ar = np.array(smp.DegasValues[nindex[name[:2]]], dtype=np.float64) # 20-21 Ar39
|
|
460
|
+
sar = np.array(smp.DegasValues[nindex[name[:2]] + 1], dtype=np.float64)
|
|
461
|
+
elif 'total' in name:
|
|
462
|
+
all_ar = np.array(smp.CorrectedValues, dtype=np.float64) # 20-21 Ar39
|
|
463
|
+
ar, sar = arr.add(*all_ar.reshape(5, 2, len(all_ar[0])))
|
|
464
|
+
ar = np.array(ar); sar = np.array(sar)
|
|
465
|
+
else:
|
|
466
|
+
raise KeyError
|
|
467
|
+
|
|
468
|
+
while ar[-1] == 0:
|
|
469
|
+
ar = ar[:-1]
|
|
470
|
+
x = list(range(0, len(ar) + 1))
|
|
471
|
+
f = ar / sum(ar) * 100
|
|
472
|
+
released = np.zeros(len(ar) + 1)
|
|
473
|
+
remained = np.zeros(len(ar) + 1) + 100
|
|
474
|
+
for i in range(1, len(ar) + 1):
|
|
475
|
+
released[i] = sum(f[:i])
|
|
476
|
+
remained[i] = 100 - released[i]
|
|
477
|
+
|
|
478
|
+
# line
|
|
479
|
+
series.append({
|
|
480
|
+
'type': 'line', 'id': f'line-{get_random_digits()}', 'name': f'line-{get_random_digits()}',
|
|
481
|
+
'color': color, 'myType': 'line', 'line_width': 1, 'line_style': 'solid',
|
|
482
|
+
'data': np.array([x, released]).transpose().tolist(),
|
|
483
|
+
'axis_index': 0, 'z_index': 99
|
|
484
|
+
})
|
|
485
|
+
series.append({
|
|
486
|
+
'type': 'line', 'id': f'line-{get_random_digits()}', 'name': f'line-{get_random_digits()}',
|
|
487
|
+
'color': color, 'myType': 'line', 'line_width': 1, 'line_style': 'solid',
|
|
488
|
+
'data': np.array([x, remained]).transpose().tolist(),
|
|
489
|
+
'axis_index': 0, 'z_index': 99
|
|
490
|
+
})
|
|
491
|
+
|
|
492
|
+
xAxis.append({
|
|
493
|
+
'extent': [0, 100],
|
|
494
|
+
'interval': [0, 20, 40, 60, 80, 100],
|
|
495
|
+
'id': 0, 'show_frame': True, 'z_index': 9,
|
|
496
|
+
'title': 'Steps [n]', 'name_location': 'middle',
|
|
497
|
+
})
|
|
498
|
+
yAxis.append({
|
|
499
|
+
'extent': [0, 100],
|
|
500
|
+
'interval': [0, 20, 40, 60, 80, 100],
|
|
501
|
+
'id': 0, 'show_frame': True, 'z_index': 9,
|
|
502
|
+
'title': 'Argon [%]', 'name_location': 'middle',
|
|
503
|
+
})
|
|
504
|
+
return xAxis, yAxis, series
|
|
505
|
+
|
|
506
|
+
|
|
44
507
|
class ExcelTemplate:
|
|
45
508
|
def __init__(self, **kwargs):
|
|
46
509
|
self.name = ""
|
ararpy/smp/json.py
CHANGED
|
@@ -22,7 +22,8 @@ def dumps(a):
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def loads(a):
|
|
25
|
-
|
|
25
|
+
# null will be converted to None by default, replace None with np.nan
|
|
26
|
+
return json.loads(a, object_hook=myHook)
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class MyEncoder(json.JSONEncoder):
|
|
@@ -51,3 +52,13 @@ class MyEncoder(json.JSONEncoder):
|
|
|
51
52
|
if not isinstance(obj, (int, str, list, dict, tuple, float)):
|
|
52
53
|
print(f"Special type, {type(obj) = }, {obj = }")
|
|
53
54
|
return super(MyEncoder, self).default(obj)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def myHook(obj):
|
|
58
|
+
if isinstance(obj, dict):
|
|
59
|
+
return {k: myHook(v) for k, v in obj.items()}
|
|
60
|
+
elif isinstance(obj, list):
|
|
61
|
+
return [myHook(v) for v in obj]
|
|
62
|
+
elif obj is None:
|
|
63
|
+
return np.nan
|
|
64
|
+
return obj
|
ararpy/smp/plots.py
CHANGED
|
@@ -61,16 +61,20 @@ def set_plot_data(sample: Sample, isInit: bool = True, isIsochron: bool = True,
|
|
|
61
61
|
try:
|
|
62
62
|
initial_plot_data(sample)
|
|
63
63
|
except (Exception, BaseException):
|
|
64
|
-
print(traceback.format_exc())
|
|
64
|
+
# print(traceback.format_exc())
|
|
65
65
|
pass
|
|
66
66
|
|
|
67
67
|
# Recalculate isochron lines
|
|
68
68
|
if isIsochron:
|
|
69
69
|
try:
|
|
70
70
|
recalc_isochrons(sample, **kwargs)
|
|
71
|
+
except (Exception, BaseException):
|
|
72
|
+
# print(traceback.format_exc())
|
|
73
|
+
pass
|
|
74
|
+
try:
|
|
71
75
|
reset_isochron_line_data(sample)
|
|
72
76
|
except (Exception, BaseException):
|
|
73
|
-
print(traceback.format_exc())
|
|
77
|
+
# print(traceback.format_exc())
|
|
74
78
|
pass
|
|
75
79
|
|
|
76
80
|
# Recalculate plateaus
|
|
@@ -78,7 +82,7 @@ def set_plot_data(sample: Sample, isInit: bool = True, isIsochron: bool = True,
|
|
|
78
82
|
try:
|
|
79
83
|
recalc_plateaus(sample)
|
|
80
84
|
except (Exception, BaseException):
|
|
81
|
-
print(traceback.format_exc())
|
|
85
|
+
# print(traceback.format_exc())
|
|
82
86
|
pass
|
|
83
87
|
|
|
84
88
|
|
|
@@ -237,7 +241,7 @@ def get_isochron_results(data: list, smp: Sample, sequence, figure_type: int = 0
|
|
|
237
241
|
try:
|
|
238
242
|
regression_res = regression_method(*data[:5])
|
|
239
243
|
except (Exception, BaseException):
|
|
240
|
-
print(f"Warning: {traceback.format_exc()}")
|
|
244
|
+
# print(f"Warning: {traceback.format_exc()}")
|
|
241
245
|
return iso_res
|
|
242
246
|
else:
|
|
243
247
|
iso_res.update(dict(zip(reg_res_index, regression_res)))
|
|
@@ -305,11 +309,11 @@ def get_3D_results(data: list, sequence: list, sample: Sample):
|
|
|
305
309
|
Q = 1 - np.exp(-1 * sample.TotalParam[46][0] * sum(sample.TotalParam[32]) / len(sample.TotalParam[32]))
|
|
306
310
|
P = PQ / Q
|
|
307
311
|
except:
|
|
308
|
-
print(f"Warning: {traceback.format_exc()}")
|
|
312
|
+
# print(f"Warning: {traceback.format_exc()}")
|
|
309
313
|
P = 0
|
|
310
314
|
age = basic.calc_age([f, sf], smp=sample)
|
|
311
315
|
except:
|
|
312
|
-
print(f"Warning: {traceback.format_exc()}")
|
|
316
|
+
# print(f"Warning: {traceback.format_exc()}")
|
|
313
317
|
k = [0] * 15
|
|
314
318
|
age = [0] * 4
|
|
315
319
|
ar40ar36, sar40ar36, P = 0, 0, 0
|
ararpy/smp/raw.py
CHANGED
|
@@ -50,8 +50,15 @@ def to_raw(file_path: Union[str, List[str]], input_filter_path: Union[str, List[
|
|
|
50
50
|
data = res.get('data', None)
|
|
51
51
|
sequences = res.get('sequences', None)
|
|
52
52
|
sequence_num = len(data) if data is not None else len(sequences)
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
# default fitting method, all exponential
|
|
54
|
+
# <option value=0>Linear</option>
|
|
55
|
+
# <option value=1>Quadratic</option>
|
|
56
|
+
# <option value=2>Exponential</option>
|
|
57
|
+
# <option value=3>Power</option>
|
|
58
|
+
# <option value=4>Average</option>
|
|
59
|
+
fitting_method = [2, 0, 2, 2, 2]
|
|
60
|
+
raw = RawData(name=file_name, data=data, isotopic_num=10, sequence_num=sequence_num, source=[file_path],
|
|
61
|
+
sequence=sequences, unit=str(input_filter[30]), fitting_method=[*fitting_method])
|
|
55
62
|
else:
|
|
56
63
|
raise ValueError("File path and input filter should be both string or list with a same length.")
|
|
57
64
|
return raw
|
ararpy/smp/sample.py
CHANGED
|
@@ -119,8 +119,8 @@ TOTAL_PARAMS_HEADERS = [
|
|
|
119
119
|
'\u2074\u2070Ar/\u00B3\u2076Ar air', '%1\u03C3',
|
|
120
120
|
'\u00B3\u2078Ar/\u00B3\u2076Ar air', '%1\u03C3', # 95-98
|
|
121
121
|
'Isochron Fitting', 'Convergence', 'Iteration', 'Discrimination', # 99-102
|
|
122
|
-
'Not Zero', 'Corr Blank', 'Corr Discr', 'Corr \u00B3\u2077Ar Decay',
|
|
123
|
-
'Corr \u00B3\u2079Ar Decay', #
|
|
122
|
+
'Not Zero', 'Corr Blank', 'Corr Discr', 'Corr \u00B3\u2077Ar Decay', # 103-106
|
|
123
|
+
'Corr \u00B3\u2079Ar Decay', # 107
|
|
124
124
|
'Ca Degassing', 'K Degassing', 'Cl Degassing', 'Trap Degassing', # 108-111
|
|
125
125
|
'Using Min Equation',
|
|
126
126
|
# 'Recalibration', 'Using Std Age', 'Use Std Ratio', # 112-115 to be completed
|
|
@@ -137,6 +137,11 @@ TOTAL_PARAMS_HEADERS = [
|
|
|
137
137
|
'Heating Time (s)', # 125
|
|
138
138
|
'Heating Actual Temp (C)', # 126
|
|
139
139
|
'Heating AT 1\u03C3', # 127
|
|
140
|
+
'36Ar Gain', '%1\u03C3', # 128-129
|
|
141
|
+
'37Ar Gain', '%1\u03C3', # 130-131
|
|
142
|
+
'38Ar Gain', '%1\u03C3', # 132-133
|
|
143
|
+
'39Ar Gain', '%1\u03C3', # 134-135
|
|
144
|
+
'40Ar Gain', '%1\u03C3', # 136-137
|
|
140
145
|
]
|
|
141
146
|
|
|
142
147
|
SAMPLE_INTERCEPT_SHORT_HEADERS = [
|
|
@@ -245,6 +250,11 @@ TOTAL_PARAMS_SHORT_HEADERS = [
|
|
|
245
250
|
'HeatingTime', # 125
|
|
246
251
|
'HeatingActualTemp', # 126
|
|
247
252
|
'HeatingActualTempError', # 127
|
|
253
|
+
'36Gain', '%1s', # 128-129
|
|
254
|
+
'37Gain', '%1s', # 130-131
|
|
255
|
+
'38Gain', '%1s', # 132-133
|
|
256
|
+
'39Gain', '%1s', # 134-135
|
|
257
|
+
'40Gain', '%1s', # 136-137
|
|
248
258
|
]
|
|
249
259
|
|
|
250
260
|
DEFAULT_PLOT_STYLES = {
|
|
@@ -731,7 +741,7 @@ DEFAULT_PLOT_STYLES = {
|
|
|
731
741
|
},
|
|
732
742
|
}
|
|
733
743
|
|
|
734
|
-
VERSION = '
|
|
744
|
+
VERSION = '20241028'
|
|
735
745
|
|
|
736
746
|
NAMED_DICT = {
|
|
737
747
|
"unknown": {"header": SAMPLE_INTERCEPT_HEADERS.copy()},
|
|
@@ -832,7 +842,8 @@ class Sample:
|
|
|
832
842
|
# self.__version = '20230730' # delete calcparams attribute
|
|
833
843
|
# self.__version = '20230827' # using merge smp to update arr version
|
|
834
844
|
# self.__version = '20231116' # change smp parameters
|
|
835
|
-
self.__version = '20240730' # change parameter table for thermo calculation
|
|
845
|
+
# self.__version = '20240730' # change parameter table for thermo calculation
|
|
846
|
+
self.__version = '20241028' # gain correction
|
|
836
847
|
|
|
837
848
|
@property
|
|
838
849
|
def version(self):
|
|
@@ -854,7 +865,7 @@ class Sample:
|
|
|
854
865
|
|
|
855
866
|
def sequence(self) -> ArArBasic: ...
|
|
856
867
|
|
|
857
|
-
def recalculate(self, *args): ...
|
|
868
|
+
def recalculate(self, *args, **kwargs): ...
|
|
858
869
|
|
|
859
870
|
def plot_age_plateau(self): ...
|
|
860
871
|
|
|
@@ -1144,16 +1155,21 @@ class RawData:
|
|
|
1144
1155
|
self.isotopic_num = isotopic_num
|
|
1145
1156
|
self.sequence_num = sequence_num
|
|
1146
1157
|
self.interpolated_blank = None
|
|
1147
|
-
if
|
|
1158
|
+
if sequence is not None:
|
|
1159
|
+
self.sequence = sequence
|
|
1160
|
+
elif data is not None:
|
|
1148
1161
|
self.sequence: List[Sequence] = [
|
|
1149
|
-
Sequence(
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1162
|
+
Sequence(
|
|
1163
|
+
index=index,
|
|
1164
|
+
name=item[0][0] if isinstance(item[0][0], str) and item[0][0] != '' else f"{self.name}-{index + 1:02d}",
|
|
1165
|
+
data=item[1:],
|
|
1166
|
+
datetime=item[0][1],
|
|
1167
|
+
type_str=item[0][2],
|
|
1168
|
+
fitting_method=[*kwargs.get("fitting_method", [0] * 5)],
|
|
1169
|
+
options=item[0][3]
|
|
1170
|
+
) for index, item in enumerate(data)]
|
|
1153
1171
|
else:
|
|
1154
1172
|
self.sequence: List[Sequence] = []
|
|
1155
|
-
if sequence is not None:
|
|
1156
|
-
self.sequence = sequence
|
|
1157
1173
|
for k, v in kwargs.items():
|
|
1158
1174
|
if hasattr(self, k) and type(getattr(self, k)) is MethodType:
|
|
1159
1175
|
continue
|