AeroViz 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of AeroViz might be problematic. Click here for more details.
- AeroViz/__init__.py +15 -0
- AeroViz/dataProcess/Chemistry/__init__.py +63 -0
- AeroViz/dataProcess/Chemistry/_calculate.py +27 -0
- AeroViz/dataProcess/Chemistry/_isoropia.py +99 -0
- AeroViz/dataProcess/Chemistry/_mass_volume.py +175 -0
- AeroViz/dataProcess/Chemistry/_ocec.py +184 -0
- AeroViz/dataProcess/Chemistry/_partition.py +29 -0
- AeroViz/dataProcess/Chemistry/_teom.py +16 -0
- AeroViz/dataProcess/Optical/_IMPROVE.py +61 -0
- AeroViz/dataProcess/Optical/__init__.py +62 -0
- AeroViz/dataProcess/Optical/_absorption.py +54 -0
- AeroViz/dataProcess/Optical/_extinction.py +36 -0
- AeroViz/dataProcess/Optical/_mie.py +16 -0
- AeroViz/dataProcess/Optical/_mie_sd.py +143 -0
- AeroViz/dataProcess/Optical/_scattering.py +30 -0
- AeroViz/dataProcess/SizeDistr/__init__.py +61 -0
- AeroViz/dataProcess/SizeDistr/__merge.py +250 -0
- AeroViz/dataProcess/SizeDistr/_merge.py +245 -0
- AeroViz/dataProcess/SizeDistr/_merge_v1.py +254 -0
- AeroViz/dataProcess/SizeDistr/_merge_v2.py +243 -0
- AeroViz/dataProcess/SizeDistr/_merge_v3.py +518 -0
- AeroViz/dataProcess/SizeDistr/_merge_v4.py +424 -0
- AeroViz/dataProcess/SizeDistr/_size_distr.py +93 -0
- AeroViz/dataProcess/VOC/__init__.py +19 -0
- AeroViz/dataProcess/VOC/_potential_par.py +76 -0
- AeroViz/dataProcess/__init__.py +11 -0
- AeroViz/dataProcess/core/__init__.py +92 -0
- AeroViz/plot/__init__.py +7 -0
- AeroViz/plot/distribution/__init__.py +1 -0
- AeroViz/plot/distribution/distribution.py +582 -0
- AeroViz/plot/improve/__init__.py +1 -0
- AeroViz/plot/improve/improve.py +240 -0
- AeroViz/plot/meteorology/__init__.py +1 -0
- AeroViz/plot/meteorology/meteorology.py +317 -0
- AeroViz/plot/optical/__init__.py +2 -0
- AeroViz/plot/optical/aethalometer.py +77 -0
- AeroViz/plot/optical/optical.py +388 -0
- AeroViz/plot/templates/__init__.py +8 -0
- AeroViz/plot/templates/contour.py +47 -0
- AeroViz/plot/templates/corr_matrix.py +108 -0
- AeroViz/plot/templates/diurnal_pattern.py +42 -0
- AeroViz/plot/templates/event_evolution.py +65 -0
- AeroViz/plot/templates/koschmieder.py +156 -0
- AeroViz/plot/templates/metal_heatmap.py +57 -0
- AeroViz/plot/templates/regression.py +256 -0
- AeroViz/plot/templates/scatter.py +130 -0
- AeroViz/plot/templates/templates.py +398 -0
- AeroViz/plot/timeseries/__init__.py +1 -0
- AeroViz/plot/timeseries/timeseries.py +317 -0
- AeroViz/plot/utils/__init__.py +3 -0
- AeroViz/plot/utils/_color.py +71 -0
- AeroViz/plot/utils/_decorator.py +74 -0
- AeroViz/plot/utils/_unit.py +55 -0
- AeroViz/process/__init__.py +31 -0
- AeroViz/process/core/DataProc.py +19 -0
- AeroViz/process/core/SizeDist.py +90 -0
- AeroViz/process/core/__init__.py +4 -0
- AeroViz/process/method/PyMieScatt_update.py +567 -0
- AeroViz/process/method/__init__.py +2 -0
- AeroViz/process/method/mie_theory.py +258 -0
- AeroViz/process/method/prop.py +62 -0
- AeroViz/process/script/AbstractDistCalc.py +143 -0
- AeroViz/process/script/Chemical.py +176 -0
- AeroViz/process/script/IMPACT.py +49 -0
- AeroViz/process/script/IMPROVE.py +161 -0
- AeroViz/process/script/Others.py +65 -0
- AeroViz/process/script/PSD.py +103 -0
- AeroViz/process/script/PSD_dry.py +94 -0
- AeroViz/process/script/__init__.py +5 -0
- AeroViz/process/script/retrieve_RI.py +70 -0
- AeroViz/rawDataReader/__init__.py +68 -0
- AeroViz/rawDataReader/core/__init__.py +397 -0
- AeroViz/rawDataReader/script/AE33.py +31 -0
- AeroViz/rawDataReader/script/AE43.py +34 -0
- AeroViz/rawDataReader/script/APS_3321.py +47 -0
- AeroViz/rawDataReader/script/Aurora.py +38 -0
- AeroViz/rawDataReader/script/BC1054.py +46 -0
- AeroViz/rawDataReader/script/EPA_vertical.py +18 -0
- AeroViz/rawDataReader/script/GRIMM.py +35 -0
- AeroViz/rawDataReader/script/IGAC_TH.py +104 -0
- AeroViz/rawDataReader/script/IGAC_ZM.py +90 -0
- AeroViz/rawDataReader/script/MA350.py +45 -0
- AeroViz/rawDataReader/script/NEPH.py +57 -0
- AeroViz/rawDataReader/script/OCEC_LCRES.py +34 -0
- AeroViz/rawDataReader/script/OCEC_RES.py +28 -0
- AeroViz/rawDataReader/script/SMPS_TH.py +41 -0
- AeroViz/rawDataReader/script/SMPS_aim11.py +51 -0
- AeroViz/rawDataReader/script/SMPS_genr.py +51 -0
- AeroViz/rawDataReader/script/TEOM.py +46 -0
- AeroViz/rawDataReader/script/Table.py +28 -0
- AeroViz/rawDataReader/script/VOC_TH.py +30 -0
- AeroViz/rawDataReader/script/VOC_ZM.py +37 -0
- AeroViz/rawDataReader/script/__init__.py +22 -0
- AeroViz/tools/__init__.py +3 -0
- AeroViz/tools/database.py +94 -0
- AeroViz/tools/dataclassifier.py +117 -0
- AeroViz/tools/datareader.py +66 -0
- AeroViz-0.1.0.dist-info/LICENSE +21 -0
- AeroViz-0.1.0.dist-info/METADATA +117 -0
- AeroViz-0.1.0.dist-info/RECORD +102 -0
- AeroViz-0.1.0.dist-info/WHEEL +5 -0
- AeroViz-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import json as jsn
|
|
2
|
+
import pickle as pkl
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from datetime import datetime as dtm, timedelta as dtmdt
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from pandas import DataFrame, date_range, concat, to_numeric, to_datetime
|
|
9
|
+
|
|
10
|
+
from ..utils.config import meta
|
|
11
|
+
|
|
12
|
+
__all__ = ['AbstractReader']
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AbstractReader(ABC):
|
|
16
|
+
nam = 'AbstractReader'
|
|
17
|
+
|
|
18
|
+
# initial config
|
|
19
|
+
# input : file path, reset switch
|
|
20
|
+
|
|
21
|
+
# list the file in the path and read pickle file if it exists, else read raw data and dump the pickle file the
|
|
22
|
+
# pickle file will be generated after read raw data first time, if you want to re-read the rawdata, please set
|
|
23
|
+
# 'reset=True'
|
|
24
|
+
|
|
25
|
+
def __init__(self, _path, QC=True, csv_raw=True, reset=False, rate=False, append_data=False, update_meta=None):
|
|
26
|
+
# logging.info(f'\n{self.nam}')
|
|
27
|
+
# print('='*65)
|
|
28
|
+
# logger.info(f"Reading file and process data")
|
|
29
|
+
|
|
30
|
+
# class parameter
|
|
31
|
+
# self.index = lambda _freq: date_range(_sta, _fin, freq=_freq)
|
|
32
|
+
self.path = Path(_path)
|
|
33
|
+
self.meta = meta[self.nam]
|
|
34
|
+
|
|
35
|
+
if update_meta is not None:
|
|
36
|
+
self.meta.update(update_meta)
|
|
37
|
+
|
|
38
|
+
self.reset = reset
|
|
39
|
+
self.rate = rate
|
|
40
|
+
self.qc = QC
|
|
41
|
+
self.csv = csv_raw
|
|
42
|
+
self.apnd = append_data & reset
|
|
43
|
+
|
|
44
|
+
self.pkl_nam = f'_read_{self.nam.lower()}.pkl'
|
|
45
|
+
self.csv_nam = f'_read_{self.nam.lower()}.csv'
|
|
46
|
+
|
|
47
|
+
self.pkl_nam_raw = f'_read_{self.nam.lower()}_raw.pkl'
|
|
48
|
+
self.csv_nam_raw = f'_read_{self.nam.lower()}_raw.csv'
|
|
49
|
+
|
|
50
|
+
self.csv_out = f'output_{self.nam.lower()}.csv'
|
|
51
|
+
|
|
52
|
+
# print(f" from {_sta.strftime('%Y-%m-%d %X')} to {_fin.strftime('%Y-%m-%d %X')}")
|
|
53
|
+
# print('='*65)
|
|
54
|
+
# print(f"{dtm.now().strftime('%m/%d %X')}")
|
|
55
|
+
|
|
56
|
+
# get data
|
|
57
|
+
def __call__(self,
|
|
58
|
+
start: dtm | None = None,
|
|
59
|
+
end: dtm | None = None,
|
|
60
|
+
mean_freq='1h',
|
|
61
|
+
csv_out=True,
|
|
62
|
+
**kwarg):
|
|
63
|
+
|
|
64
|
+
self._oth_set = kwarg
|
|
65
|
+
|
|
66
|
+
if start and end and end <= start:
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f'\nPlease check out input time : \n\tstart : {start.strftime("%Y-%m-%d %X")}\n\tend : {end.strftime("%Y-%m-%d %X")}')
|
|
69
|
+
|
|
70
|
+
fout = self._run(start, end)
|
|
71
|
+
|
|
72
|
+
if fout is not None:
|
|
73
|
+
if mean_freq is not None:
|
|
74
|
+
fout = fout.resample(mean_freq).mean()
|
|
75
|
+
|
|
76
|
+
if csv_out:
|
|
77
|
+
fout.to_csv(self.path / self.csv_out)
|
|
78
|
+
|
|
79
|
+
return fout
|
|
80
|
+
|
|
81
|
+
# dependency injection function
|
|
82
|
+
@abstractmethod
|
|
83
|
+
def _raw_reader(self, _file):
|
|
84
|
+
# customize each instrument
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
@abstractmethod
|
|
88
|
+
def _QC(self, df: DataFrame):
|
|
89
|
+
# customize each instrument
|
|
90
|
+
return df
|
|
91
|
+
|
|
92
|
+
# set each to true datetime(18:30:01 -> 18:30:00) and rindex data
|
|
93
|
+
def _raw_process(self, _df):
|
|
94
|
+
# get time from df and set time to whole time to create time index
|
|
95
|
+
_st, _ed = _df.index.sort_values()[[0, -1]]
|
|
96
|
+
_tm_index = date_range(_st.strftime('%Y%m%d %H00'),
|
|
97
|
+
(_ed + dtmdt(hours=1)).strftime('%Y%m%d %H00'),
|
|
98
|
+
freq=self.meta['freq'])
|
|
99
|
+
_tm_index.name = 'time'
|
|
100
|
+
|
|
101
|
+
return _df.apply(to_numeric, errors='coerce').resample(self.meta['freq']).mean().reindex(_tm_index)
|
|
102
|
+
|
|
103
|
+
# acquisition rate and yield rate
|
|
104
|
+
def _rate_calculate(self, _fout_raw, _fout_qc, _st_raw, _ed_raw):
|
|
105
|
+
|
|
106
|
+
if self.meta['deter_key'] is not None:
|
|
107
|
+
_start, _end = _fout_qc.index[[0, -1]]
|
|
108
|
+
|
|
109
|
+
_drop_how = 'any'
|
|
110
|
+
_the_size = len(_fout_raw.resample('1h').mean().index)
|
|
111
|
+
|
|
112
|
+
_f_pth = (self.path / f'{self.nam}.log')
|
|
113
|
+
_f = _f_pth.open('r+' if _f_pth.exists() else 'w+')
|
|
114
|
+
|
|
115
|
+
_cont = _f.read()
|
|
116
|
+
_f.seek(0)
|
|
117
|
+
|
|
118
|
+
_f.write(f"\n{dtm.now().strftime('%Y/%m/%d %X')}\n")
|
|
119
|
+
_f.write(f"{'-' * 60}\n")
|
|
120
|
+
_f.write(f"rawdata time : \n\t{_st_raw.strftime('%Y-%m-%d %X')} ~ {_ed_raw.strftime('%Y-%m-%d %X')}\n")
|
|
121
|
+
_f.write(f"output time : \n\t{_start.strftime('%Y-%m-%d %X')} ~ {_end.strftime('%Y-%m-%d %X')}\n")
|
|
122
|
+
_f.write(f"{'-' * 60}\n")
|
|
123
|
+
print(f"\n\t\tfrom {_start.strftime('%Y-%m-%d %X')} to {_end.strftime('%Y-%m-%d %X')}\n")
|
|
124
|
+
|
|
125
|
+
for _nam, _key in self.meta['deter_key'].items():
|
|
126
|
+
|
|
127
|
+
if _key == ['all']:
|
|
128
|
+
_key, _drop_how = _fout_qc.keys(), 'all'
|
|
129
|
+
|
|
130
|
+
_real_size = len(_fout_raw[_key].resample('1h').mean().copy().dropna(how=_drop_how).index)
|
|
131
|
+
_QC_size = len(_fout_qc[_key].resample('1h').mean().copy().dropna(how=_drop_how).index)
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
_acq_rate = round((_real_size / _the_size) * 100, 1)
|
|
135
|
+
_yid_rate = round((_QC_size / _real_size) * 100, 1)
|
|
136
|
+
except ZeroDivisionError:
|
|
137
|
+
_acq_rate, _yid_rate = 0, 0
|
|
138
|
+
|
|
139
|
+
_f.write(f'{_nam} : \n')
|
|
140
|
+
_f.write(f"\tacquisition rate : {_acq_rate}%\n")
|
|
141
|
+
_f.write(f'\tyield rate : {_yid_rate}%\n')
|
|
142
|
+
|
|
143
|
+
print(f'\t\t{_nam} : ')
|
|
144
|
+
print(f'\t\t\tacquisition rate : \033[91m{_acq_rate}%\033[0m')
|
|
145
|
+
print(f'\t\t\tyield rate : \033[91m{_yid_rate}%\033[0m')
|
|
146
|
+
|
|
147
|
+
_f.write(f"{'=' * 40}\n")
|
|
148
|
+
_f.write(_cont)
|
|
149
|
+
|
|
150
|
+
_f.close()
|
|
151
|
+
|
|
152
|
+
# process time index
|
|
153
|
+
@staticmethod
|
|
154
|
+
def _tmidx_process(_start, _end, _df):
|
|
155
|
+
_st, _ed = _df.index.sort_values()[[0, -1]]
|
|
156
|
+
_start, _end = to_datetime(_start) or _st, to_datetime(_end) or _ed
|
|
157
|
+
_idx = date_range(_start, _end, freq=_df.index.freq.copy())
|
|
158
|
+
_idx.name = 'time'
|
|
159
|
+
|
|
160
|
+
return _df.reindex(_idx), _st, _ed
|
|
161
|
+
|
|
162
|
+
# append new data to exist pkl
|
|
163
|
+
@staticmethod
|
|
164
|
+
def _apnd_prcs(_df_done, _df_apnd):
|
|
165
|
+
|
|
166
|
+
if _df_apnd is not None:
|
|
167
|
+
_df = concat([_df_apnd.dropna(how='all').copy(), _df_done.dropna(how='all').copy()])
|
|
168
|
+
|
|
169
|
+
_idx = date_range(*_df.index.sort_values()[[0, -1]], freq=_df_done.index.freq.copy())
|
|
170
|
+
_idx.name = 'time'
|
|
171
|
+
|
|
172
|
+
return _df.loc[~_df.index.duplicated()].copy().reindex(_idx)
|
|
173
|
+
|
|
174
|
+
return _df_done
|
|
175
|
+
|
|
176
|
+
# remove outlier
|
|
177
|
+
def _outlier_prcs(self, _df):
|
|
178
|
+
|
|
179
|
+
if (self.path / 'outlier.json') not in self.path.glob('*.json'):
|
|
180
|
+
return _df
|
|
181
|
+
|
|
182
|
+
with (self.path / 'outlier.json').open('r', encoding='utf-8', errors='ignore') as f:
|
|
183
|
+
self.outlier = jsn.load(f)
|
|
184
|
+
|
|
185
|
+
for _st, _ed in self.outlier.values():
|
|
186
|
+
_df.loc[_st:_ed] = np.nan
|
|
187
|
+
|
|
188
|
+
return _df
|
|
189
|
+
|
|
190
|
+
# save pickle file
|
|
191
|
+
def _save_dt(self, _save_raw, _save_qc):
|
|
192
|
+
# dump pickle file
|
|
193
|
+
_check = True
|
|
194
|
+
while _check:
|
|
195
|
+
try:
|
|
196
|
+
with (self.path / self.pkl_nam).open('wb') as f:
|
|
197
|
+
pkl.dump(_save_qc, f, protocol=pkl.HIGHEST_PROTOCOL)
|
|
198
|
+
|
|
199
|
+
# dump csv file
|
|
200
|
+
if self.csv:
|
|
201
|
+
_save_qc.to_csv(self.path / self.csv_nam)
|
|
202
|
+
|
|
203
|
+
# output raw data if qc file
|
|
204
|
+
if self.meta['deter_key'] is not None:
|
|
205
|
+
with (self.path / self.pkl_nam_raw).open('wb') as f:
|
|
206
|
+
pkl.dump(_save_raw, f, protocol=pkl.HIGHEST_PROTOCOL)
|
|
207
|
+
|
|
208
|
+
if self.csv:
|
|
209
|
+
_save_raw.to_csv(self.path / self.csv_nam_raw)
|
|
210
|
+
|
|
211
|
+
_check = False
|
|
212
|
+
|
|
213
|
+
except PermissionError as _err:
|
|
214
|
+
print('\n', _err)
|
|
215
|
+
input('\t\t\33[41m Please Close The File And Press "Enter" \33[0m\n')
|
|
216
|
+
|
|
217
|
+
# read pickle file
|
|
218
|
+
def _read_pkl(self, ):
|
|
219
|
+
with (self.path / self.pkl_nam).open('rb') as f:
|
|
220
|
+
_fout_qc = pkl.load(f)
|
|
221
|
+
|
|
222
|
+
if (self.path / self.pkl_nam_raw).exists():
|
|
223
|
+
with (self.path / self.pkl_nam_raw).open('rb') as f:
|
|
224
|
+
_fout_raw = pkl.load(f)
|
|
225
|
+
else:
|
|
226
|
+
_fout_raw = _fout_qc
|
|
227
|
+
|
|
228
|
+
return _fout_raw, _fout_qc
|
|
229
|
+
|
|
230
|
+
# read raw data
|
|
231
|
+
def _read_raw(self, ):
|
|
232
|
+
_df_con, _f_list = None, list(self.path.glob(self.meta['pattern']))
|
|
233
|
+
|
|
234
|
+
for file in _f_list:
|
|
235
|
+
if file.name in [self.csv_out, self.csv_nam, self.csv_nam_raw, f'{self.nam}.log']:
|
|
236
|
+
continue
|
|
237
|
+
|
|
238
|
+
print(f"\r\t\treading {file.name}", end='')
|
|
239
|
+
|
|
240
|
+
_df = self._raw_reader(file)
|
|
241
|
+
|
|
242
|
+
# concat the concated list
|
|
243
|
+
if _df is not None:
|
|
244
|
+
_df_con = concat([_df_con, _df]) if _df_con is not None else _df
|
|
245
|
+
|
|
246
|
+
if _df_con is None:
|
|
247
|
+
print(f"\t\t\033[31mNo File in '{self.path}' Could Read, Please Check Out the Current Path\033[0m")
|
|
248
|
+
return None, None
|
|
249
|
+
|
|
250
|
+
# QC
|
|
251
|
+
_fout_raw = self._raw_process(_df_con)
|
|
252
|
+
_fout_qc = self._QC(_fout_raw)
|
|
253
|
+
|
|
254
|
+
return _fout_raw, _fout_qc
|
|
255
|
+
|
|
256
|
+
# main flow
|
|
257
|
+
def _run(self, _start, _end):
|
|
258
|
+
|
|
259
|
+
_f_raw_done, _f_qc_done = None, None
|
|
260
|
+
|
|
261
|
+
# read pickle if pickle file exists and 'reset=False' or process raw data or append new data
|
|
262
|
+
_pkl_exist = self.path / self.pkl_nam in list(self.path.glob('*.pkl'))
|
|
263
|
+
if _pkl_exist & ((~self.reset) | self.apnd):
|
|
264
|
+
print(f"\n\t{dtm.now().strftime('%m/%d %X')} : Reading \033[96mPICKLE\033[0m file of {self.nam}")
|
|
265
|
+
|
|
266
|
+
_f_raw_done, _f_qc_done = self._read_pkl()
|
|
267
|
+
|
|
268
|
+
if not self.apnd:
|
|
269
|
+
_f_raw_done, _start_raw, _end_raw = self._tmidx_process(_start, _end, _f_raw_done)
|
|
270
|
+
_f_qc_done, _start_raw, _end_raw = self._tmidx_process(_start, _end, _f_qc_done)
|
|
271
|
+
|
|
272
|
+
_f_qc_done = self._outlier_prcs(_f_qc_done)
|
|
273
|
+
|
|
274
|
+
if self.rate:
|
|
275
|
+
self._rate_calculate(_f_raw_done, _f_qc_done, _start_raw, _end_raw)
|
|
276
|
+
|
|
277
|
+
return _f_qc_done if self.qc else _f_raw_done
|
|
278
|
+
|
|
279
|
+
# read raw data
|
|
280
|
+
print(f"\n\t{dtm.now().strftime('%m/%d %X')} : Reading \033[96mRAW DATA\033[0m of {self.nam} and process it")
|
|
281
|
+
|
|
282
|
+
_f_raw, _f_qc = self._read_raw()
|
|
283
|
+
if _f_raw is None:
|
|
284
|
+
return None
|
|
285
|
+
|
|
286
|
+
# append new data and pickle data
|
|
287
|
+
if self.apnd & _pkl_exist:
|
|
288
|
+
_f_raw = self._apnd_prcs(_f_raw_done, _f_raw)
|
|
289
|
+
_f_qc = self._apnd_prcs(_f_qc_done, _f_qc)
|
|
290
|
+
|
|
291
|
+
_f_qc = self._outlier_prcs(_f_qc)
|
|
292
|
+
|
|
293
|
+
# save
|
|
294
|
+
self._save_dt(_f_raw, _f_qc)
|
|
295
|
+
|
|
296
|
+
# process time index
|
|
297
|
+
# if (_start is not None)|(_end is not None):
|
|
298
|
+
_f_raw, _start_raw, _end_raw = self._tmidx_process(_start, _end, _f_raw)
|
|
299
|
+
_f_qc, _start_raw, _end_raw = self._tmidx_process(_start, _end, _f_qc)
|
|
300
|
+
|
|
301
|
+
self._rate_calculate(_f_raw, _f_qc, _start_raw, _end_raw)
|
|
302
|
+
|
|
303
|
+
return _f_qc if self.qc else _f_raw
|
|
304
|
+
|
|
305
|
+
# -------------------------------------------------------------------------------------
|
|
306
|
+
# old flow
|
|
307
|
+
# def __run(self, _start, _end):
|
|
308
|
+
#
|
|
309
|
+
# ## read pickle if pickle file exists and 'reset=False' or process raw data
|
|
310
|
+
# if (self.path / self.pkl_nam in list(self.path.glob('*.pkl'))) & (~self.reset):
|
|
311
|
+
# print(f"\n\t{dtm.now().strftime('%m/%d %X')} : Reading \033[96mPICKLE\033[0m file of {self.nam}")
|
|
312
|
+
#
|
|
313
|
+
# with (self.path / self.pkl_nam).open('rb') as f:
|
|
314
|
+
# _fout_qc = pkl.load(f)
|
|
315
|
+
#
|
|
316
|
+
# _exist = (self.path / self.pkl_nam_raw).exists()
|
|
317
|
+
# if _exist:
|
|
318
|
+
# with (self.path / self.pkl_nam_raw).open('rb') as f:
|
|
319
|
+
# _fout_raw = pkl.load(f)
|
|
320
|
+
# else:
|
|
321
|
+
# _fout_raw = _fout_qc
|
|
322
|
+
#
|
|
323
|
+
# _start, _end = to_datetime(_start) or _fout_qc.index[0], to_datetime(_end) or _fout_qc.index[-1]
|
|
324
|
+
# _idx = date_range(_start, _end, freq=_fout_qc.index.freq.copy())
|
|
325
|
+
# _idx.name = 'time'
|
|
326
|
+
#
|
|
327
|
+
# _fout_raw, _fout_qc = _fout_raw.reindex(_idx), _fout_qc.reindex(_idx)
|
|
328
|
+
# if (self.rate) & (_exist):
|
|
329
|
+
# self._rate_calculate(_fout_raw, _fout_qc)
|
|
330
|
+
#
|
|
331
|
+
# return _fout_qc if self.qc else _fout_raw
|
|
332
|
+
# else:
|
|
333
|
+
# print(
|
|
334
|
+
# f"\n\t{dtm.now().strftime('%m/%d %X')} : Reading \033[96mRAW DATA\033[0m of {self.nam} and process it")
|
|
335
|
+
#
|
|
336
|
+
# ##=================================================================================================================
|
|
337
|
+
# ## read raw data
|
|
338
|
+
# _df_con, _f_list = None, list(self.path.glob(self.meta['pattern']))
|
|
339
|
+
#
|
|
340
|
+
# if len(_f_list) == 0:
|
|
341
|
+
# print(f"\t\t\033[31mNo File in '{self.path}' Could Read, Please Check Out the Current Path\033[0m")
|
|
342
|
+
# return None
|
|
343
|
+
#
|
|
344
|
+
# for file in _f_list:
|
|
345
|
+
# if file.name in [self.csv_out, self.csv_nam, self.csv_nam_raw, f'{self.nam}.log']: continue
|
|
346
|
+
#
|
|
347
|
+
# print(f"\r\t\treading {file.name}", end='')
|
|
348
|
+
#
|
|
349
|
+
# _df = self._raw_reader(file)
|
|
350
|
+
#
|
|
351
|
+
# ## concat the concated list
|
|
352
|
+
# if _df is not None:
|
|
353
|
+
# _df_con = concat([_df_con, _df]) if _df_con is not None else _df
|
|
354
|
+
# print()
|
|
355
|
+
#
|
|
356
|
+
# ## QC
|
|
357
|
+
# _save_raw = self._raw_process(_df_con)
|
|
358
|
+
# _save_qc = self._QC(_save_raw)
|
|
359
|
+
#
|
|
360
|
+
# _start, _end = to_datetime(_start) or _save_raw.index[0], to_datetime(_end) or _save_raw.index[-1]
|
|
361
|
+
# _idx = date_range(_start, _end, freq=_save_raw.index.freq.copy())
|
|
362
|
+
# _idx.name = 'time'
|
|
363
|
+
#
|
|
364
|
+
# _fout_raw, _fout_qc = _save_raw.reindex(_idx).copy(), _save_qc.reindex(_idx).copy()
|
|
365
|
+
#
|
|
366
|
+
# self._rate_calculate(_fout_raw, _fout_qc)
|
|
367
|
+
#
|
|
368
|
+
# ##=================================================================================================================
|
|
369
|
+
# ## dump pickle file
|
|
370
|
+
# _check = True
|
|
371
|
+
# while _check:
|
|
372
|
+
#
|
|
373
|
+
# try:
|
|
374
|
+
# with (self.path / self.pkl_nam).open('wb') as f:
|
|
375
|
+
# pkl.dump(_save_qc, f, protocol=pkl.HIGHEST_PROTOCOL)
|
|
376
|
+
#
|
|
377
|
+
# ## dump csv file
|
|
378
|
+
# if self.csv:
|
|
379
|
+
# _save_qc.to_csv(self.path / self.csv_nam)
|
|
380
|
+
#
|
|
381
|
+
# ## output raw data if qc file
|
|
382
|
+
# if self.meta['deter_key'] is not None:
|
|
383
|
+
# with (self.path / self.pkl_nam_raw).open('wb') as f:
|
|
384
|
+
# pkl.dump(_save_raw, f, protocol=pkl.HIGHEST_PROTOCOL)
|
|
385
|
+
#
|
|
386
|
+
# if self.csv:
|
|
387
|
+
# _save_raw.to_csv(self.path / self.csv_nam_raw)
|
|
388
|
+
#
|
|
389
|
+
# return _fout_qc if self.qc else _fout_raw
|
|
390
|
+
#
|
|
391
|
+
# _check = False
|
|
392
|
+
#
|
|
393
|
+
# except PermissionError as _err:
|
|
394
|
+
# print('\n', _err)
|
|
395
|
+
# input('\t\t\33[41m Please Close The File And Press "Enter" \33[0m\n')
|
|
396
|
+
#
|
|
397
|
+
# return _fout_qc
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from pandas import read_table
|
|
2
|
+
|
|
3
|
+
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Reader(AbstractReader):
|
|
7
|
+
nam = 'AE33'
|
|
8
|
+
|
|
9
|
+
def _raw_reader(self, _file):
|
|
10
|
+
_df = read_table(_file, parse_dates={'time': [0, 1]}, index_col='time',
|
|
11
|
+
delimiter=r'\s+', skiprows=5, usecols=range(67))
|
|
12
|
+
_df.columns = _df.columns.str.strip(';')
|
|
13
|
+
|
|
14
|
+
# remove data without Status=0, 128 (Not much filter tape), 256 (Not much filter tape)
|
|
15
|
+
if not self._oth_set.get('ignore_err', False):
|
|
16
|
+
_df = _df.where((_df['Status'] != 0) | (_df['Status'] != 128) | (_df['Status'] != 256)).copy()
|
|
17
|
+
|
|
18
|
+
return _df[['BC1', 'BC2', 'BC3', 'BC4', 'BC5', 'BC6', 'BC7', 'Status']]
|
|
19
|
+
|
|
20
|
+
def _QC(self, _df):
|
|
21
|
+
# remove negative value
|
|
22
|
+
_df = _df[['BC1', 'BC2', 'BC3', 'BC4', 'BC5', 'BC6', 'BC7']].mask((_df < 0).copy())
|
|
23
|
+
|
|
24
|
+
# QC data in 5 min
|
|
25
|
+
def _QC_func(df):
|
|
26
|
+
_df_ave, _df_std = df.mean(), df.std()
|
|
27
|
+
_df_lowb, _df_highb = df < (_df_ave - _df_std * 1.5), df > (_df_ave + _df_std * 1.5)
|
|
28
|
+
|
|
29
|
+
return df.mask(_df_lowb | _df_highb).copy()
|
|
30
|
+
|
|
31
|
+
return _df.resample('5min').apply(_QC_func).resample('1h').mean()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from pandas import read_csv
|
|
2
|
+
|
|
3
|
+
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Reader(AbstractReader):
|
|
7
|
+
nam = 'AE43'
|
|
8
|
+
|
|
9
|
+
def _raw_reader(self, _file):
|
|
10
|
+
_df = read_csv(_file, parse_dates={'time': ['StartTime']}, index_col='time')
|
|
11
|
+
_df_id = _df['SetupID'].iloc[-1]
|
|
12
|
+
|
|
13
|
+
# get last SetupID data
|
|
14
|
+
_df = _df.groupby('SetupID').get_group(_df_id)[
|
|
15
|
+
['BC1', 'BC2', 'BC3', 'BC4', 'BC5', 'BC6', 'BC7', 'Status']].copy()
|
|
16
|
+
|
|
17
|
+
# remove data without Status=0
|
|
18
|
+
_df = _df.where(_df['Status'] == 0).copy()
|
|
19
|
+
|
|
20
|
+
return _df[['BC1', 'BC2', 'BC3', 'BC4', 'BC5', 'BC6', 'BC7']]
|
|
21
|
+
|
|
22
|
+
# QC data
|
|
23
|
+
def _QC(self, _df):
|
|
24
|
+
# remove negative value
|
|
25
|
+
_df = _df.mask((_df < 0).copy())
|
|
26
|
+
|
|
27
|
+
# QC data in 5 min
|
|
28
|
+
def _QC_func(df):
|
|
29
|
+
_df_ave, _df_std = df.mean(), df.std()
|
|
30
|
+
_df_lowb, _df_highb = df < (_df_ave - _df_std * 1.5), df > (_df_ave + _df_std * 1.5)
|
|
31
|
+
|
|
32
|
+
return df.mask(_df_lowb | _df_highb).copy()
|
|
33
|
+
|
|
34
|
+
return _df.resample('5min').apply(_QC_func).resample('1h').mean()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import numpy as n
|
|
2
|
+
from pandas import to_datetime, read_table
|
|
3
|
+
|
|
4
|
+
from AeroViz.rawDataReader.core import AbstractReader
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Reader(AbstractReader):
|
|
8
|
+
nam = 'APS_3321'
|
|
9
|
+
|
|
10
|
+
def _raw_reader(self, _file):
|
|
11
|
+
with open(_file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
12
|
+
_df = read_table(f, skiprows=6, parse_dates={'Time': ['Date', 'Start Time']}).set_index('Time')
|
|
13
|
+
_key = list(_df.keys()[3:54]) ## 542 ~ 1981
|
|
14
|
+
|
|
15
|
+
## create new keys
|
|
16
|
+
_newkey = {}
|
|
17
|
+
for _k in _key:
|
|
18
|
+
_newkey[_k] = float(_k).__round__(4)
|
|
19
|
+
# _newkey['Mode(m)'] = 'mode'
|
|
20
|
+
|
|
21
|
+
## get new dataframe
|
|
22
|
+
_df = _df[_newkey.keys()].rename(_newkey, axis=1)
|
|
23
|
+
# _df['total'] = _df[list(_newkey.values())[:-1]].sum(axis=1)*(n.diff(n.log(_df.keys()[:-1].to_numpy(float))).mean()).copy()
|
|
24
|
+
|
|
25
|
+
_df_idx = to_datetime(_df.index, errors='coerce')
|
|
26
|
+
|
|
27
|
+
return _df.set_index(_df_idx).loc[_df_idx.dropna()]
|
|
28
|
+
|
|
29
|
+
## QC data
|
|
30
|
+
def _QC(self, _df):
|
|
31
|
+
## mask out the data size lower than 7
|
|
32
|
+
_df['total'] = _df.sum(axis=1, min_count=1) * (n.diff(n.log(_df.keys().to_numpy(float)))).mean()
|
|
33
|
+
_df_size = _df['total'].dropna().resample('1h').size().resample(_df.index.freq).ffill()
|
|
34
|
+
_df = _df.mask(_df_size < 7)
|
|
35
|
+
|
|
36
|
+
## remove total conc. lower than 700
|
|
37
|
+
_df = _df.mask(_df['total'] > 700)
|
|
38
|
+
|
|
39
|
+
# not confirmed
|
|
40
|
+
"""
|
|
41
|
+
## remove the bin over 4000 nm which num. conc. larger than 1
|
|
42
|
+
# _df_remv_ky = _df.keys()[:-2][_df.keys()[:-2]>=4.]
|
|
43
|
+
|
|
44
|
+
# _df_1hr[_df_remv_ky] = _df_1hr[_df_remv_ky].copy().mask(_df_1hr[_df_remv_ky]>1.)
|
|
45
|
+
# """
|
|
46
|
+
|
|
47
|
+
return _df[_df.keys()[:-1]]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from pandas import to_datetime, read_csv
|
|
2
|
+
|
|
3
|
+
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Reader(AbstractReader):
|
|
7
|
+
nam = 'Aurora'
|
|
8
|
+
|
|
9
|
+
def _raw_reader(self, _file):
|
|
10
|
+
with (_file).open('r', encoding='utf-8-sig', errors='ignore') as f:
|
|
11
|
+
_df = read_csv(f, low_memory=False, index_col=0)
|
|
12
|
+
|
|
13
|
+
_df.index = to_datetime(_df.index, errors='coerce', format=self._oth_set.get('date_format') or 'mixed')
|
|
14
|
+
_df.index.name = 'time'
|
|
15
|
+
|
|
16
|
+
_df.columns = _df.keys().str.strip(' ')
|
|
17
|
+
|
|
18
|
+
_df = _df.loc[
|
|
19
|
+
_df.index.dropna(), ['0°σspB', '0°σspG', '0°σspR', '90°σspB', '90°σspG', '90°σspR', 'RH']].copy()
|
|
20
|
+
_df.columns = ['B', 'G', 'R', 'BB', 'BG', 'BR', 'RH']
|
|
21
|
+
|
|
22
|
+
return _df
|
|
23
|
+
|
|
24
|
+
## QC data
|
|
25
|
+
def _QC(self, _df):
|
|
26
|
+
## remove negative value
|
|
27
|
+
_df = _df.mask((_df <= 0).copy())
|
|
28
|
+
|
|
29
|
+
## call by _QC function
|
|
30
|
+
## QC data in 1 hr
|
|
31
|
+
def _QC_func(_df_1hr):
|
|
32
|
+
_df_ave = _df_1hr.mean()
|
|
33
|
+
_df_std = _df_1hr.std()
|
|
34
|
+
_df_lowb, _df_highb = _df_1hr < (_df_ave - _df_std * 1.5), _df_1hr > (_df_ave + _df_std * 1.5)
|
|
35
|
+
|
|
36
|
+
return _df_1hr.mask(_df_lowb | _df_highb).copy()
|
|
37
|
+
|
|
38
|
+
return _df.resample('1h', group_keys=False).apply(_QC_func)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from pandas import read_csv
|
|
2
|
+
|
|
3
|
+
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Reader(AbstractReader):
|
|
7
|
+
nam = 'BC1054'
|
|
8
|
+
|
|
9
|
+
def _raw_reader(self, _file):
|
|
10
|
+
with open(_file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
11
|
+
_df = read_csv(f, parse_dates=['Time'], index_col='Time')
|
|
12
|
+
|
|
13
|
+
_df = _df.rename(columns={
|
|
14
|
+
'BC1(ng/m3)': 'BC1',
|
|
15
|
+
'BC2(ng/m3)': 'BC2',
|
|
16
|
+
'BC3(ng/m3)': 'BC3',
|
|
17
|
+
'BC4(ng/m3)': 'BC4',
|
|
18
|
+
'BC5(ng/m3)': 'BC5',
|
|
19
|
+
'BC6(ng/m3)': 'BC6',
|
|
20
|
+
'BC7(ng/m3)': 'BC7',
|
|
21
|
+
'BC8(ng/m3)': 'BC8',
|
|
22
|
+
'BC9(ng/m3)': 'BC9',
|
|
23
|
+
'BC10(ng/m3)': 'BC10'
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
# remove data without Status=32 (Automatic Tape Advance), 65536 (Tape Move)
|
|
27
|
+
# if not self._oth_set.get('ignore_err', False):
|
|
28
|
+
# _df = _df.where((_df['Status'] != 32) | (_df['Status'] != 65536)).copy()
|
|
29
|
+
|
|
30
|
+
return _df[['BC1', 'BC2', 'BC3', 'BC4', 'BC5', 'BC6', 'BC7', 'BC8', 'BC9', 'BC10', 'Status']]
|
|
31
|
+
|
|
32
|
+
# QC data
|
|
33
|
+
def _QC(self, _df):
|
|
34
|
+
# remove negative value
|
|
35
|
+
_df = _df[['BC1', 'BC2', 'BC3', 'BC4', 'BC5', 'BC6', 'BC7', 'BC8', 'BC9', 'BC10']].mask((_df < 0).copy())
|
|
36
|
+
|
|
37
|
+
# call by _QC function
|
|
38
|
+
# QC data in 1 hr
|
|
39
|
+
def _QC_func(_df_1hr):
|
|
40
|
+
_df_ave = _df_1hr.mean()
|
|
41
|
+
_df_std = _df_1hr.std()
|
|
42
|
+
_df_lowb, _df_highb = _df_1hr < (_df_ave - _df_std * 1.5), _df_1hr > (_df_ave + _df_std * 1.5)
|
|
43
|
+
|
|
44
|
+
return _df_1hr.mask(_df_lowb | _df_highb).copy()
|
|
45
|
+
|
|
46
|
+
return _df.resample('1h', group_keys=False).apply(_QC_func).resample('5min').mean()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from pandas import read_csv, to_numeric
|
|
2
|
+
|
|
3
|
+
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Reader(AbstractReader):
|
|
7
|
+
nam = 'EPA_vertical'
|
|
8
|
+
|
|
9
|
+
def _raw_reader(self, _file):
|
|
10
|
+
with _file.open('r', encoding='big5', errors='ignore') as f:
|
|
11
|
+
_df = read_csv(f, names=['time', 'station', 'comp', 'data', None], skiprows=1, na_values=['-'],
|
|
12
|
+
parse_dates=['time'], index_col='time')
|
|
13
|
+
_df['data'] = to_numeric(_df['data'], errors='coerce')
|
|
14
|
+
|
|
15
|
+
_df_piv = _df.pivot_table(values='data', columns='comp', index='time')
|
|
16
|
+
_df_piv.index.name = 'time'
|
|
17
|
+
|
|
18
|
+
return _df_piv
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from pandas import to_datetime, read_csv
|
|
2
|
+
|
|
3
|
+
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Reader(AbstractReader):
|
|
7
|
+
nam = 'GRIMM'
|
|
8
|
+
|
|
9
|
+
def _raw_reader(self, _file):
|
|
10
|
+
|
|
11
|
+
_df = read_csv(_file, header=233, delimiter='\t', index_col=0, parse_dates=[0], encoding='ISO-8859-1',
|
|
12
|
+
dayfirst=True).rename_axis("Time")
|
|
13
|
+
_df.index = to_datetime(_df.index, format="%d/%m/%Y %H:%M:%S", dayfirst=True)
|
|
14
|
+
|
|
15
|
+
if _file.name.startswith("A407ST"):
|
|
16
|
+
_df.drop(_df.columns[0:11].tolist() + _df.columns[128:].tolist(), axis=1, inplace=True)
|
|
17
|
+
else:
|
|
18
|
+
_df.drop(_df.columns[0:11].tolist() + _df.columns[-5:].tolist(), axis=1, inplace=True)
|
|
19
|
+
|
|
20
|
+
if _df.empty:
|
|
21
|
+
print(_file, "is empty")
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
return _df / 0.035
|
|
25
|
+
|
|
26
|
+
def _QC(self, _df):
|
|
27
|
+
# QC data in 1 hr
|
|
28
|
+
def _QC_func(_df_1hr):
|
|
29
|
+
_df_ave = _df_1hr.mean()
|
|
30
|
+
_df_std = _df_1hr.std()
|
|
31
|
+
_df_lowb, _df_highb = _df_1hr < (_df_ave - _df_std * 1.5), _df_1hr > (_df_ave + _df_std * 1.5)
|
|
32
|
+
|
|
33
|
+
return _df_1hr.mask(_df_lowb | _df_highb).copy()
|
|
34
|
+
|
|
35
|
+
return _df.resample('5min').apply(_QC_func).resample('1h').mean()
|