Wanlau commited on
Commit
a4ef31a
·
1 Parent(s): 013b032
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ __pycache__/*
2
+ .vscode/*
NDfilter.py CHANGED
@@ -6,6 +6,7 @@ import pandas as pd
6
 
7
  ## 半衰期单位转换字典
8
  HL_UNITS = {"fs": 1e-15, "ps": 1e-12, "ns": 1e-9, "us": 1e-6, "ms": 1e-3, "s": 1, "m": 60, "h": 3600, "d": 86400, "y": 31557600, "ky": 31557600e3, "My": 31557600e6, "Gy": 31557600e9}
 
9
 
10
  def nuclidesFilterZNA(nuclides_data, Z_min=None, Z_max=None, Z_oe_idx=0, N_min=None, N_max=None, N_oe_idx=0, A_min=None, A_max=None, A_oe_idx=0):
11
  filtered = {}
@@ -186,14 +187,59 @@ def nuclideData_dict2dataframe(nuclideData_dict):
186
  a = nuclideData_dict["a"]
187
  data = []
188
  for level in nuclideData_dict["levels"]:
189
- if level["halflife"]["value"] == "STABLE":
190
- data.append((nom, z, n, a, level["energy"]["value"], level["energy"]["unit"], level["spinParity"], level["massExcess"]["value"], level["massExcess"]["unit"], level["massExcess"]["uncertainty"], None, None, None, None, None))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  else:
192
  hl = level["halflife"]["value"]
193
  hl_unit = level["halflife"]["unit"]
194
- hl_unc = level["halflife"]["uncertainty"]["value"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  for decayMode in level["decayModes"]["observed"]:
196
- data.append((nom, z, n, a, level["energy"]["value"], level["energy"]["unit"], level["spinParity"], level["massExcess"]["value"], level["massExcess"]["unit"], level["massExcess"]["uncertainty"], hl, hl_unit, hl_unc, decayMode["mode"], decayMode["value"]))
197
 
198
  nuclideDataframe = pd.DataFrame(data, columns=["Nuclide", "Z", "N", "A", "E(level)", "E(level) unit", "Spin Parity", "Mass Excess", "Mass Excess unit", "Mass Excess uncertainty", "Halflife", "Halflife unit", "Halflife uncertainty", "Decay Mode", "Branch Ratio"])
199
 
@@ -202,18 +248,143 @@ def nuclideData_dict2dataframe(nuclideData_dict):
202
  def nuclideData_dict2dataframeCompact(nuclideData_dict):
203
  data = []
204
  for level in nuclideData_dict["levels"]:
205
- if level["halflife"]["value"] == "STABLE":
206
- data.append((str(level["energy"]["value"])+" "+level["energy"]["unit"], level["spinParity"], level["massExcess"]["formats"]["NDS"]+" "+level["massExcess"]["unit"], "STABLE", None))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  else:
208
  decayModes = []
209
  for decayMode in level["decayModes"]["observed"]:
210
  decayModes.append((decayMode["mode"], decayMode["value"]))
211
  decayModeDF = pd.DataFrame(decayModes, columns=["Decay Mode", "Branch Ratio"])
212
- data.append((str(level["energy"]["value"])+" "+level["energy"]["unit"], level["spinParity"], level["massExcess"]["formats"]["NDS"]+" "+level["massExcess"]["unit"], level["halflife"]["formats"]["NDS"]+" "+level["halflife"]["unit"], decayModeDF))
213
 
214
  nuclideDataframe = pd.DataFrame(data, columns=["E(level)", "Spin Parity", "Mass Excess", "Halflife", "Decay Modes"])
215
 
216
  return nuclideDataframe
217
 
218
- ###
219
- #nuclidesFilter(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  ## 半衰期单位转换字典
8
  HL_UNITS = {"fs": 1e-15, "ps": 1e-12, "ns": 1e-9, "us": 1e-6, "ms": 1e-3, "s": 1, "m": 60, "h": 3600, "d": 86400, "y": 31557600, "ky": 31557600e3, "My": 31557600e6, "Gy": 31557600e9}
9
+ nuclides_data_path = "data/nndc_nudat_data_export.json"
10
 
11
  def nuclidesFilterZNA(nuclides_data, Z_min=None, Z_max=None, Z_oe_idx=0, N_min=None, N_max=None, N_oe_idx=0, A_min=None, A_max=None, A_oe_idx=0):
12
  filtered = {}
 
187
  a = nuclideData_dict["a"]
188
  data = []
189
  for level in nuclideData_dict["levels"]:
190
+ ## 自旋宇称
191
+ spinParity = None
192
+ if "spinParity" in level:
193
+ spinParity = level["spinParity"]
194
+
195
+ ## 质量过剩
196
+ massExcess = None
197
+ massExcess_unit = None
198
+ massExcess_unc = None
199
+ if not "massExcess" in level:
200
+ pass
201
+ else:
202
+ massExcess = level["massExcess"]["unit"]
203
+ massExcess_unit = level["massExcess"]["value"]
204
+ massExcess_unc = level["massExcess"]["uncertainty"]
205
+
206
+ ## 半衰期
207
+ hl = None
208
+ hl_unit = None
209
+ hl_unc = None
210
+ if not "halflife" in level:
211
+ pass
212
+ elif level["halflife"]["value"] == "STABLE":
213
+ pass
214
  else:
215
  hl = level["halflife"]["value"]
216
  hl_unit = level["halflife"]["unit"]
217
+ if level["halflife"]["uncertainty"]["type"] == "asymmetric":
218
+ hl_unc = "+" + str(level["halflife"]["uncertainty"]["upperLimit"]) + " -" + str(level["halflife"]["uncertainty"]["lowerLimit"])
219
+ elif level["halflife"]["uncertainty"]["type"] == "approximation":
220
+ hl_unc = "≈"
221
+ elif level["halflife"]["uncertainty"]["type"] == "limit":
222
+ if level["halflife"]["uncertainty"]["limitType"] == "lower":
223
+ if level["halflife"]["uncertainty"]["isInclusive"] == True:
224
+ hl_unc = "≥"
225
+ else:
226
+ hl_unc = ">"
227
+ elif level["halflife"]["uncertainty"]["limitType"] == "upper":
228
+ if level["halflife"]["uncertainty"]["isInclusive"] == True:
229
+ hl_unc = "≤"
230
+ else:
231
+ hl_unc = "<"
232
+ else:
233
+ hl_unc = level["halflife"]["uncertainty"]["value"]
234
+
235
+ ## 衰变模式
236
+ if not "decayModes" in level:
237
+ data.append((nom, z, n, a, level["energy"]["value"], level["energy"]["unit"], spinParity, massExcess, massExcess_unit, massExcess_unc, hl, hl_unit, hl_unc, None, None))
238
+ elif len(level["decayModes"]["observed"]) == 0:
239
+ data.append((nom, z, n, a, level["energy"]["value"], level["energy"]["unit"], spinParity, massExcess, massExcess_unit, massExcess_unc, hl, hl_unit, hl_unc, None, None))
240
+ else:
241
  for decayMode in level["decayModes"]["observed"]:
242
+ data.append((nom, z, n, a, level["energy"]["value"], level["energy"]["unit"], spinParity, massExcess, massExcess_unit, massExcess_unc, hl, hl_unit, hl_unc, decayMode["mode"], decayMode["value"]))
243
 
244
  nuclideDataframe = pd.DataFrame(data, columns=["Nuclide", "Z", "N", "A", "E(level)", "E(level) unit", "Spin Parity", "Mass Excess", "Mass Excess unit", "Mass Excess uncertainty", "Halflife", "Halflife unit", "Halflife uncertainty", "Decay Mode", "Branch Ratio"])
245
 
 
248
  def nuclideData_dict2dataframeCompact(nuclideData_dict):
249
  data = []
250
  for level in nuclideData_dict["levels"]:
251
+ ## 自旋宇称
252
+ spinParity = None
253
+ if "spinParity" in level:
254
+ spinParity = level["spinParity"]
255
+
256
+ ## 质量过剩
257
+ massExcess = None
258
+ if not "massExcess" in level:
259
+ pass
260
+ else:
261
+ massExcess = level["massExcess"]["formats"]["NDS"]+" "+level["massExcess"]["unit"]
262
+
263
+ ## 半衰期
264
+ hl = None
265
+ if not "halflife" in level:
266
+ pass
267
+ elif level["halflife"]["value"] == "STABLE":
268
+ hl = "STABLE"
269
+ else:
270
+ hl = level["halflife"]["formats"]["NDS"]+" "+level["halflife"]["unit"]
271
+
272
+ ## 衰变模式
273
+ if not "decayModes" in level:
274
+ data.append((str(level["energy"]["value"])+" "+level["energy"]["unit"], spinParity, massExcess, hl, None))
275
+ elif len(level["decayModes"]["observed"]) == 0:
276
+ data.append((str(level["energy"]["value"])+" "+level["energy"]["unit"], spinParity, massExcess, hl, None))
277
  else:
278
  decayModes = []
279
  for decayMode in level["decayModes"]["observed"]:
280
  decayModes.append((decayMode["mode"], decayMode["value"]))
281
  decayModeDF = pd.DataFrame(decayModes, columns=["Decay Mode", "Branch Ratio"])
282
+ data.append((str(level["energy"]["value"])+" "+level["energy"]["unit"], spinParity, massExcess, hl, decayModeDF))
283
 
284
  nuclideDataframe = pd.DataFrame(data, columns=["E(level)", "Spin Parity", "Mass Excess", "Halflife", "Decay Modes"])
285
 
286
  return nuclideDataframe
287
 
288
+ def nuclidesClassifyHalflife(data_path):
289
+ with open (data_path,'r', encoding='utf-8') as file:
290
+ nuclides_data = json.load(file)
291
+
292
+ classified = []
293
+ for nom, data in nuclides_data.items():
294
+ z = data["z"]
295
+ n = data["n"]
296
+ hl_type = "UN"
297
+
298
+ if len(data["levels"]) == 0:
299
+ hl_type = "UN"
300
+ elif not "halflife" in data["levels"][0]:
301
+ hl_type = "UN"
302
+ elif data["levels"][0]["halflife"]["value"] == "STABLE":
303
+ hl_type = "ST"
304
+ elif not data["levels"][0]["halflife"]["unit"] in HL_UNITS:
305
+ hl_type = "SU"
306
+ else:
307
+ hl_sec = data["levels"][0]["halflife"]["value"] * HL_UNITS[data["levels"][0]["halflife"]["unit"]]
308
+ if hl_sec < 1e-7:
309
+ hl_type = "l100ns"
310
+ elif hl_sec < 1e-6:
311
+ hl_type = "100ns"
312
+ elif hl_sec < 1e-5:
313
+ hl_type = "1us"
314
+ elif hl_sec < 1e-4:
315
+ hl_type = "10us"
316
+ elif hl_sec < 1e-3:
317
+ hl_type = "100us"
318
+ elif hl_sec < 1e-2:
319
+ hl_type = "1ms"
320
+ elif hl_sec < 1e-1:
321
+ hl_type = "10ms"
322
+ elif hl_sec < 1:
323
+ hl_type = "100ms"
324
+ elif hl_sec < 10:
325
+ hl_type = "1s"
326
+ elif hl_sec < 100:
327
+ hl_type = "10s"
328
+ elif hl_sec < 1e3:
329
+ hl_type = "100s"
330
+ elif hl_sec < 1e4:
331
+ hl_type = "1ks"
332
+ elif hl_sec < 1e5:
333
+ hl_type = "10ks"
334
+ elif hl_sec < 1e7:
335
+ hl_type = "100ks"
336
+ elif hl_sec < 1e10:
337
+ hl_type = "10Ms"
338
+ elif hl_sec < 1e15:
339
+ hl_type = "1e10s"
340
+ else:
341
+ hl_type = "1e15s"
342
+
343
+ classified.append({"z":z, "n":n, "type":hl_type})
344
+
345
+ return classified
346
+
347
+ def nuclidesClassifyDecayMode(data_path):
348
+ with open (data_path,'r', encoding='utf-8') as file:
349
+ nuclides_data = json.load(file)
350
+
351
+ classified = []
352
+ for nom, data in nuclides_data.items():
353
+ z = data["z"]
354
+ n = data["n"]
355
+ dm_type = "UNKNOWN"
356
+
357
+ if len(data["levels"]) == 0:
358
+ dm_type = "UNKNOWN"
359
+ elif not "decayModes" in data["levels"][0]:
360
+ dm_type = "UNKNOWN"
361
+ if "halflife" in data["levels"][0]:
362
+ if data["levels"][0]["halflife"]["value"] == "STABLE":
363
+ dm_type = "STABLE"
364
+ else:
365
+ decay_modes = data["levels"][0]["decayModes"]["observed"] + data["levels"][0]["decayModes"]["predicted"]
366
+ if len(decay_modes) == 0:
367
+ dm_type = "UNKNOWN"
368
+ else:
369
+ ## 据分支比排序
370
+ dms1 = []
371
+ dms2 = []
372
+ dmsd = {}
373
+ dmsd1 = []
374
+ for decay_mode in decay_modes:
375
+ if not "value" in decay_mode:
376
+ dms2.append(decay_mode)
377
+ else:
378
+ dmsd[decay_mode["mode"]] = decay_mode
379
+ dmsd1.append((decay_mode["value"], decay_mode["mode"]))
380
+ dmsdf = pd.DataFrame(dmsd1, columns=["value", "mode"])
381
+ dmsdf.sort_values(by="value", ascending=False, inplace=True)
382
+ for mode in dmsdf["mode"]:
383
+ dms1.append(dmsd[mode])
384
+ dms = dms1 + dms2
385
+ dm_type = dms[0]["mode"]
386
+ classified.append({"z":z, "n":n, "type":dm_type})
387
+
388
+ return classified
389
+
390
+ ##test
NDplot.py ADDED
@@ -0,0 +1,468 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import json
3
+ import math
4
+ import re
5
+ import numpy as np
6
+ import pandas as pd
7
+ import matplotlib.pyplot as plt
8
+ #import matplotlib.colors as mcolors
9
+ from matplotlib.patches import Patch
10
+
11
+ ## the synthesis methods: Mass Spectroscopy, Radioactive Decay, Light Particles, Fission, Fusion, Spallation, Projectile Fragmentation, and Transfer/Deep Inelastic Scattering
12
+ colors_synthesisMethods = {
13
+ "MS" : (0, 0, 0),
14
+ "RD" : (0, 255, 255),
15
+ "LP" : (255, 165, 0),
16
+ "FI" : (255, 255, 0),
17
+ "FU" : (255, 0, 0),
18
+ "SP" : (0, 0, 255),
19
+ "PF" : (0, 127, 0),
20
+ "UN" : (127, 0, 127)
21
+ }
22
+
23
+ names_synthesisMethods = {
24
+ "MS" : "Mass Spectroscopy",
25
+ "RD" : "Radioactive Decay",
26
+ "LP" : "Light Particles",
27
+ "FI" : "Fission",
28
+ "FU" : "Fusion",
29
+ "SP" : "Spallation",
30
+ "PF" : "Projectile Fragmentation",
31
+ "UN" : "Transfer/Deep Inelastic"
32
+ }
33
+
34
+ colors_halflife = {
35
+ "l100ns": (247, 189, 222),
36
+ "100ns" : (255, 198, 165),
37
+ "1us" : (255, 231, 198),
38
+ "10us" : (255, 255, 156),
39
+ "100us" : (255, 255, 16),
40
+ "1ms" : (231, 247, 132),
41
+ "10ms" : (214, 239, 57),
42
+ "100ms" : (173, 222, 99),
43
+ "1s" : (82, 181, 82),
44
+ "10s" : (99, 189, 181),
45
+ "100s" : (99, 198, 222),
46
+ "1ks" : (0, 165, 198),
47
+ "10ks" : (8, 154, 148),
48
+ "100ks" : (0, 132, 165),
49
+ "10Ms" : (49, 82, 165),
50
+ "1e10s" : (41, 0, 107),
51
+ "1e15s" : (0, 0, 0),
52
+ "ST" : (0, 0, 0),
53
+ "SU" : (255, 148, 115),
54
+ "UN" : (224, 224, 224)
55
+ }
56
+
57
+ legends_halflife = {
58
+ "l100ns": "<100ns",
59
+ "100ns" : "100ns ~ 1us",
60
+ "1us" : "1us ~ 10us",
61
+ "10us" : "10us ~ 100us",
62
+ "100us" : "100us ~ 1ms",
63
+ "1ms" : "1ms ~ 10ms",
64
+ "10ms" : "10ms ~ 100ms",
65
+ "100ms" : "100ms ~ 1s",
66
+ "1s" : "1s ~ 10s",
67
+ "10s" : "10s ~ 100s",
68
+ "100s" : "100s ~ 1ks",
69
+ "1ks" : "1ks ~ 10ks",
70
+ "10ks" : "10ks ~ 100ks",
71
+ "100ks" : "100ks ~ 10Ms",
72
+ "10Ms" : "10Ms ~ 1e10s",
73
+ "1e10s" : "1e10s ~ 1e15s",
74
+ "1e15s" : ">1e15s",
75
+ "ST" : "STABLE",
76
+ "SU" : "SpecialUnit",
77
+ "UN" : "UNKNOWN"
78
+ }
79
+
80
+ colors_DecayModes = {
81
+ "P" : (255, 148, 115),
82
+ "N" : (156, 123, 189),
83
+ "A" : (255, 255, 66),
84
+ "B-" : (231, 140, 198),
85
+ "EC+B+" : (99, 198, 222),
86
+ "EC" : (0, 132, 165),
87
+ "SF" : (82, 181, 82),
88
+ "STABLE": (0, 0, 0),
89
+ "UNKNOWN":(224, 224, 224)
90
+ }
91
+
92
+ legends_DecayModes = {
93
+ "P" : "Proton",
94
+ "N" : "Neutron",
95
+ "A" : "Alaph",
96
+ "B-" : "Beta-",
97
+ "EC+B+" : "Beta+ ElectronCapture",
98
+ "EC" : "ElectronCapture",
99
+ "SF" : "SpontaneousFission",
100
+ "STABLE": "STABLE",
101
+ "UNKNOWN":"UNKNOWN"
102
+ }
103
+
104
+ nuclides_data_path = "data/nndc_nudat_data_export.json"
105
+ data_synthesisMethods_path = "data/Nuclides_synthesisMethods.json"
106
+ ElementsList_path = "data/ElementsList.json"
107
+ data_NuclidesClassifiedHalflife_path = "data/NuclidesClassifiedHalflife.json"
108
+ data_NuclidesClassifiedDecayModes_path = "data/NuclidesClassifiedDecayModes.json"
109
+
110
+ ## 使用matplotlib绘图
111
+ ## 入参为核素分类模式、所绘制核素区域、显示信息、有无图例
112
+ ## area部分待完善
113
+ def nucildesChartPlotPLT(plot_mode=0, area=((0,0),(118,177)), text_mode=0, have_legend=True):
114
+ ## 确定绘制核素区域
115
+ z_min, n_min = area[0]
116
+ z_max, n_max = area[1]
117
+ area_ysize = z_max - z_min + 1
118
+ area_xsize = n_max - n_min + 1
119
+
120
+ ## 计算坐标时使用的单位为像素,而matplotlib的方法使用的单位为英寸,执行前须进行单位转换
121
+ nbwidth = 40
122
+ nbheight = 40
123
+ dpi = 100
124
+
125
+ ## 根据显示信息确定绘图大小
126
+ if text_mode == 0:
127
+ resize_ratio = 5
128
+ ticks_step = 10
129
+ fontsize_label = 75
130
+ fontsize_ticks = 50
131
+ elif text_mode == 1:
132
+ resize_ratio = 5
133
+ ticks_step = 10
134
+ fontsize_label = 75
135
+ fontsize_ticks = 50
136
+ elif text_mode == 2:
137
+ resize_ratio = 10
138
+ ticks_step = 10
139
+ fontsize_label = 150
140
+ fontsize_ticks = 100
141
+ elif text_mode == 3:
142
+ resize_ratio = 10
143
+ ticks_step = 10
144
+ fontsize_label = 150
145
+ fontsize_ticks = 100
146
+ else:
147
+ resize_ratio = 1
148
+ ticks_step = 10
149
+ fontsize_label = 15
150
+ fontsize_ticks = 10
151
+
152
+ ## 确定绘制范围
153
+ ## 据质子数、中子数取整十
154
+ ## 对于默认的(118,177),绘制范围为(130, 200)
155
+ x_min = math.floor(n_min / 10) * 10
156
+ x_max = math.ceil(n_max / 10) * 10
157
+ y_min = math.floor(z_min / 10) * 10
158
+ y_max = math.ceil(z_max / 10) * 10
159
+
160
+ fig = plt.figure(figsize=(10*resize_ratio*(x_max-x_min)/200, 6*resize_ratio*(y_max-y_min)/130), dpi=dpi)
161
+ ax = plt.gca()
162
+
163
+
164
+ ## 核素区域绘制,默认白色背景
165
+ bg_color = (255, 255, 255)
166
+ color_data = np.full((area_ysize, area_xsize, 3), bg_color)
167
+
168
+ dx = nbwidth * resize_ratio
169
+ dy = nbheight * resize_ratio
170
+ xposg = np.arange(0, area_xsize*dx + dx, dx)
171
+ yposg = np.arange(0, area_ysize*dy + dy, dy)
172
+
173
+ xgrid = np.tile(xposg.reshape(1, -1), (area_ysize + 1, 1))
174
+ ygrid = np.tile(yposg.reshape(-1, 1), (1, area_xsize + 1))
175
+
176
+ xgridI = xgrid / dpi
177
+ ygridI = ygrid / dpi
178
+
179
+ ## 根据核素分类模式上色
180
+ color_data = nucildesChartPlotPLTColor(copy.deepcopy(color_data), plot_mode, z_min, n_min ,z_max, n_max)
181
+
182
+ ## 停用imshow转用pcolormesh以便控制各网格大小以及绘制边框
183
+ #ax.imshow(color_data, origin="lower", extent=[n_min-0.5, n_max+0.5, z_min-0.5, z_max+0.5])
184
+ ax.pcolormesh(xgridI, ygridI, color_data.astype(np.uint8), edgecolors="white", linewidth=4*resize_ratio/dpi)
185
+
186
+
187
+ ## 绘制坐标轴
188
+ ax.set_xlim(((x_min-5)*dx/dpi, (x_max+20)*dx/dpi))
189
+ ax.set_ylim(((y_min-5)*dy/dpi, (y_max+10)*dy/dpi))
190
+ ax.set_xlabel("Neutron number", fontsize=fontsize_label, font='Times New Roman')
191
+ ax.set_ylabel("Proton number" , fontsize=fontsize_label, font='Times New Roman')
192
+
193
+ ## 刻度绘制,同样取整十 (ticks_step = 10)
194
+ xticks = np.arange(x_min, x_max + 20 + ticks_step, ticks_step)
195
+ yticks = np.arange(y_min, y_max + 10 + ticks_step, ticks_step)
196
+ xtickspos = (xticks * dx + np.ones(len(xticks)) * 0.5 * dx) / dpi
197
+ ytickspos = (yticks * dy + np.ones(len(yticks)) * 0.5 * dy) / dpi
198
+ ax.set_xticks(xtickspos, xticks, fontsize=fontsize_ticks)
199
+ ax.set_yticks(ytickspos, yticks, fontsize=fontsize_ticks)
200
+
201
+ ## 图例添加
202
+ ## 默认大小匹配全图绘制
203
+ if have_legend:
204
+ legend_handles = legendHandlesGet(plot_mode)
205
+ if len(legend_handles) < 13:
206
+ fontsize_legend = fontsize_ticks
207
+ else:
208
+ fontsize_legend = fontsize_ticks * 0.6
209
+ plt.legend(handles=legend_handles, loc="lower right", fontsize=fontsize_legend)
210
+
211
+ ## 添加显示信息
212
+ if not text_mode == 0:
213
+ color_weight = np.array((0.299, 0.587, 0.114))
214
+ text_data = nucildesChartPlotPLTText(plot_mode, z_min, n_min ,z_max, n_max)
215
+
216
+ ## 显示元素名称
217
+ if text_mode == 1:
218
+ for tdata in text_data:
219
+ ## 根据方块颜色选择文本颜色(黑或白)
220
+ base_color = color_data[tdata["pos"][1]][tdata["pos"][0]]
221
+ if np.dot(color_weight, base_color) > 128:
222
+ text_color = "black"
223
+ else:
224
+ text_color = "white"
225
+
226
+ txposi = (tdata["pos"][0] + 0.5) * dx / dpi
227
+ typosi = (tdata["pos"][1] + 0.5) * dy / dpi
228
+ ax.text(txposi, typosi, tdata["text01"], ha="center", va="center", color=text_color, fontsize=6)
229
+
230
+ ## 显示核素名称
231
+ elif text_mode == 2:
232
+ for tdata in text_data:
233
+ ## 根据方块颜色选择文本颜色(黑或白)
234
+ base_color = color_data[tdata["pos"][1]][tdata["pos"][0]]
235
+ if np.dot(color_weight, base_color) > 128:
236
+ text_color = "black"
237
+ else:
238
+ text_color = "white"
239
+
240
+ txposi = (tdata["pos"][0] + 0.5) * dx / dpi
241
+ typosi = (tdata["pos"][1] + 0.5) * dy / dpi
242
+ ax.text(txposi, typosi, tdata["text02"], ha="center", va="center", color=text_color, fontsize=6)
243
+
244
+ ## 显示详细信息
245
+ elif text_mode == 3:
246
+ for tdata in text_data:
247
+ ## 根据方块颜色选择文本颜色(黑或白)
248
+ base_color = color_data[tdata["pos"][1]][tdata["pos"][0]]
249
+ if np.dot(color_weight, base_color) > 128:
250
+ text_color = "black"
251
+ else:
252
+ text_color = "white"
253
+
254
+ txposi = (tdata["pos"][0] + 0.5) * dx / dpi
255
+ typosi = (tdata["pos"][1] + 0.85) * dy / dpi
256
+ text = tdata["text02"] + "\n" + tdata["text03"]
257
+ ax.text(txposi, typosi, text, ha="center", va="top", ma="center", color=text_color, fontsize=2.4)
258
+
259
+
260
+
261
+ #fig.savefig("test.svg", format="svg")
262
+ #fig.savefig("test.png", format="png")
263
+ #plt.show()
264
+
265
+ return fig
266
+
267
+ def nucildesChartPlotPLTColor(color_data, mode, z_min, n_min ,z_max, n_max):
268
+ ## 据半衰期上色
269
+ ## 默认使用基态数据
270
+ ## nndc上的nudat3绘制时若基态无数据则会使用激发态的数据,此处与其不同 比如:137Pm、154Lu、161Ta 等
271
+ if mode == 0:
272
+ ## 自NDfilter.nuclidesClassifyHalflife()
273
+ with open(data_NuclidesClassifiedHalflife_path, "r", encoding="utf8") as file:
274
+ data = json.load(file)
275
+
276
+ for row in data:
277
+ if (row["z"] >= z_min and row["z"] <= z_max) and (row["n"] >= n_min and row["n"] <= n_max):
278
+ ypos = row["z"] - z_min
279
+ xpos = row["n"] - n_min
280
+ if row["type"] in colors_halflife:
281
+ color_data[ypos][xpos] = np.array(colors_halflife[row["type"]])
282
+
283
+ ## 据衰变模式上色
284
+ elif mode == 1:
285
+ ## 自NDfilter.nuclidesClassifyDecayMode()
286
+ with open(data_NuclidesClassifiedDecayModes_path, "r", encoding="utf8") as file:
287
+ data = json.load(file)
288
+
289
+ for row in data:
290
+ if (row["z"] >= z_min and row["z"] <= z_max) and (row["n"] >= n_min and row["n"] <= n_max):
291
+ ypos = row["z"] - z_min
292
+ xpos = row["n"] - n_min
293
+ if row["type"] in colors_DecayModes:
294
+ color_data[ypos][xpos] = np.array(colors_DecayModes[row["type"]])
295
+ elif row["type"] in ("2B-", "β⁻"):
296
+ color_data[ypos][xpos] = np.array(colors_DecayModes["B-"])
297
+ elif row["type"] in ("2P", "3P"):
298
+ color_data[ypos][xpos] = np.array(colors_DecayModes["P"])
299
+ elif row["type"] in ("2N"):
300
+ color_data[ypos][xpos] = np.array(colors_DecayModes["N"])
301
+ else:
302
+ color_data[ypos][xpos] = np.array(colors_DecayModes["UNKNOWN"])
303
+
304
+ ## 据合成方法上色
305
+ elif mode == 2:
306
+ with open(data_synthesisMethods_path, "r", encoding="utf8") as file:
307
+ data = json.load(file)
308
+
309
+ for row in data:
310
+ if (row["z"] >= z_min and row["z"] <= z_max) and (row["n"] >= n_min and row["n"] <= n_max):
311
+ ypos = row["z"] - z_min
312
+ xpos = row["n"] - n_min
313
+ if row["type"] in colors_synthesisMethods:
314
+ color_data[ypos][xpos] = np.array(colors_synthesisMethods[row["type"]])
315
+
316
+ return color_data
317
+
318
+ def legendHandlesGet(plot_mode):
319
+ handles = []
320
+ if plot_mode == 0:
321
+ for hl_tag in colors_halflife:
322
+ if hl_tag == "ST":
323
+ pass
324
+ elif hl_tag == "1e15s":
325
+ handles.append(Patch(facecolor=np.array(colors_halflife[hl_tag])/255., label=">1e15s or Stable"))
326
+ else:
327
+ handles.append(Patch(facecolor=np.array(colors_halflife[hl_tag])/255., label=legends_halflife[hl_tag]))
328
+
329
+ elif plot_mode == 1:
330
+ for decay_mode in colors_DecayModes:
331
+ handles.append(Patch(facecolor=np.array(colors_DecayModes[decay_mode])/255., label=legends_DecayModes[decay_mode]))
332
+
333
+ elif plot_mode == 2:
334
+ for synthesis_method in colors_synthesisMethods:
335
+ handles.append(Patch(facecolor=np.array(colors_synthesisMethods[synthesis_method])/255., label=names_synthesisMethods[synthesis_method]))
336
+
337
+ return handles
338
+
339
+ def nucildesChartPlotPLTText(plot_mode, z_min, n_min ,z_max, n_max):
340
+ with open(ElementsList_path, "r", encoding="utf8") as file:
341
+ elements_list = json.load(file)
342
+
343
+ text_data = []
344
+ if plot_mode == 0 or plot_mode == 1:
345
+ with open(nuclides_data_path, "r", encoding="utf8") as file:
346
+ data = json.load(file)
347
+
348
+ ## 填充半衰期及衰变模式信息
349
+ ## 对于衰变模式多于三种的,只显示其前三种(仿nndc)
350
+ ## 对于过长的数字,将会对其进行截断
351
+ for nom, ndata in data.items():
352
+ if (ndata["z"] >= z_min and ndata["z"] <= z_max) and (ndata["n"] >= n_min and ndata["n"] <= n_max):
353
+ ypos = ndata["z"] - z_min
354
+ xpos = ndata["n"] - n_min
355
+ text01 = elements_list[str(ndata["z"])]
356
+ text02 = str(ndata["z"]+ndata["n"]) + text01
357
+
358
+ hlt = ""
359
+ dmst = []
360
+ if len(ndata["levels"]) == 0:
361
+ hlt = ""
362
+ dmst = []
363
+ else:
364
+ if not "halflife" in ndata["levels"][0]:
365
+ hlt = ""
366
+ elif not "value" in ndata["levels"][0]["halflife"]:
367
+ hlt = ""
368
+ elif ndata["levels"][0]["halflife"]["value"] == "STABLE":
369
+ hlt = "STABLE"
370
+ else:
371
+ hlv = ndata["levels"][0]["halflife"]["value"]
372
+ if hlv > 1e4:
373
+ hlt = f"{hlv:.2e}"
374
+ else:
375
+ hlt = str(hlv)
376
+
377
+ if ndata["levels"][0]["halflife"]["unit"] == "m":
378
+ hlt = hlt + " min"
379
+ else:
380
+ hlt = hlt + " " + ndata["levels"][0]["halflife"]["unit"]
381
+
382
+ if not "decayModes" in ndata["levels"][0]:
383
+ dmst = []
384
+ else:
385
+ decay_modes = ndata["levels"][0]["decayModes"]["observed"] + ndata["levels"][0]["decayModes"]["predicted"]
386
+ if len(decay_modes) == 0:
387
+ dmst = []
388
+ else:
389
+ ## 据分支比排序
390
+ dms1 = []
391
+ dms2 = []
392
+ dmsd = {}
393
+ dmsd1 = []
394
+ for decay_mode in decay_modes:
395
+ if not "value" in decay_mode:
396
+ dms2.append(decay_mode)
397
+ else:
398
+ dmsd[decay_mode["mode"]] = decay_mode
399
+ dmsd1.append((decay_mode["value"], decay_mode["mode"]))
400
+ dmsdf = pd.DataFrame(dmsd1, columns=["value", "mode"])
401
+ dmsdf.sort_values(by="value", ascending=False, inplace=True)
402
+ for mode in dmsdf["mode"]:
403
+ dms1.append(dmsd[mode])
404
+ dms = dms1 + dms2
405
+ ###
406
+ for decay_mode in dms:
407
+ text = decay_mode["mode"]
408
+ if not "value" in decay_mode:
409
+ text = text + " ?"
410
+ else:
411
+ dmv = decay_mode["value"]
412
+ dmt = str(dmv)
413
+ if len(dmt) > 7:
414
+ if re.search(rf"([eE])", dmt) == None:
415
+ if dmv > 1e-3:
416
+ dmt = dmt[:7]
417
+ else:
418
+ match00 = re.fullmatch(rf"(0+)(\.)(0+)([1-9]+)", dmt)
419
+ if not match00 == None:
420
+ ne = match00.group(4)
421
+ if len(ne) < 3:
422
+ dmt = f"{dmv:e}"
423
+ else:
424
+ dmt = f"{dmv:.2e}"
425
+ if decay_mode["uncertainty"]["type"] == "limit":
426
+ if decay_mode["uncertainty"]["limitType"] == "lower":
427
+ if decay_mode["uncertainty"]["isInclusive"] == True:
428
+ text = text + " ≥ " + dmt + "%"
429
+ else:
430
+ text = text + " > " + dmt + "%"
431
+ elif decay_mode["uncertainty"]["limitType"] == "upper":
432
+ if decay_mode["uncertainty"]["isInclusive"] == True:
433
+ text = text + " ≤ " + dmt + "%"
434
+ else:
435
+ text = text + " < " + dmt + "%"
436
+ else:
437
+ text = text + " = " + dmt + "%"
438
+ dmst.append(text)
439
+ text03 = hlt + "\n"
440
+ if not len(dmst) > 0:
441
+ pass
442
+ elif len(dmst) <= 3:
443
+ for dmt in dmst:
444
+ text03 = text03 + "\n" + dmt
445
+ else:
446
+ for idx in range(0, 3):
447
+ text03 = text03 + "\n" + dmst[idx]
448
+
449
+ text_data.append({"pos":(xpos, ypos), "text01":text01, "text02":text02, "text03":text03})
450
+
451
+ ## 填充合成方法信息
452
+ elif plot_mode == 2:
453
+ with open(data_synthesisMethods_path, "r", encoding="utf8") as file:
454
+ data = json.load(file)
455
+
456
+ for row in data:
457
+ if (row["z"] >= z_min and row["z"] <= z_max) and (row["n"] >= n_min and row["n"] <= n_max):
458
+ ypos = row["z"] - z_min
459
+ xpos = row["n"] - n_min
460
+ text01 = elements_list[str(row["z"])]
461
+ text02 = str(row["z"]+row["n"]) + text01
462
+ text03 = row["type"]
463
+ text_data.append({"pos":(xpos, ypos), "text01":text01, "text02":text02, "text03":text03})
464
+
465
+ return text_data
466
+
467
+
468
+ ## test
app.py CHANGED
@@ -1,256 +1,349 @@
1
- import gradio as gr
2
- import pandas as pd
3
- import json
4
- from tempfile import NamedTemporaryFile
5
-
6
- import NDfilter
7
-
8
- ## 核素筛选
9
- def process_filters(Z_min, Z_max, Z_oe_idx, N_min, N_max, N_oe_idx, A_min, A_max, A_oe_idx, hl_enable_idx, hl_min, hl_min_unit, hl_max, hl_max_unit, dm_enable_idx, decay_modes):
10
-
11
- filtered_data = NDfilter.nuclidesFilterZNA(nuclides_data, Z_min, Z_max, Z_oe_idx, N_min, N_max, N_oe_idx, A_min, A_max, A_oe_idx)
12
-
13
- # 根据母核半衰期进行筛选
14
- if hl_enable_idx == 1:
15
- hl_min_sec = HLunit_convert(hl_min, hl_min_unit)
16
- hl_max_sec = HLunit_convert(hl_max, hl_max_unit)
17
- filtered_data = NDfilter.nuclidesFilterHalflife(filtered_data, hl_min_sec, hl_max_sec)
18
-
19
- # 根据衰变模式进行筛选
20
- if dm_enable_idx > 0 and decay_modes:
21
- filtered_data = NDfilter.nuclidesFilterDecayModes(filtered_data, dm_enable_idx, decay_modes)
22
-
23
- # 结果处理
24
- if len(filtered_data) == 0:
25
- result_text = "没有找到符合条件的核素"
26
- result_file_path = None
27
- else:
28
- result_text = f"找到 {len(filtered_data)} 个符合条件的核素"
29
- with NamedTemporaryFile(suffix=".json", delete=False, mode='w') as file:
30
- json.dump(filtered_data, file, indent=2)
31
- result_file_path = file.name
32
- return result_text, result_file_path
33
-
34
- ## 核素查找
35
- def process_search(mode_idx, nom, z, n, a, preview_mode, file_type):
36
- result = None
37
- if mode_idx == 0:
38
- result = NDfilter.nuclidesSearchingNom(nuclides_data, nom.replace(" ", ""))
39
- elif mode_idx == 1:
40
- if not (z == None or n == None):
41
- result = NDfilter.nuclidesSearchingZN(nuclides_data, z, n)
42
- elif mode_idx == 2:
43
- if not (z == None or a == None):
44
- result = NDfilter.nuclidesSearchingZA(nuclides_data, z, a)
45
- elif mode_idx == 3:
46
- if not (n == None or a == None):
47
- result = NDfilter.nuclidesSearchingNA(nuclides_data, n, a)
48
-
49
- ## 结果处理
50
- if result == None:
51
- result_text = "没有找到此核素"
52
- result_dataframe = None
53
- result_file_path = None
54
- else:
55
- ## 文本
56
- name = result["name"]
57
- result_text = f"{name}" + "\n\nnndc页面:\n\ngetdataset:\n" + f"https://www.nndc.bnl.gov/nudat3/getdataset.jsp?nucleus={name}&unc=NDS"
58
- ## temp
59
- with open ("data/haveDecayPage.json",'r', encoding='utf-8') as file:
60
- haveDecayPage = json.load(file)
61
- if haveDecayPage[name]:
62
- result_text = result_text + "\n\ndecaysearchdirect:\n" + f"https://www.nndc.bnl.gov/nudat3/decaysearchdirect.jsp?nuc={name}&unc=NDS"
63
-
64
- ## 预览表格
65
- if preview_mode == 0:
66
- result_dataframe = NDfilter.nuclideData_dict2dataframeCompact(result)
67
- elif preview_mode == 1:
68
- result_dataframe = NDfilter.nuclideData_dict2dataframe(result)
69
-
70
- ## 文件
71
- if file_type == 0:
72
- with NamedTemporaryFile(suffix=".json", delete=False, mode='w') as file:
73
- json.dump(result, file, indent=2)
74
- result_file_path = file.name
75
- elif file_type == 1:
76
- if preview_mode == 1:
77
- tmpDataframe = result_dataframe
78
- else:
79
- tmpDataframe = NDfilter.nuclideData_dict2dataframe(result)
80
- with NamedTemporaryFile(suffix=".csv", delete=False, mode='w') as file:
81
- tmpDataframe.to_csv(file, index=False)
82
- result_file_path = file.name
83
-
84
- return result_text, result_dataframe, result_file_path
85
-
86
-
87
- ## 半衰期单位转换
88
- def HLunit_convert(hl, hl_unit):
89
- if hl_unit == "Stable":
90
- hl_sec = None
91
- else:
92
- hl_sec = hl * HL_UNITS[hl_unit]
93
- return hl_sec
94
-
95
- ## 处理查找页面输入组件激活情况
96
- def update_inputs(mode_idx):
97
-
98
- if mode_idx == 0: # 核素名称模式
99
- return [gr.Textbox(interactive=True), gr.Number(interactive=False, value=None), gr.Number(interactive=False, value=None), gr.Number(interactive=False, value=None)]
100
- elif mode_idx == 1: # Z+N模式
101
- return [gr.Textbox(interactive=False, value=None), gr.Number(interactive=True), gr.Number(interactive=True), gr.Number(interactive=False, value=None)]
102
- elif mode_idx == 2: # Z+A模式
103
- return [gr.Textbox(interactive=False, value=None), gr.Number(interactive=True), gr.Number(interactive=False, value=None), gr.Number(interactive=True)]
104
- elif mode_idx == 3: # N+A模式
105
- return [gr.Textbox(interactive=False, value=None), gr.Number(interactive=False, value=None), gr.Number(interactive=True), gr.Number(interactive=True)]
106
- else:
107
- return [gr.Textbox(interactive=False, value=None), gr.Number(interactive=False, value=None), gr.Number(interactive=False, value=None), gr.Number(interactive=False, value=None)]
108
-
109
-
110
-
111
- ## 导入数据集
112
- file_path = "data/nndc_nudat_data_export.json"
113
- with open (file_path,'r', encoding='utf-8') as file:
114
- nuclides_data = json.load(file)
115
-
116
- ## 半衰期单位转换字典
117
- HL_UNITS = {"fs": 1e-15, "ps": 1e-12, "ns": 1e-9, "us": 1e-6, "ms": 1e-3, "s": 1, "m": 60, "h": 3600, "d": 86400, "y": 31557600, "ky": 31557600e3, "My": 31557600e6, "Gy": 31557600e9}
118
-
119
- with gr.Blocks(title="核数据工具") as demo:
120
- gr.Markdown("""
121
- ## 核数据工具
122
- 可能是用来处理核数据的相关工具??
123
- 目前功能有:核素筛选、核素查找。
124
- """)
125
-
126
- with gr.Tab("核素筛选"):
127
- gr.Markdown("""
128
- ## 核素筛选
129
- 可以通过质子数(Z)、中子数(N)、质量数(A)以及母核半衰期、衰变模式等进行筛选
130
- """)
131
- with gr.Row():
132
- with gr.Column(scale=1):
133
- gr.Markdown("根据质子数(Z)、中子数(N)、质量数(A)进行筛选")
134
- with gr.Column(scale=4):
135
- with gr.Row():
136
- with gr.Column(min_width=240):
137
- gr.Markdown("质子数(Z)")
138
- Z_min = gr.Number(label="最小值", precision=0)
139
- Z_max = gr.Number(label="最大值", precision=0)
140
- Z_oe = gr.Dropdown(["任意", "奇Z", "偶Z"], label="奇偶", type="index", interactive=True)
141
- with gr.Column(min_width=240):
142
- gr.Markdown("中子数(N)")
143
- N_min = gr.Number(label="最小值", precision=0)
144
- N_max = gr.Number(label="最大值", precision=0)
145
- N_oe = gr.Dropdown(["任意", "奇N", "偶N"], label="奇偶", type="index", interactive=True)
146
- with gr.Column(min_width=240):
147
- gr.Markdown("质量数(A)")
148
- A_min = gr.Number(label="最小值", precision=0)
149
- A_max = gr.Number(label="最大值", precision=0)
150
- A_oe = gr.Dropdown(["任意", "奇A", "偶A"], label="奇偶", type="index", interactive=True)
151
-
152
- with gr.Row():
153
- with gr.Column(scale=1):
154
- gr.Markdown("根据母核半衰期进行筛选")
155
- with gr.Column(scale=4):
156
- with gr.Row():
157
- hl_enable = gr.Radio(["不使用", "使用"], value="不使用", type="index", show_label=False)
158
- hl_min = gr.Number(label="最小值", minimum=0.)
159
- hl_min_unit = gr.Dropdown(["fs", "ps", "ns", "us", "ms", "s", "m", "h", "d", "y", "ky", "My", "Gy", "Stable"], value="fs", interactive=True)
160
- hl_max = gr.Number(label="最大值", minimum=0.)
161
- hl_max_unit = gr.Dropdown(["fs", "ps", "ns", "us", "ms", "s", "m", "h", "d", "y", "ky", "My", "Gy", "Stable"], value="Stable", interactive=True)
162
-
163
- with gr.Row():
164
- with gr.Column(scale=1):
165
- gr.Markdown("根据衰变模式进行筛选")
166
- with gr.Column(scale=4):
167
- with gr.Row():
168
- dm_enable_idx = gr.Radio(["不使用", "筛选包含所有以下所选衰变模式的核素(and)", "筛选包含任意以下所选衰变模式的核素(or)"], value="不使用", type="index", interactive=True, show_label=False)
169
- with gr.Row():
170
- decayModes = gr.CheckboxGroup(['B-', 'N', '2N', 'B-N', 'P', 'B-A', 'B-2N', 'B-3N', '2P', 'EC', 'A', 'B-4N', 'EC+B+', 'ECA', 'ECP', 'IT', 'EC2P', 'EC3P', 'ECAP', '3P', '2B-', 'ECSF', '14C', 'B-SF', '24NE', 'SF', '20O', '20NE', '25NE', '28MG', 'NE', '22NE', 'SI', 'MG', '34SI'], label="decayModes", interactive=True)
171
-
172
- with gr.Row():
173
- submit_btn = gr.Button("筛选", variant="primary")
174
- reset_btn = gr.Button("重置条件", variant="primary")
175
-
176
- with gr.Row():
177
- result_text = gr.Textbox(label="筛选结果", interactive=False, show_copy_button=True)
178
- result_file = gr.File(label="结果文件", interactive=False)
179
-
180
- inputs = [
181
- Z_min, Z_max, Z_oe,
182
- N_min, N_max, N_oe,
183
- A_min, A_max, A_oe,
184
- hl_enable, hl_min, hl_min_unit, hl_max, hl_max_unit,
185
- dm_enable_idx, decayModes
186
- ]
187
-
188
- submit_btn.click(
189
- fn=process_filters,
190
- inputs=inputs,
191
- outputs=[result_text, result_file]
192
- )
193
-
194
- reset_btn.click(
195
- fn=lambda: [None,None,"任意"]*3 + ["不使用", None, "fs", None, "Stable"] + ["不使用", []],
196
- outputs=inputs
197
- )
198
-
199
-
200
- with gr.Tab("核素查找"):
201
- gr.Markdown("## 核素查找")
202
- with gr.Row():
203
- with gr.Column(scale=3):
204
- searchingMode = gr.Radio(["核素名称", "质子数(Z)、中子数(N)", "质子数(Z)、质量数(A)", "中子数(N)、质量数(A)"], value="核素名称", label="查找模式", interactive=True, type="index")
205
- gr.Markdown("### 根据核素名称查找")
206
- nuclide_in = gr.Textbox(value=None, info="请输入由质量数及元素名称所组成的核素名称,示例:232Th、232TH、th232、232-Th、th-232等。\n只要不太离谱就能识别……大概?")
207
- gr.Markdown("### 根据质子数(Z)、中子数(N)、质量数(A)查找")
208
- with gr.Row():
209
- Z_in = gr.Number(value=0, label="质子数(Z)", precision=0, interactive=False)
210
- N_in = gr.Number(value=0, label="中子数(N)", precision=0, interactive=False)
211
- A_in = gr.Number(value=0, label="质量数(A)", precision=0, interactive=False)
212
- previewMode = gr.Radio(["紧凑", "常规"], value="紧凑", type="index", label="预览模式")
213
- outputFileType = gr.Radio(["json", "csv"], value="json", type="index", label="导出文件格式")
214
- with gr.Row():
215
- submit_btn2 = gr.Button("查找", variant="primary")
216
- reset_btn2 = gr.Button("重置条件", variant="primary")
217
-
218
- with gr.Column(scale=2):
219
- result_text2 = gr.Textbox(interactive=False, show_label=False)
220
- preview_df = gr.Dataframe(label="数据预览", interactive=False)
221
- result_file2 = gr.File()
222
-
223
- searchingMode.change(
224
- fn=update_inputs,
225
- inputs=searchingMode,
226
- outputs=[nuclide_in, Z_in, N_in, A_in]
227
- )
228
-
229
- inputs2 = [
230
- searchingMode,
231
- nuclide_in,
232
- Z_in, N_in, A_in,
233
- previewMode, outputFileType
234
- ]
235
-
236
- submit_btn2.click(
237
- fn=process_search,
238
- inputs=inputs2,
239
- outputs=[result_text2, preview_df, result_file2]
240
- )
241
-
242
- reset_btn2.click(
243
- fn=lambda: [None]*4,
244
- outputs=[nuclide_in, Z_in, N_in, A_in]
245
- )
246
-
247
- with gr.Tab("核素图绘制"):
248
- gr.Markdown("""
249
- ## 核素图绘制
250
- TO DO
251
- """)
252
-
253
-
254
-
255
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  demo.launch()
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import json
4
+ from tempfile import NamedTemporaryFile
5
+
6
+ import NDfilter
7
+ import NDplot
8
+
9
+ ## 核素筛选
10
+ def process_filters(Z_min, Z_max, Z_oe_idx, N_min, N_max, N_oe_idx, A_min, A_max, A_oe_idx, hl_enable_idx, hl_min, hl_min_unit, hl_max, hl_max_unit, dm_enable_idx, decay_modes):
11
+
12
+ filtered_data = NDfilter.nuclidesFilterZNA(nuclides_data, Z_min, Z_max, Z_oe_idx, N_min, N_max, N_oe_idx, A_min, A_max, A_oe_idx)
13
+
14
+ # 根据母核半衰期进行筛选
15
+ if hl_enable_idx == 1:
16
+ hl_min_sec = HLunit_convert(hl_min, hl_min_unit)
17
+ hl_max_sec = HLunit_convert(hl_max, hl_max_unit)
18
+ filtered_data = NDfilter.nuclidesFilterHalflife(filtered_data, hl_min_sec, hl_max_sec)
19
+
20
+ # 根据衰变模式进行筛选
21
+ if dm_enable_idx > 0 and decay_modes:
22
+ filtered_data = NDfilter.nuclidesFilterDecayModes(filtered_data, dm_enable_idx, decay_modes)
23
+
24
+ # 结果处理
25
+ if len(filtered_data) == 0:
26
+ result_text = "没有找到符合条件的核素"
27
+ result_file_path = None
28
+ else:
29
+ result_text = f"找到 {len(filtered_data)} 个符合条件的核素"
30
+ with NamedTemporaryFile(suffix=".json", delete=False, mode='w') as file:
31
+ json.dump(filtered_data, file, indent=2)
32
+ result_file_path = file.name
33
+ return result_text, result_file_path
34
+
35
+ ## 核素查找
36
+ def process_search(mode_idx, nom, z, n, a, preview_mode, file_type):
37
+ result = None
38
+ if mode_idx == 0:
39
+ result = NDfilter.nuclidesSearchingNom(nuclides_data, nom.replace(" ", ""))
40
+ elif mode_idx == 1:
41
+ if not (z == None or n == None):
42
+ result = NDfilter.nuclidesSearchingZN(nuclides_data, z, n)
43
+ elif mode_idx == 2:
44
+ if not (z == None or a == None):
45
+ result = NDfilter.nuclidesSearchingZA(nuclides_data, z, a)
46
+ elif mode_idx == 3:
47
+ if not (n == None or a == None):
48
+ result = NDfilter.nuclidesSearchingNA(nuclides_data, n, a)
49
+
50
+ ## 结果处理
51
+ if result == None:
52
+ result_text = "没有找到此核素"
53
+ result_dataframe = None
54
+ result_file_path = None
55
+ else:
56
+ ## 文本
57
+ name = result["name"]
58
+ result_text = f"{name}"
59
+ if len(result["levels"]) == 0:
60
+ result_text = result_text + "\n此核素无数据"
61
+ result_text = result_text + "\n\nnndc页面:\n\ngetdataset:\n" + f"https://www.nndc.bnl.gov/nudat3/getdataset.jsp?nucleus={name}&unc=NDS"
62
+ ## temp
63
+ with open ("data/haveDecayPage.json",'r', encoding='utf-8') as file:
64
+ haveDecayPage = json.load(file)
65
+ if haveDecayPage[name]:
66
+ result_text = result_text + "\n\ndecaysearchdirect:\n" + f"https://www.nndc.bnl.gov/nudat3/decaysearchdirect.jsp?nuc={name}&unc=NDS"
67
+
68
+ ## 预览表格
69
+ if preview_mode == 0:
70
+ result_dataframe = NDfilter.nuclideData_dict2dataframeCompact(result)
71
+ elif preview_mode == 1:
72
+ result_dataframe = NDfilter.nuclideData_dict2dataframe(result)
73
+
74
+ ## 文件
75
+ if file_type == 0:
76
+ with NamedTemporaryFile(suffix=".json", delete=False, mode='w') as file:
77
+ json.dump(result, file, indent=2)
78
+ result_file_path = file.name
79
+ elif file_type == 1:
80
+ if preview_mode == 1:
81
+ tmpDataframe = result_dataframe
82
+ else:
83
+ tmpDataframe = NDfilter.nuclideData_dict2dataframe(result)
84
+ with NamedTemporaryFile(suffix=".csv", delete=False, mode='w') as file:
85
+ tmpDataframe.to_csv(file, index=False)
86
+ result_file_path = file.name
87
+ else:
88
+ result_file_path = None
89
+
90
+ return result_text, result_dataframe, result_file_path
91
+
92
+ ## 核素图绘制
93
+ def process_plot(plot_mode, text_mode, have_legend_idx, file_type3, using_filter, Z_min=0, Z_max=118, N_min=0, N_max=177):
94
+ if have_legend_idx == 0:
95
+ have_legend = True
96
+ else:
97
+ have_legend = False
98
+
99
+ area = ((0,0),(118,177))
100
+ if using_filter == 1:
101
+ area = ((Z_min,N_min), (Z_max, N_max))
102
+
103
+ result_fig = NDplot.nucildesChartPlotPLT(plot_mode, area, text_mode, have_legend)
104
+
105
+ with NamedTemporaryFile(suffix=".svg", delete=False, mode='wb') as file:
106
+ result_fig.savefig(file, format="svg")
107
+ preview_svg_path = file.name
108
+
109
+ if file_type3 == "png":
110
+ with NamedTemporaryFile(suffix=".png", delete=False, mode='wb') as file:
111
+ result_fig.savefig(file, format="png")
112
+ result_file_path = file.name
113
+ elif file_type3 == "svg":
114
+ result_file_path = preview_svg_path
115
+ else:
116
+ result_file_path = None
117
+
118
+ return result_fig, result_file_path
119
+
120
+
121
+ ## 半衰期单位转换
122
+ def HLunit_convert(hl, hl_unit):
123
+ if hl_unit == "Stable":
124
+ hl_sec = None
125
+ else:
126
+ hl_sec = hl * HL_UNITS[hl_unit]
127
+ return hl_sec
128
+
129
+ ## 处理查找页面输入组件激活情况
130
+ def update_inputs2(mode_idx):
131
+
132
+ if mode_idx == 0: # 核素名称模式
133
+ return [gr.Textbox(interactive=True), gr.Number(interactive=False, value=None), gr.Number(interactive=False, value=None), gr.Number(interactive=False, value=None)]
134
+ elif mode_idx == 1: # Z+N模式
135
+ return [gr.Textbox(interactive=False, value=None), gr.Number(interactive=True), gr.Number(interactive=True), gr.Number(interactive=False, value=None)]
136
+ elif mode_idx == 2: # Z+A模式
137
+ return [gr.Textbox(interactive=False, value=None), gr.Number(interactive=True), gr.Number(interactive=False, value=None), gr.Number(interactive=True)]
138
+ elif mode_idx == 3: # N+A模式
139
+ return [gr.Textbox(interactive=False, value=None), gr.Number(interactive=False, value=None), gr.Number(interactive=True), gr.Number(interactive=True)]
140
+ else:
141
+ return [gr.Textbox(interactive=False, value=None), gr.Number(interactive=False, value=None), gr.Number(interactive=False, value=None), gr.Number(interactive=False, value=None)]
142
+
143
+
144
+ def update_inputs3(using_filter):
145
+ if using_filter == 0:
146
+ return [gr.Number(interactive=False, value=None)] * 4
147
+ elif using_filter == 1:
148
+ return [gr.Number(interactive=True)] * 4
149
+ else:
150
+ return [gr.Number(interactive=False, value=None)] * 4
151
+
152
+ ## 导入数据集
153
+ nuclides_data_path = "data/nndc_nudat_data_export.json"
154
+ with open (nuclides_data_path,'r', encoding='utf-8') as file:
155
+ nuclides_data = json.load(file)
156
+
157
+ ## 半衰期单位转换字典
158
+ HL_UNITS = {"fs": 1e-15, "ps": 1e-12, "ns": 1e-9, "us": 1e-6, "ms": 1e-3, "s": 1, "m": 60, "h": 3600, "d": 86400, "y": 31557600, "ky": 31557600e3, "My": 31557600e6, "Gy": 31557600e9}
159
+
160
+ with gr.Blocks(title="核数据工具") as demo:
161
+ gr.Markdown("""
162
+ ## 核数据工具
163
+ 可能是用来处理核数据的相关工具??
164
+
165
+ 目前功能有:核素筛选、核素查找、核素图绘制。
166
+ """)
167
+
168
+ with gr.Tab("核素筛选"):
169
+ gr.Markdown("""
170
+ ## 核素筛选
171
+ 可以通过质子数(Z)、中子数(N)、质量数(A)以及母核半衰期、衰变模式等进行筛选
172
+ """)
173
+ with gr.Row():
174
+ with gr.Column(scale=1):
175
+ gr.Markdown("根据质子数(Z)、中子数(N)、质量数(A)进行筛选")
176
+ with gr.Column(scale=4):
177
+ with gr.Row():
178
+ with gr.Column(min_width=240):
179
+ gr.Markdown("质子数(Z)")
180
+ Z_min = gr.Number(label="最小值", precision=0)
181
+ Z_max = gr.Number(label="最大值", precision=0)
182
+ Z_oe = gr.Dropdown(["任意", "奇Z", "偶Z"], label="奇偶", type="index", interactive=True)
183
+ with gr.Column(min_width=240):
184
+ gr.Markdown("中子数(N)")
185
+ N_min = gr.Number(label="最小值", precision=0)
186
+ N_max = gr.Number(label="最大值", precision=0)
187
+ N_oe = gr.Dropdown(["任意", "奇N", "偶N"], label="奇偶", type="index", interactive=True)
188
+ with gr.Column(min_width=240):
189
+ gr.Markdown("质量数(A)")
190
+ A_min = gr.Number(label="最小值", precision=0)
191
+ A_max = gr.Number(label="最大值", precision=0)
192
+ A_oe = gr.Dropdown(["任意", "奇A", "偶A"], label="奇偶", type="index", interactive=True)
193
+
194
+ with gr.Row():
195
+ with gr.Column(scale=1):
196
+ gr.Markdown("根据母核半衰期进行筛选")
197
+ with gr.Column(scale=4):
198
+ with gr.Row():
199
+ hl_enable = gr.Radio(["不使用", "使用"], value="不使用", type="index", show_label=False)
200
+ hl_min = gr.Number(label="最小值", minimum=0.)
201
+ hl_min_unit = gr.Dropdown(["fs", "ps", "ns", "us", "ms", "s", "m", "h", "d", "y", "ky", "My", "Gy", "Stable"], value="fs", interactive=True)
202
+ hl_max = gr.Number(label="最大值", minimum=0.)
203
+ hl_max_unit = gr.Dropdown(["fs", "ps", "ns", "us", "ms", "s", "m", "h", "d", "y", "ky", "My", "Gy", "Stable"], value="Stable", interactive=True)
204
+
205
+ with gr.Row():
206
+ with gr.Column(scale=1):
207
+ gr.Markdown("根据衰变模式进行筛选")
208
+ with gr.Column(scale=4):
209
+ with gr.Row():
210
+ dm_enable_idx = gr.Radio(["不使用", "筛选包含所有以下所选衰变模式的核素(and)", "筛选包含任意以下所选衰变模式的核素(or)"], value="不使用", type="index", interactive=True, show_label=False)
211
+ with gr.Row():
212
+ decayModes = gr.CheckboxGroup(['B-', 'N', '2N', 'B-N', 'P', 'B-A', 'B-2N', 'B-3N', '2P', 'EC', 'A', 'B-4N', 'EC+B+', 'ECA', 'ECP', 'IT', 'EC2P', 'EC3P', 'ECAP', '3P', '2B-', 'ECSF', '14C', 'B-SF', '24NE', 'SF', '20O', '20NE', '25NE', '28MG', 'NE', '22NE', 'SI', 'MG', '34SI'], label="decayModes", interactive=True)
213
+
214
+ with gr.Row():
215
+ submit_btn = gr.Button("筛选", variant="primary")
216
+ reset_btn = gr.Button("重置条件", variant="primary")
217
+
218
+ with gr.Row():
219
+ result_text = gr.Textbox(label="筛选结果", interactive=False, show_copy_button=True)
220
+ result_file = gr.File(label="结果文件", interactive=False)
221
+
222
+ inputs = [
223
+ Z_min, Z_max, Z_oe,
224
+ N_min, N_max, N_oe,
225
+ A_min, A_max, A_oe,
226
+ hl_enable, hl_min, hl_min_unit, hl_max, hl_max_unit,
227
+ dm_enable_idx, decayModes
228
+ ]
229
+
230
+ submit_btn.click(
231
+ fn=process_filters,
232
+ inputs=inputs,
233
+ outputs=[result_text, result_file]
234
+ )
235
+
236
+ reset_btn.click(
237
+ fn=lambda: [None,None,"任意"]*3 + ["不使用", None, "fs", None, "Stable"] + ["不使用", []],
238
+ outputs=inputs
239
+ )
240
+
241
+
242
+ with gr.Tab("核素查找"):
243
+ gr.Markdown("## 核素查找")
244
+ with gr.Row():
245
+ with gr.Column(scale=3):
246
+ searchingMode = gr.Radio(["核素名称", "质子数(Z)、中子数(N)", "质子数(Z)、质量数(A)", "中子数(N)、质量数(A)"], value="核素名称", label="查找模式", interactive=True, type="index")
247
+ gr.Markdown("### 根据核素名称查找")
248
+ nuclide_in = gr.Textbox(value=None, info="请输入由质量数及元素名称所组成的核素名称,示例:232Th、232TH、th232、232-Th、th-232等。\n只要不太离谱就能识别……大概?")
249
+ gr.Markdown("### 根据质子数(Z)、中子数(N)、质量数(A)查找")
250
+ with gr.Row():
251
+ Z_in = gr.Number(value=0, label="质子数(Z)", precision=0, interactive=False)
252
+ N_in = gr.Number(value=0, label="中子数(N)", precision=0, interactive=False)
253
+ A_in = gr.Number(value=0, label="质量数(A)", precision=0, interactive=False)
254
+ previewMode = gr.Radio(["紧凑", "常规"], value="紧凑", type="index", label="预览模式")
255
+ outputFileType = gr.Radio(["json", "csv"], value="json", type="index", label="导出文件格式")
256
+ with gr.Row():
257
+ submit_btn2 = gr.Button("查找", variant="primary")
258
+ reset_btn2 = gr.Button("重置条件", variant="primary")
259
+
260
+ with gr.Column(scale=2):
261
+ result_text2 = gr.Textbox(interactive=False, show_label=False)
262
+ preview_df = gr.Dataframe(label="数据预览", interactive=False)
263
+ result_file2 = gr.File(interactive=False)
264
+
265
+ searchingMode.change(
266
+ fn=update_inputs2,
267
+ inputs=searchingMode,
268
+ outputs=[nuclide_in, Z_in, N_in, A_in]
269
+ )
270
+
271
+ inputs2 = [
272
+ searchingMode,
273
+ nuclide_in,
274
+ Z_in, N_in, A_in,
275
+ previewMode, outputFileType
276
+ ]
277
+
278
+ submit_btn2.click(
279
+ fn=process_search,
280
+ inputs=inputs2,
281
+ outputs=[result_text2, preview_df, result_file2]
282
+ )
283
+
284
+ reset_btn2.click(
285
+ fn=lambda: [None]*4,
286
+ outputs=[nuclide_in, Z_in, N_in, A_in]
287
+ )
288
+
289
+ with gr.Tab("核素图绘制"):
290
+ gr.Markdown("""
291
+ ## 核素图绘制
292
+
293
+ 可根据半衰期、衰变模式、合成方法等分类模式绘制核素图。
294
+
295
+ 部分代码参考了Ming-Hao-Zhang的[Nuclei-Chart-Generator](https://github.com/Ming-Hao-Zhang/Nuclei-Chart-Generator)
296
+ """)
297
+ with gr.Row():
298
+ with gr.Column(scale=3):
299
+ img_preview = gr.Plot(label="图片预览")
300
+ with gr.Column(scale=2):
301
+ plot_mode = gr.Radio(["寿命", "衰变模式", "合成方法"], value="寿命", label="核素分类模式", type="index")
302
+ text_mode = gr.Radio(["无", "元素名称", "核素名称", "详细信息"], value="无", label="显示信息", type="index")
303
+ have_legend_idx = gr.Radio(["显示图例", "隐藏图例"], value="显示图例", label="图例", type="index")
304
+ file_type3 = gr.Radio(["svg", "png"], value="svg", label="导出格式", info="png为位图格式,svg为矢量图格式。\n显示详细信息时,受分辨率限制,png格式将会失真。如需高清晰度图像,请使用svg。")
305
+
306
+ with gr.Accordion(open=False, label="更多选项") as filter3:
307
+ gr.Markdown("根据质子数(Z)、中子数(N)筛选 (未启用)")
308
+ using_filter = gr.Radio(["不使用", "使用"], value="不使用", show_label=False, type='index', interactive=False)
309
+ with gr.Row():
310
+ with gr.Column(min_width=120):
311
+ gr.Markdown("质子数(Z)")
312
+ Z_min = gr.Number(label="最小值", precision=0, interactive=False)
313
+ Z_max = gr.Number(label="最大值", precision=0, interactive=False)
314
+ with gr.Column(min_width=120):
315
+ gr.Markdown("中子数(N)")
316
+ N_min = gr.Number(label="最小值", precision=0, interactive=False)
317
+ N_max = gr.Number(label="最大值", precision=0, interactive=False)
318
+
319
+ with gr.Row():
320
+ submit_btn3 = gr.Button("绘制", variant="primary")
321
+ reset_btn3 = gr.Button("重置条件", variant="primary")
322
+
323
+ result_file3 = gr.File(interactive=False)
324
+
325
+ using_filter.change(
326
+ fn=update_inputs3,
327
+ inputs=using_filter,
328
+ outputs=[Z_min, Z_max, N_min, N_max]
329
+ )
330
+
331
+ filter3.collapse(
332
+ fn=lambda: "不使用",
333
+ outputs= using_filter
334
+ )
335
+
336
+ inputs3 = [plot_mode, text_mode, have_legend_idx, file_type3, using_filter, Z_min, Z_max, N_min, N_max]
337
+
338
+ submit_btn3.click(
339
+ fn=process_plot,
340
+ inputs=inputs3,
341
+ outputs=[img_preview, result_file3]
342
+ )
343
+
344
+ reset_btn3.click(
345
+ fn=lambda: ["寿命", "无", "显示图例", "svg", "不使用"] + [None]*4,
346
+ outputs=inputs3
347
+ )
348
+
349
  demo.launch()
data/ElementsList.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"0": "n", "1": "H", "2": "He", "3": "Li", "4": "Be", "5": "B", "6": "C", "7": "N", "8": "O", "9": "F", "10": "Ne", "11": "Na", "12": "Mg", "13": "Al", "14": "Si", "15": "P", "16": "S", "17": "Cl", "18": "Ar", "19": "K", "20": "Ca", "21": "Sc", "22": "Ti", "23": "V", "24": "Cr", "25": "Mn", "26": "Fe", "27": "Co", "28": "Ni", "29": "Cu", "30": "Zn", "31": "Ga", "32": "Ge", "33": "As", "34": "Se", "35": "Br", "36": "Kr", "37": "Rb", "38": "Sr", "39": "Y", "40": "Zr", "41": "Nb", "42": "Mo", "43": "Tc", "44": "Ru", "45": "Rh", "46": "Pd", "47": "Ag", "48": "Cd", "49": "In", "50": "Sn", "51": "Sb", "52": "Te", "53": "I", "54": "Xe", "55": "Cs", "56": "Ba", "57": "La", "58": "Ce", "59": "Pr", "60": "Nd", "61": "Pm", "62": "Sm", "63": "Eu", "64": "Gd", "65": "Tb", "66": "Dy", "67": "Ho", "68": "Er", "69": "Tm", "70": "Yb", "71": "Lu", "72": "Hf", "73": "Ta", "74": "W", "75": "Re", "76": "Os", "77": "Ir", "78": "Pt", "79": "Au", "80": "Hg", "81": "Tl", "82": "Pb", "83": "Bi", "84": "Po", "85": "At", "86": "Rn", "87": "Fr", "88": "Ra", "89": "Ac", "90": "Th", "91": "Pa", "92": "U", "93": "Np", "94": "Pu", "95": "Am", "96": "Cm", "97": "Bk", "98": "Cf", "99": "Es", "100": "Fm", "101": "Md", "102": "No", "103": "Lr", "104": "Rf", "105": "Db", "106": "Sg", "107": "Bh", "108": "Hs", "109": "Mt", "110": "Ds", "111": "Rg", "112": "Cn", "113": "Nh", "114": "Fl", "115": "Mc", "116": "Lv", "117": "Ts", "118": "Og"}
data/NuclidesClassifiedDecayModes.json ADDED
The diff for this file is too large to render. See raw diff
 
data/NuclidesClassifiedHalflife.json ADDED
The diff for this file is too large to render. See raw diff
 
data/Nuclides_synthesisMethods.json ADDED
The diff for this file is too large to render. See raw diff