majoplot 0.1.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.
- majoplot/__init__.py +0 -0
- majoplot/__main__.py +25 -0
- majoplot/app/__init__.py +0 -0
- majoplot/app/cli.py +259 -0
- majoplot/app/gui.py +6 -0
- majoplot/config.json +11 -0
- majoplot/domain/base.py +433 -0
- majoplot/domain/importers/PPMS_Resistivity.py +128 -0
- majoplot/domain/importers/VSM.py +109 -0
- majoplot/domain/importers/XRD.py +62 -0
- majoplot/domain/muti_axes_spec.py +172 -0
- majoplot/domain/scenarios/PPMS_Resistivity/RT.py +119 -0
- majoplot/domain/scenarios/VSM/MT.py +131 -0
- majoplot/domain/scenarios/VSM/MT_insert.py +135 -0
- majoplot/domain/scenarios/VSM/MT_reliability_analysis.py +145 -0
- majoplot/domain/scenarios/XRD/Compare.py +104 -0
- majoplot/domain/utils.py +87 -0
- majoplot/gui/__init__.py +0 -0
- majoplot/gui/main.py +529 -0
- majoplot/infra/plotters/matplot.py +337 -0
- majoplot/infra/plotters/origin.py +1006 -0
- majoplot/infra/plotters/origin_utils/originlab_type_library.py +403 -0
- majoplot-0.1.0.dist-info/METADATA +81 -0
- majoplot-0.1.0.dist-info/RECORD +27 -0
- majoplot-0.1.0.dist-info/WHEEL +4 -0
- majoplot-0.1.0.dist-info/entry_points.txt +2 -0
- majoplot-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from ..base import *
|
|
5
|
+
|
|
6
|
+
class XRD:
|
|
7
|
+
instrument = "XRD"
|
|
8
|
+
|
|
9
|
+
@classmethod
|
|
10
|
+
def fetch_raw_data(cls, raw_data_file:TextIO, raw_data_name:str)->Data|FAIL:
|
|
11
|
+
labels = LabelDict(
|
|
12
|
+
initital={"instrument":cls.instrument ,"raw_data": LabelValue(raw_data_name)},
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# read
|
|
16
|
+
initial_pos = raw_data_file.tell() # remember current position
|
|
17
|
+
first_line = raw_data_file.readline().strip()
|
|
18
|
+
match first_line:
|
|
19
|
+
case "<?xml version=\"1.0\" encoding=\"UTF-8\"?>":
|
|
20
|
+
# xrdml from XRD
|
|
21
|
+
import xml.etree.ElementTree as ET
|
|
22
|
+
from datetime import datetime
|
|
23
|
+
raw_data_file.seek(initial_pos) # rewind to original position
|
|
24
|
+
_headers = ("2θ","I")
|
|
25
|
+
tree = ET.parse(raw_data_file)
|
|
26
|
+
root = tree.getroot()
|
|
27
|
+
# Get the default namespace URI from the root tag: "{uri}xrdMeasurements"
|
|
28
|
+
ns_uri = root.tag.split("}")[0].lstrip("{")
|
|
29
|
+
ns = {"x": ns_uri}
|
|
30
|
+
start = float(root.find(".//x:positions[@axis='2Theta']/x:startPosition", ns).text)
|
|
31
|
+
end = float(root.find(".//x:positions[@axis='2Theta']/x:endPosition", ns).text)
|
|
32
|
+
ts_elem = root.find(".//x:startTimeStamp", ns)
|
|
33
|
+
ts = ts_elem.text.strip()
|
|
34
|
+
# Parse ISO 8601 with timezone offset
|
|
35
|
+
dt = datetime.fromisoformat(ts)
|
|
36
|
+
|
|
37
|
+
# Format date as YYYYMMDD
|
|
38
|
+
labels["date"] = dt.strftime("%Y%m%d")
|
|
39
|
+
|
|
40
|
+
intensities_text = root.find(".//x:intensities", ns).text
|
|
41
|
+
I = np.fromstring(intensities_text, sep=" ")
|
|
42
|
+
base = np.max(I) / 100
|
|
43
|
+
I = I / base
|
|
44
|
+
two_theta = np.linspace(start, end, I.size)
|
|
45
|
+
points = np.column_stack([two_theta, I])
|
|
46
|
+
labels["source"] = "experiment"
|
|
47
|
+
return Data(labels=labels, _headers=_headers, points=points)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
case "h k l d (Å) F(real) F(imag) |F| 2θ I M ID(λ) Phase":
|
|
51
|
+
# Refraction table from CIF by VESTA
|
|
52
|
+
_headers = ("2θ","I","h","k","l")
|
|
53
|
+
indexs = {"2θ":7,"I":8,"h":0,"k":1,"l":2}
|
|
54
|
+
points = []
|
|
55
|
+
for line in raw_data_file:
|
|
56
|
+
cells = line.split()
|
|
57
|
+
points.append([float(cells[indexs[head]]) for head in _headers])
|
|
58
|
+
labels["source"] = "cif"
|
|
59
|
+
return Data(labels=labels,_headers=_headers,points=np.array(points))
|
|
60
|
+
|
|
61
|
+
case _:
|
|
62
|
+
return fail_signal
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import NamedTuple
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
import numpy as np
|
|
5
|
+
from itertools import chain
|
|
6
|
+
|
|
7
|
+
from .base import *
|
|
8
|
+
|
|
9
|
+
class InsertAxesSpec(NamedTuple):
|
|
10
|
+
x:float
|
|
11
|
+
y:float
|
|
12
|
+
width:float
|
|
13
|
+
height:float
|
|
14
|
+
legend_holder:str="last axes"
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def default(cls, figure_size:tuple[float], axes_pool:list[Axes])->InsertAxesSpec:
|
|
18
|
+
POINT_BOX = 0.01
|
|
19
|
+
MARGIN_SCALE_OFFSET = 0.05
|
|
20
|
+
PIXEL_NUM = 20
|
|
21
|
+
INSERT_MARGIN_SCALE = 0.8
|
|
22
|
+
MARGIN_CENTER_OFFSET = 0.85
|
|
23
|
+
INSERT_TOP_PIXEL_MARGEN = 0
|
|
24
|
+
INSERT_RIGHT_PIXEL_MARGEN = 0
|
|
25
|
+
FAIL_AREA_THRESHOLD = 0.1
|
|
26
|
+
ASPECT_RATIO = 1
|
|
27
|
+
|
|
28
|
+
if len(axes_pool) > 2:
|
|
29
|
+
return fail_signal
|
|
30
|
+
main = axes_pool[0]
|
|
31
|
+
|
|
32
|
+
# collect scatters in main
|
|
33
|
+
main_scatters = chain.from_iterable(data.points_for_plot for data in main.data_pool)
|
|
34
|
+
|
|
35
|
+
# get the xlim, ylim of main
|
|
36
|
+
xlim = main.xlim
|
|
37
|
+
ylim = main.ylim
|
|
38
|
+
x_span_min = main.spec.x_log_scale_min_span
|
|
39
|
+
y_span_min = main.spec.y_log_scale_min_span
|
|
40
|
+
if xlim[0] > 0 and xlim[1] > 0 and (xlim[1] / xlim[0]) >= x_span_min:
|
|
41
|
+
xlim = (np.log10(xlim[0]), np.log10(xlim[1]))
|
|
42
|
+
if ylim[0] > 0 and ylim[0] > 0 and (ylim[1] / ylim[0]) >= y_span_min:
|
|
43
|
+
ylim = (np.log10(ylim[0]), np.log10(ylim[1]))
|
|
44
|
+
|
|
45
|
+
width = xlim[1] - xlim[0]
|
|
46
|
+
height = ylim[1] - ylim[0]
|
|
47
|
+
x_offset = width * MARGIN_SCALE_OFFSET
|
|
48
|
+
y_offset = height * MARGIN_SCALE_OFFSET
|
|
49
|
+
width += x_offset * 2
|
|
50
|
+
height += y_offset *2
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Examine the occupation situation
|
|
54
|
+
occ = np.zeros((PIXEL_NUM, PIXEL_NUM))
|
|
55
|
+
box_t = lambda n: min(n,PIXEL_NUM-1)
|
|
56
|
+
box_b = lambda n: max(n,0)
|
|
57
|
+
for scatter in main_scatters:
|
|
58
|
+
x,y = scatter[:2]
|
|
59
|
+
x_pos = (x - xlim[0] + x_offset)/width
|
|
60
|
+
y_pos = (y - ylim[0] + y_offset)/height
|
|
61
|
+
xbox = (x_pos - POINT_BOX, x_pos + POINT_BOX)
|
|
62
|
+
ybox = (y_pos - POINT_BOX, y_pos + POINT_BOX)
|
|
63
|
+
x_pixel_box = range(box_b(np.int_(xbox[0]*PIXEL_NUM)), box_t(np.int_(xbox[1]*PIXEL_NUM)+1))
|
|
64
|
+
y_pixel_box = range(box_b(np.int_(ybox[0]*PIXEL_NUM)), box_t(np.int_(ybox[1]*PIXEL_NUM)+1))
|
|
65
|
+
for i in x_pixel_box:
|
|
66
|
+
for j in y_pixel_box:
|
|
67
|
+
occ[j,i] = 1
|
|
68
|
+
|
|
69
|
+
# matrix to histograms
|
|
70
|
+
histograms = np.zeros((PIXEL_NUM, PIXEL_NUM))
|
|
71
|
+
for x in range(PIXEL_NUM):
|
|
72
|
+
for y in range(PIXEL_NUM):
|
|
73
|
+
h = 0
|
|
74
|
+
for i in reversed(range(y+1)):
|
|
75
|
+
if occ[i,x] == 0:
|
|
76
|
+
h+=1
|
|
77
|
+
else:
|
|
78
|
+
break
|
|
79
|
+
histograms[y, x] = h
|
|
80
|
+
import matplotlib.pyplot as plt
|
|
81
|
+
@dataclass(slots=True)
|
|
82
|
+
class Rectangle:
|
|
83
|
+
x0:int|np.int_
|
|
84
|
+
x1:int|np.int_
|
|
85
|
+
y1:int|np.int_
|
|
86
|
+
h:int|np.int_
|
|
87
|
+
w:int|np.int_ = field(init=False,default=0)
|
|
88
|
+
taller:bool = field(init=False,default=False)
|
|
89
|
+
S:float|np.float64 = field(init=False,default=0)
|
|
90
|
+
|
|
91
|
+
def __post_init__(self):
|
|
92
|
+
self.w = self.x1 - self.x0 + 1
|
|
93
|
+
self_aspect_ratio = self.h / self.w
|
|
94
|
+
if self_aspect_ratio < ASPECT_RATIO:
|
|
95
|
+
self.taller = False
|
|
96
|
+
self.S = self.h ** 2 / ASPECT_RATIO
|
|
97
|
+
else:
|
|
98
|
+
self.taller = True
|
|
99
|
+
self.S = self.w ** 2 * ASPECT_RATIO
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
largest_rec = Rectangle(PIXEL_NUM-1,PIXEL_NUM-1,PIXEL_NUM-1,histograms[PIXEL_NUM-1,PIXEL_NUM-1])
|
|
103
|
+
|
|
104
|
+
for y in reversed(range(PIXEL_NUM)):
|
|
105
|
+
x_stack = []
|
|
106
|
+
for x in reversed(range(-1,PIXEL_NUM)):
|
|
107
|
+
cur_h = histograms[y, x] if x != -1 else 0
|
|
108
|
+
while x_stack:
|
|
109
|
+
top_x = x_stack[-1]
|
|
110
|
+
h = histograms[y, top_x]
|
|
111
|
+
|
|
112
|
+
if cur_h >= h:
|
|
113
|
+
break
|
|
114
|
+
|
|
115
|
+
x_stack.pop()
|
|
116
|
+
|
|
117
|
+
right = x_stack[-1]-1 if x_stack else PIXEL_NUM-1
|
|
118
|
+
cur_rec = Rectangle(
|
|
119
|
+
x0=x+1,
|
|
120
|
+
x1=right,
|
|
121
|
+
y1=y,
|
|
122
|
+
h=h
|
|
123
|
+
)
|
|
124
|
+
if cur_rec.S > largest_rec.S:
|
|
125
|
+
largest_rec = cur_rec
|
|
126
|
+
x_stack.append(x)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# calculate the final rec para (anchor on left bottom)
|
|
130
|
+
p_x = (largest_rec.x0 - INSERT_RIGHT_PIXEL_MARGEN) / PIXEL_NUM
|
|
131
|
+
p_y = (largest_rec.y1-largest_rec.h - INSERT_TOP_PIXEL_MARGEN) / PIXEL_NUM
|
|
132
|
+
p_w = largest_rec.w / PIXEL_NUM
|
|
133
|
+
p_h = largest_rec.h / PIXEL_NUM
|
|
134
|
+
|
|
135
|
+
margined_S = largest_rec.S / ( PIXEL_NUM ** 2 ) * ( INSERT_MARGIN_SCALE ** 2)
|
|
136
|
+
if margined_S < FAIL_AREA_THRESHOLD:
|
|
137
|
+
return fail_signal
|
|
138
|
+
|
|
139
|
+
if largest_rec.taller:
|
|
140
|
+
adjusted_x = p_x
|
|
141
|
+
adjusted_y = p_y + p_h - p_w * ASPECT_RATIO
|
|
142
|
+
margin_c_x = adjusted_x + p_w * MARGIN_CENTER_OFFSET
|
|
143
|
+
margin_c_y = adjusted_y + p_w * ASPECT_RATIO * MARGIN_CENTER_OFFSET
|
|
144
|
+
margined_w = p_w * INSERT_MARGIN_SCALE
|
|
145
|
+
margined_h = margined_w * ASPECT_RATIO
|
|
146
|
+
else:
|
|
147
|
+
adjusted_x = p_x + p_w - p_h / ASPECT_RATIO
|
|
148
|
+
adjusted_y = p_y
|
|
149
|
+
margin_c_x = adjusted_x + p_h / ASPECT_RATIO * MARGIN_CENTER_OFFSET
|
|
150
|
+
margin_c_y = adjusted_y + p_h * MARGIN_CENTER_OFFSET
|
|
151
|
+
margined_h = p_h * INSERT_MARGIN_SCALE
|
|
152
|
+
margined_w = margined_h / ASPECT_RATIO
|
|
153
|
+
margined_x = (adjusted_x - margin_c_x) * INSERT_MARGIN_SCALE + margin_c_x
|
|
154
|
+
margined_y = (adjusted_y - margin_c_y) * INSERT_MARGIN_SCALE + margin_c_y
|
|
155
|
+
|
|
156
|
+
return InsertAxesSpec(
|
|
157
|
+
legend_holder="last axes",
|
|
158
|
+
x=margined_x,
|
|
159
|
+
y=margined_y,
|
|
160
|
+
width=margined_w,
|
|
161
|
+
height=margined_h,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class DualYAxesSpec(NamedTuple):
|
|
167
|
+
legend_holder = "figure"
|
|
168
|
+
|
|
169
|
+
class StackAxesSpec(NamedTuple):
|
|
170
|
+
legend_holder = "axes_self"
|
|
171
|
+
nrows:int
|
|
172
|
+
ncols:int
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ...base import *
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
FIGSIZE = (8, 6)
|
|
7
|
+
|
|
8
|
+
T = "Temperature (K)"
|
|
9
|
+
H = "Magnetic Field (Oe)"
|
|
10
|
+
R = "Resistivity (Ohm-m)"
|
|
11
|
+
RI ={
|
|
12
|
+
1: {"R":"Bridge 1 Resistivity (Ohm-m)", "I":"Bridge 1 Excitation (uA)"},
|
|
13
|
+
2: {"R":"Bridge 2 Resistivity (Ohm-m)", "I":"Bridge 2 Excitation (uA)"},
|
|
14
|
+
3: {"R":"Bridge 3 Resistivity (Ohm-m)", "I":"Bridge 3 Excitation (uA)"},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class RT:
|
|
18
|
+
data_summary_label_names = ["H"]
|
|
19
|
+
axes_label_names = ("date", "raw_data", "bridge", "sample_name")
|
|
20
|
+
figure_label_names = ("date", "raw_data", "bridge", "sample_name")
|
|
21
|
+
figure_summary_label_names = ("raw_data","bridge","sample_name")
|
|
22
|
+
max_axes_in_one_figure = 1
|
|
23
|
+
project_to_child_folder_label_names = {"date":"sample_name"}
|
|
24
|
+
parent_folder_name = "RT"
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def preprocess(cls, raw_datas:list[Data])->list[Data]:
|
|
28
|
+
datas = []
|
|
29
|
+
for raw_data in raw_datas:
|
|
30
|
+
raw_labels = raw_data.labels
|
|
31
|
+
headers = raw_data.headers
|
|
32
|
+
raw_points = raw_data.points
|
|
33
|
+
|
|
34
|
+
# Split by H
|
|
35
|
+
split_datas = []
|
|
36
|
+
|
|
37
|
+
last_H_stage = round(raw_points[0][headers[H]])
|
|
38
|
+
current_points = [ last_H_stage, [ raw_points[0] ] ]
|
|
39
|
+
|
|
40
|
+
for point in raw_points[1:]:
|
|
41
|
+
cur_H_stage = round(point[headers[H]])
|
|
42
|
+
if cur_H_stage != last_H_stage:
|
|
43
|
+
split_datas.append(current_points)
|
|
44
|
+
last_H_stage = cur_H_stage
|
|
45
|
+
current_points = [ last_H_stage, [ point ] ]
|
|
46
|
+
else:
|
|
47
|
+
current_points[1].append(point)
|
|
48
|
+
else:
|
|
49
|
+
split_datas.append(current_points)
|
|
50
|
+
|
|
51
|
+
# 3 bridges
|
|
52
|
+
for H_stage, points in split_datas:
|
|
53
|
+
for i in range(1,4):
|
|
54
|
+
_headerTRI = (T,RI[i]["R"],RI[i]["I"])
|
|
55
|
+
_headers = (T,RI[i]["R"])
|
|
56
|
+
s_points = [ [point[headers[x]] for x in _headerTRI] for point in points]
|
|
57
|
+
# clear null R points
|
|
58
|
+
s_points = np.array([point for point in s_points if point[1]])
|
|
59
|
+
# record
|
|
60
|
+
Imin = np.min(s_points[:,1])
|
|
61
|
+
Imax = np.max(s_points[:,1])
|
|
62
|
+
if (Imax - Imin) / Imax < 0.03:
|
|
63
|
+
Irange = f"{np.mean(s_points[:,1]):.1e}"
|
|
64
|
+
else:
|
|
65
|
+
Irange = f"{Imin:.1e}~{Imax:.1e}"
|
|
66
|
+
labels = LabelDict()
|
|
67
|
+
labels["instrument"] = raw_labels["instrument"]
|
|
68
|
+
labels["raw_data"] = raw_labels["raw_data"]
|
|
69
|
+
labels["date"] = raw_labels["date"]
|
|
70
|
+
labels["bridge"] = LabelValue(i,unit="Bridge",unit_as_postfix=False)
|
|
71
|
+
labels["sample_name"] = raw_labels[f"sample{i}_name"]
|
|
72
|
+
labels["sample_units"] = raw_labels[f"sample{i}_units"]
|
|
73
|
+
labels["H"] = LabelValue(H_stage, unit="Oe")
|
|
74
|
+
labels["I_range"] = LabelValue(Irange,unit="μA")
|
|
75
|
+
labels.summary_names = cls.data_summary_label_names
|
|
76
|
+
datas.append(Data(
|
|
77
|
+
labels=labels,
|
|
78
|
+
_headers=_headers,
|
|
79
|
+
points=s_points[:,0:2],
|
|
80
|
+
ignore_outliers=IgnoreOutlierSpec(min_gap_base=1e-6,min_gap_multiple=10),
|
|
81
|
+
))
|
|
82
|
+
|
|
83
|
+
return datas
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def make_axes_spec(cls, axes_labels)->AxesSpec:
|
|
89
|
+
return AxesSpec(
|
|
90
|
+
x_axis_title=T,
|
|
91
|
+
y_axis_title=R,
|
|
92
|
+
major_grid=None,
|
|
93
|
+
major_tick=TickSpec(),
|
|
94
|
+
legend=LegendSpec(fontsize=5),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def make_figure_spec(cls,figure_labels, axes_pool:Iterable[Axes])->FigureSpec:
|
|
100
|
+
figure_name = figure_labels.brief_summary
|
|
101
|
+
|
|
102
|
+
return FigureSpec(
|
|
103
|
+
name=figure_name,
|
|
104
|
+
title=None,
|
|
105
|
+
figsize=FIGSIZE,
|
|
106
|
+
linestyle_cycle= ("-",),
|
|
107
|
+
linecolor_cycle = (
|
|
108
|
+
"#2d0b59", "#3b0f6f", "#4a136e", "#5a176e", "#6a1c6e",
|
|
109
|
+
"#7a216f", "#8b2770", "#9b2d71", "#ac3372", "#bd3973",
|
|
110
|
+
"#ce4074", "#df4775", "#f04f76", "#f86a5a", "#fb8c3c",
|
|
111
|
+
"#fdbb2d", "#fcfdbf",
|
|
112
|
+
),
|
|
113
|
+
linemarker_cycle = ("o","s","^","v","d","*","x","+"),
|
|
114
|
+
alpa_cycle = (1.0,),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def make_muti_axes_spec(cls, axes_pool:list[Axes])->MutiAxesSpec|FAIL|None:
|
|
119
|
+
return None
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from copy import copy
|
|
3
|
+
|
|
4
|
+
from ...base import *
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
FIGSIZE = (8, 6)
|
|
8
|
+
|
|
9
|
+
T = "Temperature (K)"
|
|
10
|
+
M = "DC Moment Free Ctr (emu)"
|
|
11
|
+
H = "Magnetic Field (Oe)"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MT:
|
|
15
|
+
data_summary_label_names = ["H","cooling_type"]
|
|
16
|
+
axes_label_names = ("material","date","raw_data", "H")
|
|
17
|
+
figure_label_names = ("material","date", "raw_data","H")
|
|
18
|
+
figure_summary_label_names = ("raw_data","date")
|
|
19
|
+
max_axes_in_one_figure = 1
|
|
20
|
+
project_to_child_folder_label_names = {"material":"date","date":"material"}
|
|
21
|
+
parent_folder_name = "MT"
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def preprocess(cls, raw_datas:list[Data])->list[Data]:
|
|
25
|
+
datas = []
|
|
26
|
+
for raw_data in raw_datas:
|
|
27
|
+
raw_labels = raw_data.labels
|
|
28
|
+
headers = raw_data.headers
|
|
29
|
+
raw_points = raw_data.points
|
|
30
|
+
iT = headers[T]
|
|
31
|
+
iH = headers[H]
|
|
32
|
+
iM = headers[M]
|
|
33
|
+
|
|
34
|
+
check_deque = []
|
|
35
|
+
|
|
36
|
+
current_points = []
|
|
37
|
+
current_cool_type = "ZFC"
|
|
38
|
+
try:
|
|
39
|
+
current_points.append(raw_points[0])
|
|
40
|
+
H_stage = round(raw_points[0, iH])
|
|
41
|
+
except KeyError:
|
|
42
|
+
return []
|
|
43
|
+
|
|
44
|
+
def append_data():
|
|
45
|
+
nonlocal current_points, check_deque, datas
|
|
46
|
+
nonlocal current_cool_type
|
|
47
|
+
current_points.append(check_deque.pop(0))
|
|
48
|
+
labels = copy(raw_labels)
|
|
49
|
+
labels["H"] = LabelValue(H_stage, "Oe")
|
|
50
|
+
if current_points[-1][iT] < current_points[0][iT]:
|
|
51
|
+
unused = True
|
|
52
|
+
labels["cooling_type"] = "cooling"
|
|
53
|
+
else:
|
|
54
|
+
unused = False
|
|
55
|
+
if current_cool_type == "ZFC":
|
|
56
|
+
labels["cooling_type"] = "ZFC"
|
|
57
|
+
current_cool_type = "FC"
|
|
58
|
+
else:
|
|
59
|
+
labels["cooling_type"] = "FC"
|
|
60
|
+
current_cool_type = "ZFC"
|
|
61
|
+
labels["scenario"] = "MT"
|
|
62
|
+
labels.summary_names = cls.data_summary_label_names
|
|
63
|
+
datas.append(
|
|
64
|
+
Data(
|
|
65
|
+
labels=labels,
|
|
66
|
+
_headers=(T,M),
|
|
67
|
+
points=np.array(current_points)[:,[iT,iM]],
|
|
68
|
+
ignore_outliers=IgnoreOutlierSpec(
|
|
69
|
+
min_gap_base=5e-7,
|
|
70
|
+
min_gap_multiple=10
|
|
71
|
+
),
|
|
72
|
+
unused=unused,
|
|
73
|
+
))
|
|
74
|
+
|
|
75
|
+
for point in raw_points[1:]:
|
|
76
|
+
check_deque.append(point)
|
|
77
|
+
if len(check_deque) == 2:
|
|
78
|
+
# not the same H?
|
|
79
|
+
if abs(check_deque[1][iH] - H_stage) > 2:
|
|
80
|
+
append_data()
|
|
81
|
+
current_points = [check_deque.pop()]
|
|
82
|
+
H_stage = round(current_points[0][iH])
|
|
83
|
+
current_cool_type = "ZFC"
|
|
84
|
+
# not the same heating curve?
|
|
85
|
+
elif (check_deque[0][iT] - current_points[0][iT])>2 and (check_deque[0][iT] - check_deque[1][iT])>2:
|
|
86
|
+
append_data()
|
|
87
|
+
current_points = [check_deque.pop()]
|
|
88
|
+
else:
|
|
89
|
+
# the same curve
|
|
90
|
+
current_points.append(check_deque.pop(0))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
else:
|
|
94
|
+
while check_deque:
|
|
95
|
+
append_data()
|
|
96
|
+
|
|
97
|
+
return datas
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def make_axes_spec(cls,axes_labels)->AxesSpec:
|
|
102
|
+
return AxesSpec(
|
|
103
|
+
x_axis_title=T,
|
|
104
|
+
y_axis_title=M,
|
|
105
|
+
major_grid=None,
|
|
106
|
+
major_tick=TickSpec(),
|
|
107
|
+
legend=LegendSpec(),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def make_figure_spec(cls,figure_labels, axes_pool:Iterable[Axes])->FigureSpec:
|
|
113
|
+
H_stages = {}
|
|
114
|
+
for axes in axes_pool:
|
|
115
|
+
H_stages[axes.labels["H"]] = None
|
|
116
|
+
|
|
117
|
+
figure_name = f"{figure_labels.brief_summary}-{",".join(str(H_stage) for H_stage in H_stages)}"
|
|
118
|
+
|
|
119
|
+
return FigureSpec(
|
|
120
|
+
name=figure_name,
|
|
121
|
+
title=None,
|
|
122
|
+
figsize=FIGSIZE,
|
|
123
|
+
linestyle_cycle= ("-", "--"),
|
|
124
|
+
linecolor_cycle = ("black", "red"),
|
|
125
|
+
linemarker_cycle = ("o","o","s","s","^","^","v","v","d","d","*","*","x","x","+","+"),
|
|
126
|
+
alpa_cycle = (1.0,),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
@classmethod
|
|
130
|
+
def make_muti_axes_spec(cls, axes_pool:list[Axes])->MutiAxesSpec|FAIL|None:
|
|
131
|
+
return None
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from copy import copy
|
|
3
|
+
|
|
4
|
+
from ...base import *
|
|
5
|
+
from ...muti_axes_spec import InsertAxesSpec
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
FIGSIZE = (8, 6)
|
|
9
|
+
|
|
10
|
+
T = "Temperature (K)"
|
|
11
|
+
M = "DC Moment Free Ctr (emu)"
|
|
12
|
+
H = "Magnetic Field (Oe)"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MT_insert:
|
|
16
|
+
data_summary_label_names = ["H","cooling_type"]
|
|
17
|
+
axes_label_names = ("material","date","raw_data", "H")
|
|
18
|
+
figure_label_names = ("material","date", "raw_data")
|
|
19
|
+
figure_summary_label_names = ("raw_data","date")
|
|
20
|
+
max_axes_in_one_figure = 2
|
|
21
|
+
project_to_child_folder_label_names = {"material":"date","date":"material"}
|
|
22
|
+
parent_folder_name = "MT"
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def preprocess(cls, raw_datas:list[Data])->list[Data]:
|
|
26
|
+
datas = []
|
|
27
|
+
for raw_data in raw_datas:
|
|
28
|
+
raw_labels = raw_data.labels
|
|
29
|
+
headers = raw_data.headers
|
|
30
|
+
raw_points = raw_data.points
|
|
31
|
+
iT = headers[T]
|
|
32
|
+
iH = headers[H]
|
|
33
|
+
iM = headers[M]
|
|
34
|
+
|
|
35
|
+
check_deque = []
|
|
36
|
+
|
|
37
|
+
current_points = []
|
|
38
|
+
current_cool_type = "ZFC"
|
|
39
|
+
try:
|
|
40
|
+
current_points.append(raw_points[0])
|
|
41
|
+
H_stage = round(raw_points[0, iH])
|
|
42
|
+
except KeyError:
|
|
43
|
+
return []
|
|
44
|
+
|
|
45
|
+
def append_data():
|
|
46
|
+
nonlocal current_points, check_deque, datas
|
|
47
|
+
nonlocal current_cool_type
|
|
48
|
+
current_points.append(check_deque.pop(0))
|
|
49
|
+
labels = copy(raw_labels)
|
|
50
|
+
labels["H"] = LabelValue(H_stage, "Oe")
|
|
51
|
+
if current_points[-1][iT] < current_points[0][iT]:
|
|
52
|
+
unused = True
|
|
53
|
+
labels["cooling_type"] = "cooling"
|
|
54
|
+
else:
|
|
55
|
+
unused = False
|
|
56
|
+
if current_cool_type == "ZFC":
|
|
57
|
+
labels["cooling_type"] = "ZFC"
|
|
58
|
+
current_cool_type = "FC"
|
|
59
|
+
else:
|
|
60
|
+
labels["cooling_type"] = "FC"
|
|
61
|
+
current_cool_type = "ZFC"
|
|
62
|
+
labels["scenario"] = "MT"
|
|
63
|
+
labels.summary_names = cls.data_summary_label_names
|
|
64
|
+
datas.append(
|
|
65
|
+
Data(
|
|
66
|
+
labels=labels,
|
|
67
|
+
_headers=(T,M),
|
|
68
|
+
points=np.array(current_points)[:,[iT,iM]],
|
|
69
|
+
ignore_outliers=IgnoreOutlierSpec(
|
|
70
|
+
min_gap_base=5e-7,
|
|
71
|
+
min_gap_multiple=10
|
|
72
|
+
),
|
|
73
|
+
unused=unused,
|
|
74
|
+
))
|
|
75
|
+
|
|
76
|
+
for point in raw_points[1:]:
|
|
77
|
+
check_deque.append(point)
|
|
78
|
+
if len(check_deque) == 2:
|
|
79
|
+
# not the same H?
|
|
80
|
+
if abs(check_deque[1][iH] - H_stage) > 2:
|
|
81
|
+
append_data()
|
|
82
|
+
current_points = [check_deque.pop()]
|
|
83
|
+
H_stage = round(current_points[0][iH])
|
|
84
|
+
current_cool_type = "ZFC"
|
|
85
|
+
# not the same heating curve?
|
|
86
|
+
elif (check_deque[0][iT] - current_points[0][iT])>2 and (check_deque[0][iT] - check_deque[1][iT])>2:
|
|
87
|
+
append_data()
|
|
88
|
+
current_points = [check_deque.pop()]
|
|
89
|
+
else:
|
|
90
|
+
# the same curve
|
|
91
|
+
current_points.append(check_deque.pop(0))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
else:
|
|
95
|
+
while check_deque:
|
|
96
|
+
append_data()
|
|
97
|
+
|
|
98
|
+
return datas
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def make_axes_spec(cls, axes_labels)->AxesSpec:
|
|
103
|
+
return AxesSpec(
|
|
104
|
+
x_axis_title=T,
|
|
105
|
+
y_axis_title=M,
|
|
106
|
+
major_grid=None,
|
|
107
|
+
major_tick=TickSpec(),
|
|
108
|
+
legend=LegendSpec(),
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def make_figure_spec(cls,figure_labels, axes_pool:Iterable[Axes])->FigureSpec:
|
|
114
|
+
H_stages = {}
|
|
115
|
+
for axes in axes_pool:
|
|
116
|
+
H_stages[axes.labels["H"]] = None
|
|
117
|
+
|
|
118
|
+
figure_name = f"{figure_labels.brief_summary}-{",".join(str(H_stage) for H_stage in H_stages)}"
|
|
119
|
+
|
|
120
|
+
return FigureSpec(
|
|
121
|
+
name=figure_name,
|
|
122
|
+
title=None,
|
|
123
|
+
figsize=FIGSIZE,
|
|
124
|
+
linestyle_cycle= ("-", "--"),
|
|
125
|
+
linecolor_cycle = ("black", "red"),
|
|
126
|
+
linemarker_cycle = ("o","o","s","s","^","^","v","v","d","d","*","*","x","x","+","+"),
|
|
127
|
+
alpa_cycle = (1.0,),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def make_muti_axes_spec(cls, axes_pool:list[Axes])->MutiAxesSpec|FAIL|None:
|
|
132
|
+
if len(axes_pool) == 2:
|
|
133
|
+
return InsertAxesSpec.default(FIGSIZE, axes_pool)
|
|
134
|
+
else:
|
|
135
|
+
return None
|