AeroViz 0.1.5__py3-none-any.whl → 0.1.6__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.
Potentially problematic release.
This version of AeroViz might be problematic. Click here for more details.
- AeroViz/dataProcess/Chemistry/_mass_volume.py +4 -3
- AeroViz/dataProcess/Optical/_IMPROVE.py +2 -3
- AeroViz/dataProcess/SizeDistr/__init__.py +6 -10
- AeroViz/rawDataReader/__init__.py +3 -5
- AeroViz/rawDataReader/config/supported_instruments.py +30 -31
- AeroViz/rawDataReader/core/__init__.py +108 -103
- AeroViz/rawDataReader/script/APS_3321.py +2 -2
- AeroViz/rawDataReader/script/{Sunset_OCEC.py → OCEC.py} +1 -1
- AeroViz/rawDataReader/script/SMPS.py +76 -0
- AeroViz/rawDataReader/script/VOC.py +2 -2
- AeroViz/rawDataReader/script/__init__.py +2 -4
- {AeroViz-0.1.5.dist-info → AeroViz-0.1.6.dist-info}/METADATA +13 -10
- {AeroViz-0.1.5.dist-info → AeroViz-0.1.6.dist-info}/RECORD +16 -18
- AeroViz/rawDataReader/script/SMPS_TH.py +0 -41
- AeroViz/rawDataReader/script/SMPS_aim11.py +0 -51
- AeroViz/rawDataReader/script/SMPS_genr.py +0 -51
- {AeroViz-0.1.5.dist-info → AeroViz-0.1.6.dist-info}/LICENSE +0 -0
- {AeroViz-0.1.5.dist-info → AeroViz-0.1.6.dist-info}/WHEEL +0 -0
- {AeroViz-0.1.5.dist-info → AeroViz-0.1.6.dist-info}/top_level.txt +0 -0
|
@@ -2,13 +2,14 @@ from pandas import concat, DataFrame
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
def _basic(df_che, df_ref, df_water, df_density, nam_lst):
|
|
5
|
+
|
|
5
6
|
df_all = concat(df_che, axis=1)
|
|
6
7
|
index = df_all.index.copy()
|
|
7
8
|
df_all.columns = nam_lst
|
|
8
9
|
|
|
9
10
|
# parameter
|
|
10
11
|
mol_A, mol_S, mol_N = df_all['NH4+'] / 18, df_all['SO42-'] / 96, df_all['NO3-'] / 62
|
|
11
|
-
df_all['status'] =
|
|
12
|
+
df_all['status'] = mol_A / (2 * mol_S + mol_N)
|
|
12
13
|
|
|
13
14
|
convert_nam = {'AS': 'SO42-',
|
|
14
15
|
'AN': 'NO3-',
|
|
@@ -92,7 +93,7 @@ def _basic(df_che, df_ref, df_water, df_density, nam_lst):
|
|
|
92
93
|
df_mass['total'] = df_mass.sum(axis=1, min_count=6)
|
|
93
94
|
|
|
94
95
|
qc_ratio = df_mass['total'] / df_ref
|
|
95
|
-
qc_cond = (qc_ratio >= 0.
|
|
96
|
+
qc_cond = (qc_ratio >= 0.5) & (qc_ratio <= 1.5)
|
|
96
97
|
|
|
97
98
|
# volume
|
|
98
99
|
df_vol = DataFrame()
|
|
@@ -153,7 +154,7 @@ def _basic(df_che, df_ref, df_water, df_density, nam_lst):
|
|
|
153
154
|
out.update(ri_dic)
|
|
154
155
|
|
|
155
156
|
for _ky, _df in out.items():
|
|
156
|
-
out[_ky] = _df.reindex(index)
|
|
157
|
+
out[_ky] = _df.reindex(index)
|
|
157
158
|
|
|
158
159
|
return out
|
|
159
160
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import pickle as pkl
|
|
2
1
|
from pathlib import Path
|
|
3
2
|
|
|
4
3
|
import numpy as np
|
|
5
|
-
from pandas import DataFrame
|
|
4
|
+
from pandas import DataFrame, read_pickle
|
|
6
5
|
|
|
7
6
|
from AeroViz.dataProcess.core import union_index
|
|
8
7
|
|
|
@@ -12,7 +11,7 @@ def _revised(_df_mass, _df_RH):
|
|
|
12
11
|
|
|
13
12
|
# fRH
|
|
14
13
|
with (Path(__file__).parent / 'fRH.pkl').open('rb') as f:
|
|
15
|
-
_fRH =
|
|
14
|
+
_fRH = read_pickle(f)
|
|
16
15
|
_fRH.loc[np.nan] = np.nan
|
|
17
16
|
|
|
18
17
|
def fRH(_RH):
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
from ..core import Writer, run_process
|
|
2
2
|
|
|
3
|
-
__all__ = [
|
|
4
|
-
|
|
5
|
-
'SizeDistr',
|
|
6
|
-
|
|
7
|
-
]
|
|
3
|
+
__all__ = ['SizeDistr']
|
|
8
4
|
|
|
9
5
|
|
|
10
6
|
class SizeDistr(Writer):
|
|
11
7
|
|
|
12
|
-
|
|
8
|
+
# basic
|
|
13
9
|
@run_process('SizeDistr - basic', 'distr_basic')
|
|
14
10
|
def basic(self, df, hybrid_bin_start_loc=None, unit='nm', bin_range=(0, 20000), input_type='norm'):
|
|
15
11
|
from ._size_distr import _basic
|
|
@@ -18,7 +14,7 @@ class SizeDistr(Writer):
|
|
|
18
14
|
|
|
19
15
|
return self, out
|
|
20
16
|
|
|
21
|
-
|
|
17
|
+
# merge
|
|
22
18
|
@run_process('SizeDistr - merge_SMPS_APS_v4', 'distr_merge')
|
|
23
19
|
def merge_SMPS_APS_v4(self, df_smps, df_aps, df_pm25, aps_unit='um',
|
|
24
20
|
smps_overlap_lowbound=500, aps_fit_highbound=1000, dndsdv_alg=True,
|
|
@@ -30,7 +26,7 @@ class SizeDistr(Writer):
|
|
|
30
26
|
|
|
31
27
|
return self, out
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
# merge
|
|
34
30
|
@run_process('SizeDistr - merge_SMPS_APS_v3', 'distr_merge')
|
|
35
31
|
def merge_SMPS_APS_v3(self, df_smps, df_aps, aps_unit='um',
|
|
36
32
|
smps_overlap_lowbound=500, aps_fit_highbound=1000, dndsdv_alg=True):
|
|
@@ -40,7 +36,7 @@ class SizeDistr(Writer):
|
|
|
40
36
|
|
|
41
37
|
return self, out
|
|
42
38
|
|
|
43
|
-
|
|
39
|
+
# merge
|
|
44
40
|
@run_process('SizeDistr - merge_SMPS_APS_v2', 'distr_merge')
|
|
45
41
|
def merge_SMPS_APS_v2(self, df_smps, df_aps, aps_unit='um',
|
|
46
42
|
smps_overlap_lowbound=500, aps_fit_highbound=1000):
|
|
@@ -50,7 +46,7 @@ class SizeDistr(Writer):
|
|
|
50
46
|
|
|
51
47
|
return self, out
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
# merge
|
|
54
50
|
@run_process('SizeDistr - merge_SMPS_APS_v1', 'distr_merge')
|
|
55
51
|
def merge_SMPS_APS(self, df_smps, df_aps, aps_unit='um', shift_mode='mobility',
|
|
56
52
|
smps_overlap_lowbound=523, aps_fit_highbound=800):
|
|
@@ -12,7 +12,7 @@ def RawDataReader(instrument_name: str,
|
|
|
12
12
|
qc: bool = True,
|
|
13
13
|
csv_raw: bool = True,
|
|
14
14
|
reset: bool = False,
|
|
15
|
-
rate: bool =
|
|
15
|
+
rate: bool = True,
|
|
16
16
|
append_data: bool = False,
|
|
17
17
|
start: datetime | None = None,
|
|
18
18
|
end: datetime | None = None,
|
|
@@ -72,9 +72,7 @@ def RawDataReader(instrument_name: str,
|
|
|
72
72
|
instrument_class_map = {
|
|
73
73
|
'NEPH': NEPH,
|
|
74
74
|
'Aurora': Aurora,
|
|
75
|
-
'
|
|
76
|
-
'SMPS_aim11': SMPS_aim11,
|
|
77
|
-
'SMPS_TH': SMPS_TH,
|
|
75
|
+
'SMPS': SMPS,
|
|
78
76
|
'GRIMM': GRIMM,
|
|
79
77
|
'APS_3321': APS_3321,
|
|
80
78
|
'AE33': AE33,
|
|
@@ -82,7 +80,7 @@ def RawDataReader(instrument_name: str,
|
|
|
82
80
|
'BC1054': BC1054,
|
|
83
81
|
'MA350': MA350,
|
|
84
82
|
'TEOM': TEOM,
|
|
85
|
-
'
|
|
83
|
+
'OCEC': OCEC,
|
|
86
84
|
'IGAC': IGAC,
|
|
87
85
|
'VOC': VOC,
|
|
88
86
|
'Table': Table,
|
|
@@ -2,76 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
meta = {
|
|
4
4
|
"NEPH": {
|
|
5
|
-
"pattern": "*.dat",
|
|
5
|
+
"pattern": ["*.dat"],
|
|
6
6
|
"freq": "5min",
|
|
7
7
|
"deter_key": {"Scatter Coe. (550 nm)": ["G"]},
|
|
8
8
|
},
|
|
9
9
|
|
|
10
10
|
"Aurora": {
|
|
11
|
-
"pattern": "*.csv",
|
|
11
|
+
"pattern": ["*.csv"],
|
|
12
12
|
"freq": "1min",
|
|
13
13
|
"deter_key": {"Scatter Coe. (550 nm)": ["G"]},
|
|
14
14
|
},
|
|
15
15
|
|
|
16
|
-
"
|
|
17
|
-
"pattern": "*.txt",
|
|
18
|
-
"freq": "6min",
|
|
19
|
-
"deter_key": {"Bins": ["all"]},
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
"SMPS_genr": {
|
|
23
|
-
"pattern": "*.txt",
|
|
24
|
-
"freq": "6min",
|
|
25
|
-
"deter_key": {"Bins": ["all"]},
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
"SMPS_aim11": {
|
|
29
|
-
"pattern": "*.csv",
|
|
16
|
+
"SMPS": {
|
|
17
|
+
"pattern": ["*.txt", "*.csv"],
|
|
30
18
|
"freq": "6min",
|
|
31
19
|
"deter_key": {"Bins": ["all"]},
|
|
32
20
|
},
|
|
33
21
|
|
|
34
22
|
"GRIMM": {
|
|
35
|
-
"pattern": "*.dat",
|
|
23
|
+
"pattern": ["*.dat"],
|
|
36
24
|
"freq": "6min",
|
|
37
25
|
"deter_key": {"Bins": ["all"]},
|
|
38
26
|
},
|
|
39
27
|
|
|
40
28
|
"APS_3321": {
|
|
41
|
-
"pattern": "*.
|
|
29
|
+
"pattern": ["*.txt"],
|
|
42
30
|
"freq": "6min",
|
|
43
31
|
"deter_key": {"Bins": ["all"]},
|
|
44
32
|
},
|
|
45
33
|
|
|
46
34
|
"AE33": {
|
|
47
|
-
"pattern": "[!ST|!CT|!FV]*[!log]_AE33*.dat",
|
|
35
|
+
"pattern": ["[!ST|!CT|!FV]*[!log]_AE33*.dat"],
|
|
48
36
|
"freq": "1min",
|
|
49
37
|
"deter_key": {"BC Mass Conc. (880 nm)": ["BC6"]},
|
|
50
38
|
"error_state": [],
|
|
51
39
|
},
|
|
52
40
|
|
|
53
41
|
"AE43": {
|
|
54
|
-
"pattern": "[!ST|!CT|!FV]*[!log]_AE43*.dat",
|
|
42
|
+
"pattern": ["[!ST|!CT|!FV]*[!log]_AE43*.dat"],
|
|
55
43
|
"freq": "1min",
|
|
56
44
|
"deter_key": {"BC Mass Conc. (880 nm)": ["BC6"]},
|
|
57
45
|
"error_state": [],
|
|
58
46
|
},
|
|
59
47
|
|
|
60
48
|
"BC1054": {
|
|
61
|
-
"pattern": "*.csv",
|
|
49
|
+
"pattern": ["*.csv"],
|
|
62
50
|
"freq": "1min",
|
|
63
51
|
"deter_key": {"BC Mass Conc. (880 nm)": ["BC9"]},
|
|
64
52
|
"error_state": [1, 2, 4, 8, 16, 32, 65536],
|
|
65
53
|
},
|
|
66
54
|
|
|
67
55
|
"MA350": {
|
|
68
|
-
"pattern": "*.csv",
|
|
56
|
+
"pattern": ["*.csv"],
|
|
69
57
|
"freq": "1min",
|
|
70
58
|
"deter_key": {"BC Mass Conc. (880 nm)": ["BC5"]},
|
|
71
59
|
},
|
|
72
60
|
|
|
73
61
|
"TEOM": {
|
|
74
|
-
"pattern": "*.csv",
|
|
62
|
+
"pattern": ["*.csv"],
|
|
75
63
|
"freq": "6min",
|
|
76
64
|
"deter_key": {
|
|
77
65
|
"PM1.0 Mass Conc.": ["PM_Total"],
|
|
@@ -79,8 +67,8 @@ meta = {
|
|
|
79
67
|
},
|
|
80
68
|
},
|
|
81
69
|
|
|
82
|
-
"
|
|
83
|
-
"pattern": "*LCRes.csv",
|
|
70
|
+
"OCEC": {
|
|
71
|
+
"pattern": ["*LCRes.csv"],
|
|
84
72
|
"freq": "1h",
|
|
85
73
|
"deter_key": {
|
|
86
74
|
"Thermal OC": ["Thermal_OC"],
|
|
@@ -91,7 +79,7 @@ meta = {
|
|
|
91
79
|
},
|
|
92
80
|
|
|
93
81
|
"IGAC": {
|
|
94
|
-
"pattern": "*.csv",
|
|
82
|
+
"pattern": ["*.csv"],
|
|
95
83
|
"freq": "1h",
|
|
96
84
|
"deter_key": {
|
|
97
85
|
"Na+": ["Na+"],
|
|
@@ -108,7 +96,7 @@ meta = {
|
|
|
108
96
|
},
|
|
109
97
|
|
|
110
98
|
"VOC": {
|
|
111
|
-
"pattern": "*.csv",
|
|
99
|
+
"pattern": ["*.csv"],
|
|
112
100
|
"freq": "1h",
|
|
113
101
|
"key": [
|
|
114
102
|
'Benzene', 'Toluene', 'Ethylbenzene', 'm/p-Xylene', 'o-Xylene', 'Ethane', 'Propane', 'Isobutane',
|
|
@@ -129,20 +117,31 @@ meta = {
|
|
|
129
117
|
},
|
|
130
118
|
|
|
131
119
|
"Table": {
|
|
132
|
-
"pattern": "*.csv",
|
|
120
|
+
"pattern": ["*.csv"],
|
|
133
121
|
"freq": "1h",
|
|
134
122
|
"deter_key": None,
|
|
135
123
|
},
|
|
136
124
|
|
|
137
125
|
"EPA_vertical": {
|
|
138
|
-
"pattern": "*.csv",
|
|
126
|
+
"pattern": ["*.csv"],
|
|
139
127
|
"freq": "1h",
|
|
140
128
|
"deter_key": None,
|
|
141
129
|
},
|
|
142
130
|
|
|
143
131
|
"Minion": {
|
|
144
|
-
"pattern": "*.csv",
|
|
132
|
+
"pattern": ["*.csv"],
|
|
145
133
|
"freq": "1h",
|
|
146
|
-
"deter_key":
|
|
134
|
+
"deter_key": {
|
|
135
|
+
"Na+": ["Na+"],
|
|
136
|
+
"NH4+": ["NH4+"],
|
|
137
|
+
"K+": ["K+"],
|
|
138
|
+
"Mg2+": ["Mg2+"],
|
|
139
|
+
"Ca2+": ["Ca2+"],
|
|
140
|
+
"Cl-": ["Cl-"],
|
|
141
|
+
"NO2-": ["NO2-"],
|
|
142
|
+
"NO3-": ["NO3-"],
|
|
143
|
+
"SO42-": ["SO42-"],
|
|
144
|
+
"Main Salt (NH4+, NO3-, SO42-)": ["NO3-", "SO42-", "NH4+"],
|
|
145
|
+
},
|
|
147
146
|
},
|
|
148
147
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import json
|
|
1
|
+
import json
|
|
2
2
|
import logging
|
|
3
3
|
import pickle as pkl
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
@@ -9,28 +9,35 @@ from typing import Any
|
|
|
9
9
|
import numpy as np
|
|
10
10
|
import pandas as pd
|
|
11
11
|
from pandas import DataFrame, date_range, concat, to_numeric, to_datetime
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.progress import Progress, TextColumn, BarColumn, TimeRemainingColumn, TaskProgressColumn
|
|
12
14
|
|
|
13
15
|
from ..config.supported_instruments import meta
|
|
14
16
|
|
|
15
17
|
__all__ = ['AbstractReader']
|
|
16
18
|
|
|
17
19
|
|
|
20
|
+
console = Console(force_terminal=True, color_system="auto")
|
|
21
|
+
|
|
22
|
+
|
|
18
23
|
class AbstractReader(ABC):
|
|
19
|
-
|
|
24
|
+
"""
|
|
25
|
+
Abstract class for reading raw data from different instruments. Each instrument should have a separate class that
|
|
26
|
+
inherits from this class and implements the abstract methods. The abstract methods are `_raw_reader` and `_QC`.
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
28
|
+
List the file in the path and read pickle file if it exists, else read raw data and dump the pickle file the
|
|
29
|
+
pickle file will be generated after read raw data first time, if you want to re-read the rawdata, please set
|
|
30
|
+
'reset=True'
|
|
31
|
+
"""
|
|
23
32
|
|
|
24
|
-
|
|
25
|
-
# pickle file will be generated after read raw data first time, if you want to re-read the rawdata, please set
|
|
26
|
-
# 'reset=True'
|
|
33
|
+
nam = 'AbstractReader'
|
|
27
34
|
|
|
28
35
|
def __init__(self,
|
|
29
36
|
path: Path | str,
|
|
30
37
|
qc: bool = True,
|
|
31
38
|
csv_raw: bool = True,
|
|
32
39
|
reset: bool = False,
|
|
33
|
-
rate: bool =
|
|
40
|
+
rate: bool = True,
|
|
34
41
|
append_data: bool = False):
|
|
35
42
|
|
|
36
43
|
self.path = Path(path)
|
|
@@ -41,7 +48,7 @@ class AbstractReader(ABC):
|
|
|
41
48
|
self.rate = rate
|
|
42
49
|
self.qc = qc
|
|
43
50
|
self.csv = csv_raw
|
|
44
|
-
self.append = append_data
|
|
51
|
+
self.append = append_data and reset
|
|
45
52
|
|
|
46
53
|
self.pkl_nam = self.path / f'_read_{self.nam.lower()}.pkl'
|
|
47
54
|
self.csv_nam = self.path / f'_read_{self.nam.lower()}.csv'
|
|
@@ -49,21 +56,12 @@ class AbstractReader(ABC):
|
|
|
49
56
|
self.csv_nam_raw = self.path / f'_read_{self.nam.lower()}_raw.csv'
|
|
50
57
|
self.csv_out = self.path / f'output_{self.nam.lower()}.csv'
|
|
51
58
|
|
|
52
|
-
# dependency injection function, customize each instrument
|
|
53
|
-
@abstractmethod
|
|
54
|
-
def _raw_reader(self, file):
|
|
55
|
-
pass
|
|
56
|
-
|
|
57
|
-
@abstractmethod
|
|
58
|
-
def _QC(self, df: DataFrame):
|
|
59
|
-
return df
|
|
60
|
-
|
|
61
59
|
def __call__(self,
|
|
62
60
|
start: dtm | None = None,
|
|
63
61
|
end: dtm | None = None,
|
|
64
62
|
mean_freq: str = '1h',
|
|
65
63
|
csv_out: bool = True,
|
|
66
|
-
) -> DataFrame
|
|
64
|
+
) -> DataFrame:
|
|
67
65
|
|
|
68
66
|
if start and end and end <= start:
|
|
69
67
|
raise ValueError(f"Invalid time range: start {start} is after end {end}")
|
|
@@ -78,6 +76,14 @@ class AbstractReader(ABC):
|
|
|
78
76
|
|
|
79
77
|
return data
|
|
80
78
|
|
|
79
|
+
@abstractmethod
|
|
80
|
+
def _raw_reader(self, file):
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
@abstractmethod
|
|
84
|
+
def _QC(self, df: DataFrame):
|
|
85
|
+
return df
|
|
86
|
+
|
|
81
87
|
@staticmethod
|
|
82
88
|
def basic_QC(df: DataFrame):
|
|
83
89
|
df_ave, df_std = df.mean(), df.std()
|
|
@@ -85,40 +91,25 @@ class AbstractReader(ABC):
|
|
|
85
91
|
|
|
86
92
|
return df.mask(df_lowb | df_highb).copy()
|
|
87
93
|
|
|
88
|
-
# set each to true datetime(18:30:01 -> 18:30:00) and rindex data
|
|
89
|
-
def _raw_process(self, _df):
|
|
90
|
-
# get time from df and set time to whole time to create time index
|
|
91
|
-
_st, _ed = _df.index.sort_values()[[0, -1]]
|
|
92
|
-
_tm_index = date_range(_st.strftime('%Y%m%d %H00'), _ed.floor('h').strftime('%Y%m%d %H00'),
|
|
93
|
-
freq=self.meta['freq'])
|
|
94
|
-
_tm_index.name = 'time'
|
|
95
|
-
|
|
96
|
-
return _df.apply(to_numeric, errors='coerce').resample(self.meta['freq']).mean().reindex(_tm_index)
|
|
97
|
-
|
|
98
94
|
def _setup_logger(self) -> logging.Logger:
|
|
99
95
|
logger = logging.getLogger(self.nam)
|
|
100
96
|
logger.setLevel(logging.INFO)
|
|
97
|
+
|
|
98
|
+
for handler in logger.handlers[:]:
|
|
99
|
+
logger.removeHandler(handler)
|
|
100
|
+
|
|
101
101
|
handler = logging.FileHandler(self.path / f'{self.nam}.log')
|
|
102
102
|
handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s'))
|
|
103
103
|
logger.addHandler(handler)
|
|
104
104
|
return logger
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
def _rate_calculate(self, _fout_raw, _fout_qc, _st_raw, _ed_raw):
|
|
106
|
+
def _rate_calculate(self, _fout_raw, _fout_qc, _st_raw, _ed_raw) -> None:
|
|
108
107
|
if self.meta['deter_key'] is not None:
|
|
109
108
|
_start, _end = _fout_qc.index[[0, -1]]
|
|
110
109
|
|
|
111
110
|
_drop_how = 'any'
|
|
112
111
|
_the_size = len(_fout_raw.resample('1h').mean().index)
|
|
113
112
|
|
|
114
|
-
self.logger.info(f"{'=' * 60}")
|
|
115
|
-
self.logger.info(
|
|
116
|
-
f"Raw data time : {_st_raw.strftime('%Y-%m-%d %H:%M:%S')} to {_ed_raw.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
117
|
-
self.logger.info(
|
|
118
|
-
f"Output time : {_start.strftime('%Y-%m-%d %H:%M:%S')} to {_end.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
119
|
-
self.logger.info(f"{'-' * 60}")
|
|
120
|
-
print(f"\n\n\t\tfrom {_start.strftime('%Y-%m-%d %H:%M:%S')} to {_end.strftime('%Y-%m-%d %H:%M:%S')}\n")
|
|
121
|
-
|
|
122
113
|
for _nam, _key in self.meta['deter_key'].items():
|
|
123
114
|
if _key == ['all']:
|
|
124
115
|
_key, _drop_how = _fout_qc.keys(), 'all'
|
|
@@ -137,9 +128,19 @@ class AbstractReader(ABC):
|
|
|
137
128
|
self.logger.info(f'\tYield rate: {_yid_rate}%')
|
|
138
129
|
self.logger.info(f"{'=' * 60}")
|
|
139
130
|
|
|
140
|
-
print(f'\
|
|
141
|
-
print(f'\t\
|
|
142
|
-
print(f'\t\
|
|
131
|
+
print(f'\n\t{_nam} : ')
|
|
132
|
+
print(f'\t\tacquisition rate : \033[91m{_acq_rate}%\033[0m')
|
|
133
|
+
print(f'\t\tyield rate : \033[91m{_yid_rate}%\033[0m')
|
|
134
|
+
|
|
135
|
+
# set each to true datetime(18:30:01 -> 18:30:00) and rindex data
|
|
136
|
+
def _raw_process(self, _df):
|
|
137
|
+
# get time from df and set time to whole time to create time index
|
|
138
|
+
_st, _ed = _df.index.sort_values()[[0, -1]]
|
|
139
|
+
_tm_index = date_range(_st.strftime('%Y%m%d %H00'), _ed.floor('h').strftime('%Y%m%d %H00'),
|
|
140
|
+
freq=self.meta['freq'])
|
|
141
|
+
_tm_index.name = 'time'
|
|
142
|
+
|
|
143
|
+
return _df.apply(to_numeric, errors='coerce').resample(self.meta['freq']).mean().reindex(_tm_index)
|
|
143
144
|
|
|
144
145
|
# process time index
|
|
145
146
|
@staticmethod
|
|
@@ -153,7 +154,7 @@ class AbstractReader(ABC):
|
|
|
153
154
|
|
|
154
155
|
# append new data to exist pkl
|
|
155
156
|
@staticmethod
|
|
156
|
-
def
|
|
157
|
+
def _append_process(_df_done, _df_apnd):
|
|
157
158
|
|
|
158
159
|
if _df_apnd is not None:
|
|
159
160
|
_df = concat([_df_apnd.dropna(how='all').copy(), _df_done.dropna(how='all').copy()])
|
|
@@ -165,16 +166,16 @@ class AbstractReader(ABC):
|
|
|
165
166
|
|
|
166
167
|
return _df_done
|
|
167
168
|
|
|
168
|
-
|
|
169
|
-
|
|
169
|
+
def _outlier_process(self, _df):
|
|
170
|
+
outlier_file = self.path / 'outlier.json'
|
|
170
171
|
|
|
171
|
-
if
|
|
172
|
+
if not outlier_file.exists():
|
|
172
173
|
return _df
|
|
173
174
|
|
|
174
|
-
with
|
|
175
|
-
|
|
175
|
+
with outlier_file.open('r', encoding='utf-8', errors='ignore') as f:
|
|
176
|
+
outliers = json.load(f)
|
|
176
177
|
|
|
177
|
-
for _st, _ed in
|
|
178
|
+
for _st, _ed in outliers.values():
|
|
178
179
|
_df.loc[_st:_ed] = np.nan
|
|
179
180
|
|
|
180
181
|
return _df
|
|
@@ -192,14 +193,13 @@ class AbstractReader(ABC):
|
|
|
192
193
|
|
|
193
194
|
@staticmethod
|
|
194
195
|
def _safe_pickle_dump(file_path: Path, data: Any) -> None:
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
input('\t\t\33[41m Please close the file and press "Enter" \33[0m\n')
|
|
196
|
+
try:
|
|
197
|
+
with file_path.open('wb') as f:
|
|
198
|
+
pkl.dump(data, f, protocol=pkl.HIGHEST_PROTOCOL)
|
|
199
|
+
except PermissionError as e:
|
|
200
|
+
raise IOError(f"Unable to write to {file_path}. The file may be in use or you may not have permission: {e}")
|
|
201
|
+
except Exception as e:
|
|
202
|
+
raise IOError(f"Error writing to {file_path}: {e}")
|
|
203
203
|
|
|
204
204
|
# read pickle file
|
|
205
205
|
def _read_pkl(self):
|
|
@@ -207,31 +207,41 @@ class AbstractReader(ABC):
|
|
|
207
207
|
return pkl.load(raw_data), pkl.load(qc_data)
|
|
208
208
|
|
|
209
209
|
def _read_raw_files(self) -> tuple[DataFrame | None, DataFrame | None]:
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
files = [f
|
|
211
|
+
for file_pattern in self.meta['pattern']
|
|
212
|
+
for pattern in {file_pattern.lower(), file_pattern.upper(), file_pattern}
|
|
213
|
+
for f in self.path.glob(pattern)
|
|
212
214
|
if f.name not in [self.csv_out.name, self.csv_nam.name, self.csv_nam_raw.name, f'{self.nam}.log']]
|
|
213
215
|
|
|
214
216
|
if not files:
|
|
215
|
-
raise FileNotFoundError(f"
|
|
216
|
-
f"Please check the current path.\033[0m")
|
|
217
|
+
raise FileNotFoundError(f"No files in '{self.path}' could be read. Please check the current path.")
|
|
217
218
|
|
|
218
219
|
df_list = []
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
with Progress(
|
|
221
|
+
TextColumn("[bold blue]{task.description}", style="bold blue"),
|
|
222
|
+
BarColumn(bar_width=18, complete_style="green", finished_style="bright_green"),
|
|
223
|
+
TaskProgressColumn(),
|
|
224
|
+
TimeRemainingColumn(),
|
|
225
|
+
TextColumn("{task.fields[filename]}", style="yellow"),
|
|
226
|
+
console=console,
|
|
227
|
+
expand=False
|
|
228
|
+
) as progress:
|
|
229
|
+
task = progress.add_task(f"Reading {self.nam} files", total=len(files), filename="")
|
|
230
|
+
for file in files:
|
|
231
|
+
progress.update(task, advance=1, filename=file.name)
|
|
232
|
+
try:
|
|
233
|
+
df = self._raw_reader(file)
|
|
224
234
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
235
|
+
if df is not None and not df.empty:
|
|
236
|
+
df_list.append(df)
|
|
237
|
+
else:
|
|
238
|
+
self.logger.warning(f"File {file.name} produced an empty DataFrame or None.")
|
|
229
239
|
|
|
230
|
-
|
|
231
|
-
|
|
240
|
+
except pd.errors.ParserError as e:
|
|
241
|
+
self.logger.error(f"Error tokenizing data: {e}")
|
|
232
242
|
|
|
233
|
-
|
|
234
|
-
|
|
243
|
+
except Exception as e:
|
|
244
|
+
self.logger.error(f"Error reading {file.name}: {e}")
|
|
235
245
|
|
|
236
246
|
if not df_list:
|
|
237
247
|
raise ValueError("All files were either empty or failed to read.")
|
|
@@ -241,47 +251,42 @@ class AbstractReader(ABC):
|
|
|
241
251
|
|
|
242
252
|
return raw_data, qc_data
|
|
243
253
|
|
|
244
|
-
# main flow
|
|
245
254
|
def _run(self, _start, _end):
|
|
246
|
-
_f_raw_done, _f_qc_done = None, None
|
|
247
|
-
|
|
248
255
|
# read pickle if pickle file exists and 'reset=False' or process raw data or append new data
|
|
249
|
-
if self.pkl_nam_raw.exists() and self.pkl_nam.exists() and
|
|
250
|
-
print(f"\n
|
|
256
|
+
if self.pkl_nam_raw.exists() and self.pkl_nam.exists() and not self.reset:
|
|
257
|
+
print(f"\n{dtm.now().strftime('%m/%d %X')} : Reading {self.nam} \033[96mPICKLE\033[0m "
|
|
258
|
+
f"from {_start} to {_end}\n")
|
|
251
259
|
|
|
252
260
|
_f_raw_done, _f_qc_done = self._read_pkl()
|
|
253
261
|
|
|
254
|
-
if
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
self._rate_calculate(_f_raw_done, _f_qc_done, _start_raw, _end_raw)
|
|
262
|
-
|
|
263
|
-
return _f_qc_done if self.qc else _f_raw_done
|
|
262
|
+
if self.append:
|
|
263
|
+
print(f"Appending new data from {_start} to {_end}")
|
|
264
|
+
_f_raw_new, _f_qc_new = self._read_raw_files()
|
|
265
|
+
_f_raw = self._append_process(_f_raw_done, _f_raw_new)
|
|
266
|
+
_f_qc = self._append_process(_f_qc_done, _f_qc_new)
|
|
267
|
+
else:
|
|
268
|
+
_f_raw, _f_qc = _f_raw_done, _f_qc_done
|
|
264
269
|
|
|
265
|
-
|
|
266
|
-
|
|
270
|
+
else:
|
|
271
|
+
print(f"\n{dtm.now().strftime('%m/%d %X')} : Reading {self.nam} \033[96mRAW DATA\033[0m "
|
|
272
|
+
f"from {_start} to {_end}\n")
|
|
273
|
+
_f_raw, _f_qc = self._read_raw_files()
|
|
267
274
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if self.append and self.pkl_nam.exists():
|
|
272
|
-
_f_raw = self._apnd_prcs(_f_raw_done, _f_raw)
|
|
273
|
-
_f_qc = self._apnd_prcs(_f_qc_done, _f_qc)
|
|
275
|
+
# process time index
|
|
276
|
+
_f_raw, _start_raw, _end_raw = self._tmidx_process(_start, _end, _f_raw)
|
|
277
|
+
_f_qc, _start_raw, _end_raw = self._tmidx_process(_start, _end, _f_qc)
|
|
274
278
|
|
|
275
|
-
_f_qc = self.
|
|
279
|
+
_f_qc = self._outlier_process(_f_qc)
|
|
276
280
|
|
|
277
281
|
# save
|
|
278
282
|
self._save_data(_f_raw, _f_qc)
|
|
279
283
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
+
self.logger.info(f"{'=' * 60}")
|
|
285
|
+
self.logger.info(f"Raw data time : {_start_raw} to {_end_raw}")
|
|
286
|
+
self.logger.info(f"Output time : {_start} to {_end}")
|
|
287
|
+
self.logger.info(f"{'-' * 60}")
|
|
284
288
|
|
|
285
|
-
self.
|
|
289
|
+
if self.rate:
|
|
290
|
+
self._rate_calculate(_f_raw, _f_qc, _start_raw, _end_raw)
|
|
286
291
|
|
|
287
292
|
return _f_qc if self.qc else _f_raw
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import numpy as
|
|
1
|
+
import numpy as np
|
|
2
2
|
from pandas import to_datetime, read_table
|
|
3
3
|
|
|
4
4
|
from AeroViz.rawDataReader.core import AbstractReader
|
|
@@ -29,7 +29,7 @@ class Reader(AbstractReader):
|
|
|
29
29
|
# QC data
|
|
30
30
|
def _QC(self, _df):
|
|
31
31
|
# mask out the data size lower than 7
|
|
32
|
-
_df['total'] = _df.sum(axis=1, min_count=1) * (
|
|
32
|
+
_df['total'] = _df.sum(axis=1, min_count=1) * (np.diff(np.log(_df.keys().to_numpy(float)))).mean()
|
|
33
33
|
_df_size = _df['total'].dropna().resample('1h').size().resample(_df.index.freq).ffill()
|
|
34
34
|
_df = _df.mask(_df_size < 7)
|
|
35
35
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from pandas import to_datetime, to_numeric, read_csv, isna
|
|
5
|
+
|
|
6
|
+
from AeroViz.rawDataReader.core import AbstractReader
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def find_header_row(file_obj, delimiter):
|
|
10
|
+
csv_reader = csv.reader(file_obj, delimiter=delimiter)
|
|
11
|
+
for skip, row in enumerate(csv_reader):
|
|
12
|
+
if row and (row[0] in ['Sample #', 'Scan Number']):
|
|
13
|
+
return skip
|
|
14
|
+
raise ValueError("Header row not found")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def parse_date(df, date_format):
|
|
18
|
+
if 'Date' in df.columns and 'Start Time' in df.columns:
|
|
19
|
+
return to_datetime(df['Date'] + ' ' + df['Start Time'], format=date_format, errors='coerce')
|
|
20
|
+
elif 'DateTime Sample Start' in df.columns:
|
|
21
|
+
return to_datetime(df['DateTime Sample Start'], format=date_format, errors='coerce')
|
|
22
|
+
else:
|
|
23
|
+
raise ValueError("Expected date columns not found")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Reader(AbstractReader):
|
|
27
|
+
nam = 'SMPS'
|
|
28
|
+
|
|
29
|
+
def _raw_reader(self, file):
|
|
30
|
+
with open(file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
31
|
+
if file.suffix.lower() == '.txt':
|
|
32
|
+
delimiter, date_formats = '\t', ['%m/%d/%y %X', '%m/%d/%Y %X']
|
|
33
|
+
else: # csv
|
|
34
|
+
delimiter, date_formats = ',', ['%d/%m/%Y %X']
|
|
35
|
+
|
|
36
|
+
skip = find_header_row(f, delimiter)
|
|
37
|
+
f.seek(0)
|
|
38
|
+
|
|
39
|
+
_df = read_csv(f, sep=delimiter, skiprows=skip)
|
|
40
|
+
|
|
41
|
+
for date_format in date_formats:
|
|
42
|
+
_time_index = parse_date(_df, date_format)
|
|
43
|
+
if not isna(_time_index).all():
|
|
44
|
+
break
|
|
45
|
+
else:
|
|
46
|
+
raise ValueError("Unable to parse dates with given formats")
|
|
47
|
+
|
|
48
|
+
# sequence the data
|
|
49
|
+
numeric_cols = [col for col in _df.columns if col.strip().replace('.', '').isdigit()]
|
|
50
|
+
numeric_cols.sort(key=lambda x: float(x.strip()))
|
|
51
|
+
|
|
52
|
+
_df.index = _time_index
|
|
53
|
+
_df.index.name = 'time'
|
|
54
|
+
|
|
55
|
+
_df_smps = _df[numeric_cols]
|
|
56
|
+
_df_smps.columns = _df_smps.columns.astype(float)
|
|
57
|
+
|
|
58
|
+
return _df_smps.apply(to_numeric, errors='coerce')
|
|
59
|
+
|
|
60
|
+
# QC data
|
|
61
|
+
def _QC(self, _df):
|
|
62
|
+
|
|
63
|
+
# mask out the data size lower than 7
|
|
64
|
+
_df['total'] = _df.sum(axis=1, min_count=1) * (np.diff(np.log(_df.keys().to_numpy(float)))).mean()
|
|
65
|
+
_df_size = _df['total'].dropna().resample('1h').size().resample(_df.index.freq).ffill()
|
|
66
|
+
_df = _df.mask(_df_size < 7)
|
|
67
|
+
|
|
68
|
+
# remove total conc. lower than 2000
|
|
69
|
+
_df = _df.mask(_df['total'] < 2000)
|
|
70
|
+
|
|
71
|
+
# remove the bin over 400 nm which num. conc. larger than 4000
|
|
72
|
+
_df_remv_ky = _df.keys()[:-2][_df.keys()[:-2] >= 400.]
|
|
73
|
+
|
|
74
|
+
_df[_df_remv_ky] = _df[_df_remv_ky].copy().mask(_df[_df_remv_ky] > 4000.)
|
|
75
|
+
|
|
76
|
+
return _df[_df.keys()[:-1]]
|
|
@@ -20,8 +20,8 @@ class Reader(AbstractReader):
|
|
|
20
20
|
|
|
21
21
|
if invalid_keys:
|
|
22
22
|
self.logger.warning(f'{invalid_keys} are not supported keys.')
|
|
23
|
-
print(f'\n\t
|
|
24
|
-
f'\n\
|
|
23
|
+
print(f'\n\t{invalid_keys} are not supported keys.'
|
|
24
|
+
f'\n\tPlease check the\033[91m support_voc.md\033[0m file to use the correct name.')
|
|
25
25
|
|
|
26
26
|
if valid_keys:
|
|
27
27
|
return _df[valid_keys].loc[~_df.index.duplicated() & _df.index.notna()]
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
__all__ = [
|
|
2
2
|
'NEPH',
|
|
3
3
|
'Aurora',
|
|
4
|
-
'
|
|
5
|
-
'SMPS_genr',
|
|
6
|
-
'SMPS_aim11',
|
|
4
|
+
'SMPS',
|
|
7
5
|
'APS_3321',
|
|
8
6
|
'GRIMM',
|
|
9
7
|
'AE33',
|
|
@@ -11,7 +9,7 @@ __all__ = [
|
|
|
11
9
|
'BC1054',
|
|
12
10
|
'MA350',
|
|
13
11
|
'TEOM',
|
|
14
|
-
'
|
|
12
|
+
'OCEC',
|
|
15
13
|
'IGAC',
|
|
16
14
|
'VOC',
|
|
17
15
|
'Table',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: AeroViz
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: Aerosol science
|
|
5
5
|
Home-page: https://github.com/Alex870521/AeroViz
|
|
6
6
|
Author: alex
|
|
@@ -11,14 +11,15 @@ Classifier: Operating System :: OS Independent
|
|
|
11
11
|
Requires-Python: >=3.12
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: pandas
|
|
15
|
-
Requires-Dist: numpy
|
|
16
|
-
Requires-Dist: matplotlib
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist:
|
|
19
|
-
Requires-Dist: scikit-learn
|
|
20
|
-
Requires-Dist: windrose
|
|
21
|
-
Requires-Dist: tabulate
|
|
14
|
+
Requires-Dist: pandas ==2.2.2
|
|
15
|
+
Requires-Dist: numpy ==1.26.4
|
|
16
|
+
Requires-Dist: matplotlib ==3.8.4
|
|
17
|
+
Requires-Dist: scipy ==1.14.0
|
|
18
|
+
Requires-Dist: seaborn ==0.13.2
|
|
19
|
+
Requires-Dist: scikit-learn ==1.5.1
|
|
20
|
+
Requires-Dist: windrose ==1.9.2
|
|
21
|
+
Requires-Dist: tabulate ==0.9.0
|
|
22
|
+
Requires-Dist: rich ~=13.7.1
|
|
22
23
|
|
|
23
24
|
## <div align="center">AeroViz for Aerosol Science Visualization</div>
|
|
24
25
|
|
|
@@ -52,13 +53,15 @@ Requires-Dist: tabulate
|
|
|
52
53
|
## <div align="center">Installation</div>
|
|
53
54
|
|
|
54
55
|
```bash
|
|
55
|
-
pip install AeroViz
|
|
56
|
+
pip install AeroViz
|
|
56
57
|
```
|
|
57
58
|
|
|
58
59
|
## <div align="center">Usage</div>
|
|
59
60
|
|
|
60
61
|
```python
|
|
61
62
|
import AeroViz
|
|
63
|
+
|
|
64
|
+
from AeroViz import RawDataReader, DataProcess, plot
|
|
62
65
|
```
|
|
63
66
|
|
|
64
67
|
## <div align="center">RawDataReader Supported Instruments</div>
|
|
@@ -5,14 +5,14 @@ AeroViz/dataProcess/__init__.py,sha256=D3rTVUiGfs_daGuaotVtbijOgLAp6HaRWchj-zoEn
|
|
|
5
5
|
AeroViz/dataProcess/Chemistry/__init__.py,sha256=fyyomjxkQcUNWDx4R5jPrHafAftN-v2liUZii9OlaiU,2058
|
|
6
6
|
AeroViz/dataProcess/Chemistry/_calculate.py,sha256=q7ojTFPok0vg8k_1PMECNdP5CPanR9NWQ4Rx5iTcHew,599
|
|
7
7
|
AeroViz/dataProcess/Chemistry/_isoropia.py,sha256=3wp_FXdN230awlStMbctutwld4oot9WaAVXETGd6PSs,3255
|
|
8
|
-
AeroViz/dataProcess/Chemistry/_mass_volume.py,sha256=
|
|
8
|
+
AeroViz/dataProcess/Chemistry/_mass_volume.py,sha256=0joH2BAx0NUwDFzyrLgG-v7WrGl46R7zWxwbajWBV8o,5378
|
|
9
9
|
AeroViz/dataProcess/Chemistry/_ocec.py,sha256=gqDTs9rOyr0RXdN1Nrxv6Vgvh04IFgHwk4gAJUgZZGc,5437
|
|
10
10
|
AeroViz/dataProcess/Chemistry/_partition.py,sha256=tKhb6BJns46UiUlEq6Zq7ahYnvUJ_whY3tWE54C3bqU,1023
|
|
11
11
|
AeroViz/dataProcess/Chemistry/_teom.py,sha256=IiM-TrifWpQLTbKllG-4k4c3mvQulfcmjswWu6muCXA,486
|
|
12
12
|
AeroViz/dataProcess/Chemistry/isrpia.cnf,sha256=iWXTqsOZFmNrJxAI9nYuilZ9h6ru1icdPFVim7YKc_k,566
|
|
13
13
|
AeroViz/dataProcess/Chemistry/isrpia2.exe,sha256=xFYPTXHSjl_-atmVcTmqqOkTZgUn1p8h-kFMcoGMIQw,1560032
|
|
14
14
|
AeroViz/dataProcess/Optical/Angstrom_exponent.py,sha256=KSGM_hf2oUPsLoLuhYSRDK5zdekwce9KgqhzRnf2Y4g,706
|
|
15
|
-
AeroViz/dataProcess/Optical/_IMPROVE.py,sha256=
|
|
15
|
+
AeroViz/dataProcess/Optical/_IMPROVE.py,sha256=n3uHUQTivckIrNlbE8rP7lPZGcMWZUAnS_qX8pXd55Q,1670
|
|
16
16
|
AeroViz/dataProcess/Optical/__init__.py,sha256=h_IYhaum0DhK7Qw6lWFvjAEv7uAqLVVPEwU0V4hJnX4,1371
|
|
17
17
|
AeroViz/dataProcess/Optical/_absorption.py,sha256=pYHIoj_R23wKvxR4acUqqU9JXKY40wgsFvZH78rETrY,1234
|
|
18
18
|
AeroViz/dataProcess/Optical/_extinction.py,sha256=anUemSXmLvJi2CSxqTYgQCgUW4pSUqgZ0q0xZ4zs0zY,1189
|
|
@@ -20,7 +20,7 @@ AeroViz/dataProcess/Optical/_mie.py,sha256=K_I8NqRStCdExRVxq2rX5hQdvYmfKuu9JCkNt
|
|
|
20
20
|
AeroViz/dataProcess/Optical/_mie_sd.py,sha256=cbWSorfG-l92csaXsZJ7005f8ij2H_VZopIhNPCwx70,4812
|
|
21
21
|
AeroViz/dataProcess/Optical/_scattering.py,sha256=w5xXXOfafV9a_dXY60YqTyzFDZppjBJeLcKl5PeCQe4,961
|
|
22
22
|
AeroViz/dataProcess/Optical/fRH.pkl,sha256=PhJ-BYTaUDjl2Lp5Wz0zeiLQCzrsNdq8nP7Jd1BXyXE,4528
|
|
23
|
-
AeroViz/dataProcess/SizeDistr/__init__.py,sha256=
|
|
23
|
+
AeroViz/dataProcess/SizeDistr/__init__.py,sha256=fka1IJW4wZzYWE9HjWi8i03ab0JLFXOUdaHWYs4VHEQ,2172
|
|
24
24
|
AeroViz/dataProcess/SizeDistr/__merge.py,sha256=A-ZmduUA9a0nVM8szhG1AWhsfUPu2UhGIaqFLcmg7Lk,9422
|
|
25
25
|
AeroViz/dataProcess/SizeDistr/_merge.py,sha256=CyZwUc2M4lL-OE74e8mXq41nC6X0LJTAV8TwpO3fS2o,9176
|
|
26
26
|
AeroViz/dataProcess/SizeDistr/_merge_v1.py,sha256=6Anb8DszoatK66tc9ccA6ZApbqtL7pZRPR5TKHj-Tbs,9526
|
|
@@ -79,13 +79,13 @@ AeroViz/process/script/PSD.py,sha256=unSvyHp1RqgQecY-Lab-wRFGP2u45blSO4NCNTaxcRQ
|
|
|
79
79
|
AeroViz/process/script/PSD_dry.py,sha256=P9rSQVA78jHXrY2bDiC1iQvG0w9Js8QiBNfooPOXzfY,3269
|
|
80
80
|
AeroViz/process/script/__init__.py,sha256=QExUHHK79oiwZXvk8u00P8rLwWhGOc1fpZY2Fx8Vkxg,188
|
|
81
81
|
AeroViz/process/script/retrieve_RI.py,sha256=9OQJU1w6VzVqKz00e9GdWswRAnaETe_1meAHp5N_s54,2711
|
|
82
|
-
AeroViz/rawDataReader/__init__.py,sha256=
|
|
82
|
+
AeroViz/rawDataReader/__init__.py,sha256=jXLrf0A-Hxufw-IQp0-Nyci4PszWk5YU4SnpH4ob1RE,3862
|
|
83
83
|
AeroViz/rawDataReader/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
84
|
-
AeroViz/rawDataReader/config/supported_instruments.py,sha256=
|
|
85
|
-
AeroViz/rawDataReader/core/__init__.py,sha256=
|
|
84
|
+
AeroViz/rawDataReader/config/supported_instruments.py,sha256=iE2dqnAhXsHUeVfho5vYYcXL97fg_xt3VvvYcyxCU48,4408
|
|
85
|
+
AeroViz/rawDataReader/core/__init__.py,sha256=W_RwJZmMCTjTwWiTSxcXFhkasO3cyQWEPSdA7-ymeqU,11058
|
|
86
86
|
AeroViz/rawDataReader/script/AE33.py,sha256=Nv0u0w_V50sDjsLh17ZkNT6A75TjIo2A1O6GYc4zkJg,1107
|
|
87
87
|
AeroViz/rawDataReader/script/AE43.py,sha256=Qq9MdiBKzDuKIEFPanmn7wUbkN5VeSTG6Dopw8i0W90,1056
|
|
88
|
-
AeroViz/rawDataReader/script/APS_3321.py,sha256=
|
|
88
|
+
AeroViz/rawDataReader/script/APS_3321.py,sha256=x75G72Xl0vElr6Njbv8SlOcosAHNozseaJzAxVmfXyI,1697
|
|
89
89
|
AeroViz/rawDataReader/script/Aurora.py,sha256=b0XPs2gc_2UJj4HnOHwW7o255zsCPp459goaDqeAJA8,1387
|
|
90
90
|
AeroViz/rawDataReader/script/BC1054.py,sha256=QGU1SRDoE8e4yNXUX7RsdK5zh72fNd2Q0IpUy7iFzrg,1486
|
|
91
91
|
AeroViz/rawDataReader/script/EPA_vertical.py,sha256=MpcbOzbigivsuldCxzn_B6POtQMzahGQhM_sWRDVP9s,1669
|
|
@@ -94,21 +94,19 @@ AeroViz/rawDataReader/script/IGAC.py,sha256=BDhmsNy02EvLY0sd75NM6XvLGVTEJlxyQQbp
|
|
|
94
94
|
AeroViz/rawDataReader/script/MA350.py,sha256=YRY19R2V6nyHMpGMOLVZvK8_41OCCzdTcSnuZR-OJsU,1287
|
|
95
95
|
AeroViz/rawDataReader/script/Minion.py,sha256=c128ZkkxakV6wq1k9NtEq0scdi1mh9Mn0jhQFqz_uVE,3940
|
|
96
96
|
AeroViz/rawDataReader/script/NEPH.py,sha256=OSDtbJ4sujtnf3bzbENXoyJwA-RIeOkPXNCEJ6MvkPQ,2735
|
|
97
|
-
AeroViz/rawDataReader/script/
|
|
98
|
-
AeroViz/rawDataReader/script/
|
|
99
|
-
AeroViz/rawDataReader/script/SMPS_genr.py,sha256=rR5OO63ozDKMcGBfNFPi_f49gUbx2qYx60GMSgC9jwg,1609
|
|
100
|
-
AeroViz/rawDataReader/script/Sunset_OCEC.py,sha256=6TyosCQ4N6jB9yZOfAJHwiIvkTYCwCThmMbhe4_U9a0,2322
|
|
97
|
+
AeroViz/rawDataReader/script/OCEC.py,sha256=t3N_bs5RishlfzFqxTSfMlemZBDIco6cKZ4mU0j9_6g,2315
|
|
98
|
+
AeroViz/rawDataReader/script/SMPS.py,sha256=RnqysTWNaFautGnyPKZgMjdtPdauv9Mqu9IpuTEGpXs,2706
|
|
101
99
|
AeroViz/rawDataReader/script/TEOM.py,sha256=Hx_DDnvGSfSl9cgIVmuf4VmphaFfNCY60mqPWoLmNvw,1796
|
|
102
100
|
AeroViz/rawDataReader/script/Table.py,sha256=othBoQSFVcjfWX0_Q4y8BkjCBc5CihvC6LyrhyJWywk,800
|
|
103
|
-
AeroViz/rawDataReader/script/VOC.py,sha256=
|
|
104
|
-
AeroViz/rawDataReader/script/__init__.py,sha256=
|
|
101
|
+
AeroViz/rawDataReader/script/VOC.py,sha256=sUn3ba_iYQ8Uy8qKNI-6qb1YvHsKN4G6BosBnLLMctc,1269
|
|
102
|
+
AeroViz/rawDataReader/script/__init__.py,sha256=EXLjVwKN-wr3pMi-ILjiPH86ojwfoIif5vG2Q__DGZc,225
|
|
105
103
|
AeroViz/tools/__init__.py,sha256=tPUmCI9Fi1LgE-QSVnzan5jRdYQBIENH9PRDXB_DhTw,109
|
|
106
104
|
AeroViz/tools/database.py,sha256=05VzjJyhlRrhsZdhfFQ__7CxGm4MdFekLjz3_Is5h9U,3430
|
|
107
105
|
AeroViz/tools/dataclassifier.py,sha256=_wpv0PlZ5EGkcNqHxfFtdEsYvHP5FVE8sMZXikhm_YE,4492
|
|
108
106
|
AeroViz/tools/dataprinter.py,sha256=Jq2Yztpa9YCOeLDVTrRs7PhSdNIPhEAexVj1YSuJ7hY,2249
|
|
109
107
|
AeroViz/tools/datareader.py,sha256=iTQ0U8hdNMjCdbiH7EiKW10UEoxzxXRHc4s5_1IikJo,1933
|
|
110
|
-
AeroViz-0.1.
|
|
111
|
-
AeroViz-0.1.
|
|
112
|
-
AeroViz-0.1.
|
|
113
|
-
AeroViz-0.1.
|
|
114
|
-
AeroViz-0.1.
|
|
108
|
+
AeroViz-0.1.6.dist-info/LICENSE,sha256=E-679GpGGkp3irmtuJXiT7R4cNUA4cmsH6Q7QUgPf5U,1069
|
|
109
|
+
AeroViz-0.1.6.dist-info/METADATA,sha256=Fp-P1AKOfLLX0c46uZms4TfEQ5ImonxFHThq5oHFs4c,5434
|
|
110
|
+
AeroViz-0.1.6.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
|
111
|
+
AeroViz-0.1.6.dist-info/top_level.txt,sha256=BYsmTst_o4FZOKRP1XIvIMlN6mMTTXNfnSToL2_nVbQ,8
|
|
112
|
+
AeroViz-0.1.6.dist-info/RECORD,,
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
from pandas import to_datetime, read_table
|
|
2
|
-
|
|
3
|
-
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Reader(AbstractReader):
|
|
7
|
-
nam = 'SMPS_TH'
|
|
8
|
-
|
|
9
|
-
def _raw_reader(self, file):
|
|
10
|
-
with open(file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
11
|
-
_df = read_table(f, skiprows=18, parse_dates={'Time': ['Date', 'Start Time']}).set_index('Time')
|
|
12
|
-
_key = list(_df.keys()[6:-26])
|
|
13
|
-
|
|
14
|
-
_newkey = {}
|
|
15
|
-
for _k in _key:
|
|
16
|
-
_newkey[_k] = float(_k).__round__(4)
|
|
17
|
-
|
|
18
|
-
# _newkey['Total Conc.(#/cm)'] = 'total'
|
|
19
|
-
# _newkey['Mode(nm)'] = 'mode'
|
|
20
|
-
|
|
21
|
-
_df_idx = to_datetime(_df.index, errors='coerce')
|
|
22
|
-
return _df[_newkey.keys()].rename(_newkey, axis=1).set_index(_df_idx).loc[_df_idx.dropna()]
|
|
23
|
-
|
|
24
|
-
# QC data
|
|
25
|
-
def _QC(self, _df):
|
|
26
|
-
import numpy as n
|
|
27
|
-
|
|
28
|
-
# mask out the data size lower than 7
|
|
29
|
-
_df['total'] = _df.sum(axis=1, min_count=1) * (n.diff(n.log(_df.keys().to_numpy(float)))).mean()
|
|
30
|
-
_df_size = _df['total'].dropna().resample('1h').size().resample(_df.index.freq).ffill()
|
|
31
|
-
_df = _df.mask(_df_size < 7)
|
|
32
|
-
|
|
33
|
-
# remove total conc. lower than 2000
|
|
34
|
-
_df = _df.mask(_df['total'] < 2000)
|
|
35
|
-
|
|
36
|
-
# remove the bin over 400 nm which num. conc. larger than 4000
|
|
37
|
-
_df_remv_ky = _df.keys()[:-2][_df.keys()[:-2] >= 400.]
|
|
38
|
-
|
|
39
|
-
_df[_df_remv_ky] = _df[_df_remv_ky].copy().mask(_df[_df_remv_ky] > 4000.)
|
|
40
|
-
|
|
41
|
-
return _df[_df.keys()[:-1]]
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
from pandas import to_datetime, read_csv, to_numeric
|
|
2
|
-
|
|
3
|
-
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Reader(AbstractReader):
|
|
7
|
-
nam = 'SMPS_aim11'
|
|
8
|
-
|
|
9
|
-
def _raw_reader(self, file):
|
|
10
|
-
with open(file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
11
|
-
|
|
12
|
-
skiprows = 0
|
|
13
|
-
for _line in f:
|
|
14
|
-
|
|
15
|
-
if _line.split(',')[0] == 'Scan Number':
|
|
16
|
-
f.seek(0)
|
|
17
|
-
break
|
|
18
|
-
|
|
19
|
-
skiprows += 1
|
|
20
|
-
# breakpoint()
|
|
21
|
-
_df = read_csv(f, skiprows=skiprows)
|
|
22
|
-
_tm_idx = to_datetime(_df['DateTime Sample Start'], format='%d/%m/%Y %X', errors='coerce')
|
|
23
|
-
|
|
24
|
-
# index
|
|
25
|
-
_df = _df.set_index(_tm_idx).loc[_tm_idx.dropna()]
|
|
26
|
-
|
|
27
|
-
# keys
|
|
28
|
-
_key = to_numeric(_df.keys(), errors='coerce')
|
|
29
|
-
_df.columns = _key
|
|
30
|
-
_df = _df.loc[:, ~_key.isna()]
|
|
31
|
-
|
|
32
|
-
return _df.apply(to_numeric, errors='coerce')
|
|
33
|
-
|
|
34
|
-
# QC data
|
|
35
|
-
def _QC(self, _df):
|
|
36
|
-
import numpy as n
|
|
37
|
-
|
|
38
|
-
# mask out the data size lower than 7
|
|
39
|
-
_df['total'] = _df.sum(axis=1, min_count=1) * (n.diff(n.log(_df.keys().to_numpy(float)))).mean()
|
|
40
|
-
_df_size = _df['total'].dropna().resample('1h').size().resample(_df.index.freq).ffill()
|
|
41
|
-
_df = _df.mask(_df_size < 7)
|
|
42
|
-
|
|
43
|
-
# remove total conc. lower than 2000
|
|
44
|
-
_df = _df.mask(_df['total'] < 2000)
|
|
45
|
-
|
|
46
|
-
# remove the bin over 400 nm which num. conc. larger than 4000
|
|
47
|
-
_df_remv_ky = _df.keys()[:-2][_df.keys()[:-2] >= 400.]
|
|
48
|
-
|
|
49
|
-
_df[_df_remv_ky] = _df[_df_remv_ky].copy().mask(_df[_df_remv_ky] > 4000.)
|
|
50
|
-
|
|
51
|
-
return _df[_df.keys()[:-1]]
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
from pandas import to_datetime, read_table, to_numeric
|
|
2
|
-
|
|
3
|
-
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Reader(AbstractReader):
|
|
7
|
-
nam = 'SMPS_genr'
|
|
8
|
-
|
|
9
|
-
def _raw_reader(self, file):
|
|
10
|
-
with open(file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
11
|
-
|
|
12
|
-
skiprows = 0
|
|
13
|
-
for _line in f:
|
|
14
|
-
|
|
15
|
-
if _line.split('\t')[0] == 'Sample #':
|
|
16
|
-
f.seek(0)
|
|
17
|
-
break
|
|
18
|
-
|
|
19
|
-
skiprows += 1
|
|
20
|
-
|
|
21
|
-
_df = read_table(f, skiprows=skiprows)
|
|
22
|
-
_tm_idx = to_datetime(_df['Date'] + _df['Start Time'], format='%m/%d/%y%X', errors='coerce')
|
|
23
|
-
|
|
24
|
-
# index
|
|
25
|
-
_df = _df.set_index(_tm_idx).loc[_tm_idx.dropna()]
|
|
26
|
-
|
|
27
|
-
# keys
|
|
28
|
-
_key = to_numeric(_df.keys(), errors='coerce')
|
|
29
|
-
_df.columns = _key
|
|
30
|
-
_df = _df.loc[:, ~_key.isna()]
|
|
31
|
-
|
|
32
|
-
return _df.apply(to_numeric, errors='coerce')
|
|
33
|
-
|
|
34
|
-
# QC data
|
|
35
|
-
def _QC(self, _df):
|
|
36
|
-
import numpy as n
|
|
37
|
-
|
|
38
|
-
# mask out the data size lower than 7
|
|
39
|
-
_df['total'] = _df.sum(axis=1, min_count=1) * (n.diff(n.log(_df.keys().to_numpy(float)))).mean()
|
|
40
|
-
_df_size = _df['total'].dropna().resample('1h').size().resample(_df.index.freq).ffill()
|
|
41
|
-
_df = _df.mask(_df_size < 7)
|
|
42
|
-
|
|
43
|
-
# remove total conc. lower than 2000
|
|
44
|
-
_df = _df.mask(_df['total'] < 2000)
|
|
45
|
-
|
|
46
|
-
# remove the bin over 400 nm which num. conc. larger than 4000
|
|
47
|
-
_df_remv_ky = _df.keys()[:-2][_df.keys()[:-2] >= 400.]
|
|
48
|
-
|
|
49
|
-
_df[_df_remv_ky] = _df[_df_remv_ky].copy().mask(_df[_df_remv_ky] > 4000.)
|
|
50
|
-
|
|
51
|
-
return _df[_df.keys()[:-1]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|