AeroViz 0.1.3__py3-none-any.whl → 0.1.4__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 +7 -5
- AeroViz/{config → data}/DEFAULT_DATA.csv +1 -1
- AeroViz/dataProcess/Chemistry/__init__.py +40 -40
- AeroViz/dataProcess/Chemistry/_calculate.py +15 -15
- AeroViz/dataProcess/Chemistry/_isoropia.py +72 -68
- AeroViz/dataProcess/Chemistry/_mass_volume.py +158 -161
- AeroViz/dataProcess/Chemistry/_ocec.py +109 -109
- AeroViz/dataProcess/Chemistry/_partition.py +19 -18
- AeroViz/dataProcess/Chemistry/_teom.py +9 -11
- AeroViz/dataProcess/Chemistry/isrpia.cnf +21 -0
- AeroViz/dataProcess/Optical/Angstrom_exponent.py +20 -0
- AeroViz/dataProcess/Optical/_IMPROVE.py +40 -41
- AeroViz/dataProcess/Optical/__init__.py +29 -44
- AeroViz/dataProcess/Optical/_absorption.py +21 -47
- AeroViz/dataProcess/Optical/_extinction.py +31 -25
- AeroViz/dataProcess/Optical/_mie.py +5 -7
- AeroViz/dataProcess/Optical/_mie_sd.py +89 -90
- AeroViz/dataProcess/Optical/_scattering.py +19 -20
- AeroViz/dataProcess/SizeDistr/__init__.py +39 -39
- AeroViz/dataProcess/SizeDistr/__merge.py +159 -158
- AeroViz/dataProcess/SizeDistr/_merge.py +155 -154
- AeroViz/dataProcess/SizeDistr/_merge_v1.py +162 -161
- AeroViz/dataProcess/SizeDistr/_merge_v2.py +153 -152
- AeroViz/dataProcess/SizeDistr/_merge_v3.py +327 -327
- AeroViz/dataProcess/SizeDistr/_merge_v4.py +273 -275
- AeroViz/dataProcess/SizeDistr/_size_distr.py +51 -51
- AeroViz/dataProcess/VOC/__init__.py +9 -9
- AeroViz/dataProcess/VOC/_potential_par.py +53 -55
- AeroViz/dataProcess/__init__.py +28 -6
- AeroViz/dataProcess/core/__init__.py +59 -65
- AeroViz/plot/__init__.py +7 -2
- AeroViz/plot/bar.py +126 -0
- AeroViz/plot/box.py +69 -0
- AeroViz/plot/distribution/distribution.py +421 -427
- AeroViz/plot/meteorology/meteorology.py +240 -292
- AeroViz/plot/optical/__init__.py +0 -1
- AeroViz/plot/optical/optical.py +230 -230
- AeroViz/plot/pie.py +198 -0
- AeroViz/plot/regression.py +196 -0
- AeroViz/plot/scatter.py +165 -0
- AeroViz/plot/templates/__init__.py +2 -4
- AeroViz/plot/templates/ammonium_rich.py +34 -0
- AeroViz/plot/templates/contour.py +25 -25
- AeroViz/plot/templates/corr_matrix.py +86 -93
- AeroViz/plot/templates/diurnal_pattern.py +28 -26
- AeroViz/plot/templates/koschmieder.py +59 -123
- AeroViz/plot/templates/metal_heatmap.py +135 -37
- AeroViz/plot/timeseries/__init__.py +1 -0
- AeroViz/plot/timeseries/template.py +47 -0
- AeroViz/plot/timeseries/timeseries.py +324 -264
- AeroViz/plot/utils/__init__.py +2 -1
- AeroViz/plot/utils/_color.py +57 -57
- AeroViz/plot/utils/_unit.py +48 -48
- AeroViz/plot/utils/plt_utils.py +92 -0
- AeroViz/plot/utils/sklearn_utils.py +49 -0
- AeroViz/plot/utils/units.json +5 -0
- AeroViz/plot/violin.py +80 -0
- AeroViz/process/__init__.py +17 -17
- AeroViz/process/core/DataProc.py +9 -9
- AeroViz/process/core/SizeDist.py +81 -81
- AeroViz/process/method/PyMieScatt_update.py +488 -488
- AeroViz/process/method/mie_theory.py +231 -229
- AeroViz/process/method/prop.py +40 -40
- AeroViz/process/script/AbstractDistCalc.py +103 -103
- AeroViz/process/script/Chemical.py +168 -167
- AeroViz/process/script/IMPACT.py +40 -40
- AeroViz/process/script/IMPROVE.py +152 -152
- AeroViz/process/script/Others.py +45 -45
- AeroViz/process/script/PSD.py +26 -26
- AeroViz/process/script/PSD_dry.py +69 -70
- AeroViz/process/script/retrieve_RI.py +50 -51
- AeroViz/rawDataReader/__init__.py +53 -58
- AeroViz/rawDataReader/config/supported_instruments.py +155 -0
- AeroViz/rawDataReader/core/__init__.py +233 -356
- AeroViz/rawDataReader/script/AE33.py +17 -18
- AeroViz/rawDataReader/script/AE43.py +18 -21
- AeroViz/rawDataReader/script/APS_3321.py +30 -30
- AeroViz/rawDataReader/script/Aurora.py +23 -24
- AeroViz/rawDataReader/script/BC1054.py +36 -40
- AeroViz/rawDataReader/script/EPA_vertical.py +37 -9
- AeroViz/rawDataReader/script/GRIMM.py +16 -23
- AeroViz/rawDataReader/script/IGAC.py +90 -0
- AeroViz/rawDataReader/script/MA350.py +32 -39
- AeroViz/rawDataReader/script/Minion.py +103 -0
- AeroViz/rawDataReader/script/NEPH.py +69 -74
- AeroViz/rawDataReader/script/SMPS_TH.py +25 -25
- AeroViz/rawDataReader/script/SMPS_aim11.py +32 -32
- AeroViz/rawDataReader/script/SMPS_genr.py +31 -31
- AeroViz/rawDataReader/script/Sunset_OCEC.py +60 -0
- AeroViz/rawDataReader/script/TEOM.py +30 -28
- AeroViz/rawDataReader/script/Table.py +13 -14
- AeroViz/rawDataReader/script/VOC.py +26 -0
- AeroViz/rawDataReader/script/__init__.py +18 -20
- AeroViz/tools/database.py +64 -66
- AeroViz/tools/dataclassifier.py +106 -106
- AeroViz/tools/dataprinter.py +51 -51
- AeroViz/tools/datareader.py +38 -38
- {AeroViz-0.1.3.dist-info → AeroViz-0.1.4.dist-info}/METADATA +5 -4
- AeroViz-0.1.4.dist-info/RECORD +112 -0
- AeroViz/plot/improve/__init__.py +0 -1
- AeroViz/plot/improve/improve.py +0 -240
- AeroViz/plot/optical/aethalometer.py +0 -77
- AeroViz/plot/templates/event_evolution.py +0 -65
- AeroViz/plot/templates/regression.py +0 -256
- AeroViz/plot/templates/scatter.py +0 -130
- AeroViz/plot/templates/templates.py +0 -398
- AeroViz/plot/utils/_decorator.py +0 -74
- AeroViz/rawDataReader/script/IGAC_TH.py +0 -104
- AeroViz/rawDataReader/script/IGAC_ZM.py +0 -90
- AeroViz/rawDataReader/script/OCEC_LCRES.py +0 -34
- AeroViz/rawDataReader/script/OCEC_RES.py +0 -28
- AeroViz/rawDataReader/script/VOC_TH.py +0 -30
- AeroViz/rawDataReader/script/VOC_ZM.py +0 -37
- AeroViz/rawDataReader/utils/__init__.py +0 -0
- AeroViz/rawDataReader/utils/config.py +0 -169
- AeroViz-0.1.3.dist-info/RECORD +0 -111
- /AeroViz/{config → data}/DEFAULT_PNSD_DATA.csv +0 -0
- /AeroViz/{config → rawDataReader/config}/__init__.py +0 -0
- {AeroViz-0.1.3.dist-info → AeroViz-0.1.4.dist-info}/LICENSE +0 -0
- {AeroViz-0.1.3.dist-info → AeroViz-0.1.4.dist-info}/WHEEL +0 -0
- {AeroViz-0.1.3.dist-info → AeroViz-0.1.4.dist-info}/top_level.txt +0 -0
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
from typing import Literal
|
|
2
|
-
|
|
3
|
-
import matplotlib.pyplot as plt
|
|
4
|
-
import numpy as np
|
|
5
|
-
import pandas as pd
|
|
6
|
-
import seaborn as sns
|
|
7
|
-
from matplotlib.pyplot import Figure, Axes
|
|
8
|
-
from pandas import DataFrame
|
|
9
|
-
|
|
10
|
-
from AeroViz.plot.utils import *
|
|
11
|
-
|
|
12
|
-
__all__ = [
|
|
13
|
-
'pie',
|
|
14
|
-
'donuts',
|
|
15
|
-
'violin',
|
|
16
|
-
'bar',
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _auto_label_pct(pct,
|
|
21
|
-
symbol: bool = True,
|
|
22
|
-
include_pct: bool = False,
|
|
23
|
-
ignore: Literal["inner", "outer"] = 'inner',
|
|
24
|
-
value: float = 2):
|
|
25
|
-
if not symbol:
|
|
26
|
-
return ''
|
|
27
|
-
cond = pct <= value if ignore == 'inner' else pct > value
|
|
28
|
-
label = '' if cond else '{:.1f}'.format(pct)
|
|
29
|
-
return '' if label == '' else label + '%' if include_pct else label
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@set_figure(fs=8, fw='bold')
|
|
33
|
-
def pie(data_set: DataFrame | dict,
|
|
34
|
-
labels: list[str],
|
|
35
|
-
unit: str,
|
|
36
|
-
style: Literal["pie", 'donut'],
|
|
37
|
-
ax: Axes | None = None,
|
|
38
|
-
symbol: bool = True,
|
|
39
|
-
**kwargs) -> tuple[Figure, Axes]:
|
|
40
|
-
"""
|
|
41
|
-
Create a pie or donut chart based on the provided data.
|
|
42
|
-
|
|
43
|
-
Parameters
|
|
44
|
-
----------
|
|
45
|
-
data_set : pd.DataFrame | dict
|
|
46
|
-
A pandas DataFrame or dictionary mapping category names to a list of species.
|
|
47
|
-
If a DataFrame is provided, the index represents the categories, and each column contains species data.
|
|
48
|
-
If a dictionary is provided, it maps category names to lists of species data.
|
|
49
|
-
It is assumed that all lists or DataFrame columns contain the same number of entries as the *labels* list.
|
|
50
|
-
labels : list of str
|
|
51
|
-
The labels for each category.
|
|
52
|
-
unit : str
|
|
53
|
-
The unit to display in the center of the donut chart.
|
|
54
|
-
style : Literal["pie", 'donut']
|
|
55
|
-
The style of the chart, either 'pie' for a standard pie chart or 'donut' for a donut chart.
|
|
56
|
-
ax : plt.Axes or None, optional
|
|
57
|
-
The Axes object to plot the chart onto. If None, a new figure and Axes will be created.
|
|
58
|
-
symbol : bool, optional
|
|
59
|
-
Whether to display values for each species in the chart.
|
|
60
|
-
**kwargs
|
|
61
|
-
Additional keyword arguments to be passed to the plotting function.
|
|
62
|
-
|
|
63
|
-
Returns
|
|
64
|
-
-------
|
|
65
|
-
matplotlib.axes.Axes
|
|
66
|
-
The Axes object containing the violin plot.
|
|
67
|
-
|
|
68
|
-
Notes
|
|
69
|
-
-----
|
|
70
|
-
- If *data_set* is a dictionary, it should contain lists of species that correspond to each category in *labels*.
|
|
71
|
-
- The length of each list in *data_set* or the number of columns in the DataFrame should match the length of the *labels* list.
|
|
72
|
-
|
|
73
|
-
Examples
|
|
74
|
-
--------
|
|
75
|
-
>>> data_set = {'Category 1': [10, 20, 30], 'Category 2': [15, 25, 35]}
|
|
76
|
-
>>> labels = ['Species 1', 'Species 2', 'Species 3']
|
|
77
|
-
>>> pie(data_set, labels, unit='kg', style='pie', symbol=True)
|
|
78
|
-
"""
|
|
79
|
-
if isinstance(data_set, DataFrame):
|
|
80
|
-
category_names = list(data_set.index)
|
|
81
|
-
data = data_set.to_numpy()
|
|
82
|
-
|
|
83
|
-
pies, species = data.shape
|
|
84
|
-
|
|
85
|
-
elif isinstance(data_set, dict):
|
|
86
|
-
category_names = list(data_set.keys())
|
|
87
|
-
data = np.array(list(data_set.values()))
|
|
88
|
-
|
|
89
|
-
pies, species = data.shape
|
|
90
|
-
|
|
91
|
-
else:
|
|
92
|
-
raise ValueError('data_set must be a DataFrame or a dictionary.')
|
|
93
|
-
|
|
94
|
-
colors = kwargs.get('colors') or (Color.colors1 if species == 6 else Color.getColor(num=species))
|
|
95
|
-
|
|
96
|
-
radius = 4
|
|
97
|
-
width = 4 if style == 'pie' else 1
|
|
98
|
-
|
|
99
|
-
text = [''] * pies if style == 'pie' else [Unit(unit) + '\n\n' + '{:.2f}'.format(x) for x in data.sum(axis=1)]
|
|
100
|
-
pct_distance = 0.6 if style == 'pie' else 0.88
|
|
101
|
-
|
|
102
|
-
fig, ax = plt.subplots(1, pies, figsize=((pies * 2) + 1, 2)) if ax is None else (ax.get_figure(), ax)
|
|
103
|
-
|
|
104
|
-
if pies == 1:
|
|
105
|
-
ax = [ax]
|
|
106
|
-
|
|
107
|
-
for i in range(pies):
|
|
108
|
-
ax[i].pie(data[i], labels=None, colors=colors, textprops=None,
|
|
109
|
-
autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, include_pct=True),
|
|
110
|
-
pctdistance=pct_distance, radius=radius, wedgeprops=dict(width=width, edgecolor='w'))
|
|
111
|
-
|
|
112
|
-
ax[i].pie(data[i], labels=None, colors=colors, textprops=None,
|
|
113
|
-
autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, ignore='outer', include_pct=True),
|
|
114
|
-
pctdistance=1.3, radius=radius, wedgeprops=dict(width=width, edgecolor='w'))
|
|
115
|
-
ax[i].axis('equal')
|
|
116
|
-
ax[i].text(0, 0, text[i], ha='center', va='center')
|
|
117
|
-
ax[i].set_title(category_names[i])
|
|
118
|
-
|
|
119
|
-
ax[-1].legend(labels, loc='center left', prop={'weight': 'bold'}, bbox_to_anchor=(1, 0, 1.15, 1))
|
|
120
|
-
|
|
121
|
-
# fig.savefig(f"pie_{style}_{title}")
|
|
122
|
-
|
|
123
|
-
plt.show()
|
|
124
|
-
|
|
125
|
-
return fig, ax
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
@set_figure(fs=8, fw='bold')
|
|
129
|
-
def donuts(data_set: DataFrame | dict,
|
|
130
|
-
labels: list[str],
|
|
131
|
-
unit: str,
|
|
132
|
-
ax: Axes | None = None,
|
|
133
|
-
symbol=True,
|
|
134
|
-
**kwargs) -> tuple[Figure, Axes]:
|
|
135
|
-
"""
|
|
136
|
-
Plot a donut chart based on the data set.
|
|
137
|
-
|
|
138
|
-
Parameters
|
|
139
|
-
----------
|
|
140
|
-
data_set : pd.DataFrame | dict
|
|
141
|
-
A pandas DataFrame or a dictionary mapping category names to a list of species.
|
|
142
|
-
If a DataFrame is provided, the index represents the categories, and each column contains species data.
|
|
143
|
-
If a dictionary is provided, it maps category names to lists of species data.
|
|
144
|
-
It is assumed that all lists or DataFrame columns contain the same number of entries as the *labels* list.
|
|
145
|
-
labels : list of str
|
|
146
|
-
The category labels.
|
|
147
|
-
unit : str
|
|
148
|
-
The unit to be displayed in the center of the donut chart.
|
|
149
|
-
ax : matplotlib.axes.Axes, optional
|
|
150
|
-
The axes to plot on. If None, the current axes will be used (default).
|
|
151
|
-
symbol : bool, optional
|
|
152
|
-
Whether to display values for each species (default is True).
|
|
153
|
-
**kwargs : dict, optional
|
|
154
|
-
Additional keyword arguments to pass to the matplotlib pie chart function.
|
|
155
|
-
|
|
156
|
-
Returns
|
|
157
|
-
-------
|
|
158
|
-
matplotlib.axes.Axes
|
|
159
|
-
The axes containing the donut chart.
|
|
160
|
-
"""
|
|
161
|
-
|
|
162
|
-
if isinstance(data_set, DataFrame):
|
|
163
|
-
category_names = list(data_set.index)
|
|
164
|
-
data = data_set.to_numpy()
|
|
165
|
-
|
|
166
|
-
pies, species = data.shape
|
|
167
|
-
|
|
168
|
-
elif isinstance(data_set, dict):
|
|
169
|
-
category_names = list(data_set.keys())
|
|
170
|
-
data = np.array(list(data_set.values()))
|
|
171
|
-
|
|
172
|
-
pies, species = data.shape
|
|
173
|
-
|
|
174
|
-
else:
|
|
175
|
-
raise ValueError('data_set must be a DataFrame or a dictionary.')
|
|
176
|
-
|
|
177
|
-
colors1 = kwargs.get('colors') or (Color.colors1 if species == 6 else Color.getColor(num=species))
|
|
178
|
-
colors2 = Color.adjust_opacity(colors1, 0.8)
|
|
179
|
-
colors3 = Color.adjust_opacity(colors1, 0.6)
|
|
180
|
-
|
|
181
|
-
fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
|
|
182
|
-
|
|
183
|
-
ax.pie(data[2], labels=None, colors=colors1, textprops=None,
|
|
184
|
-
autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, include_pct=True),
|
|
185
|
-
pctdistance=0.9, radius=14, wedgeprops=dict(width=3, edgecolor='w'))
|
|
186
|
-
|
|
187
|
-
ax.pie(data[1], labels=None, colors=colors2, textprops=None,
|
|
188
|
-
autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, include_pct=True),
|
|
189
|
-
pctdistance=0.85, radius=11, wedgeprops=dict(width=3, edgecolor='w'))
|
|
190
|
-
|
|
191
|
-
ax.pie(data[0], labels=None, colors=colors3, textprops=None,
|
|
192
|
-
autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, include_pct=True),
|
|
193
|
-
pctdistance=0.80, radius=8, wedgeprops=dict(width=3, edgecolor='w'))
|
|
194
|
-
|
|
195
|
-
text = (Unit(f'{unit}') + '\n\n' +
|
|
196
|
-
'Event : ' + "{:.2f}".format(np.sum(data[2])) + '\n' +
|
|
197
|
-
'Transition : ' + "{:.2f}".format(np.sum(data[1])) + '\n' +
|
|
198
|
-
'Clean : ' + "{:.2f}".format(np.sum(data[0])))
|
|
199
|
-
|
|
200
|
-
ax.text(0, 0, text, ha='center', va='center')
|
|
201
|
-
ax.axis('equal')
|
|
202
|
-
|
|
203
|
-
ax.set_title(kwargs.get('title', ''))
|
|
204
|
-
|
|
205
|
-
ax.legend(labels, loc='center', prop={'weight': 'bold'}, title_fontproperties={'weight': 'bold'},
|
|
206
|
-
title=f'Outer : {category_names[2]}' + '\n' + f'Middle : {category_names[1]}' + '\n' + f'Inner : {category_names[0]}',
|
|
207
|
-
bbox_to_anchor=(0.8, 0, 0.5, 1))
|
|
208
|
-
|
|
209
|
-
# fig.savefig(f"donuts_{title}")
|
|
210
|
-
|
|
211
|
-
plt.show()
|
|
212
|
-
|
|
213
|
-
return fig, ax
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
@set_figure(figsize=(5, 4))
|
|
217
|
-
def bar(data_set: DataFrame | dict,
|
|
218
|
-
data_std: DataFrame | None,
|
|
219
|
-
labels: list[str],
|
|
220
|
-
unit: str,
|
|
221
|
-
style: Literal["stacked", "dispersed"] = "dispersed",
|
|
222
|
-
orientation: Literal["va", "ha"] = 'va',
|
|
223
|
-
ax: Axes | None = None,
|
|
224
|
-
symbol=True,
|
|
225
|
-
**kwargs
|
|
226
|
-
) -> tuple[Figure, Axes]:
|
|
227
|
-
"""
|
|
228
|
-
Parameters
|
|
229
|
-
----------
|
|
230
|
-
data_set : pd.DataFrame or dict
|
|
231
|
-
A mapping from category names to a list of species mean or a DataFrame with columns as categories and values as means.
|
|
232
|
-
data_std : pd.DataFrame or None
|
|
233
|
-
A DataFrame with standard deviations corresponding to data_set, or None if standard deviations are not provided.
|
|
234
|
-
labels : list of str
|
|
235
|
-
The species names.
|
|
236
|
-
unit : str
|
|
237
|
-
The unit for the values.
|
|
238
|
-
style : {'stacked', 'dispersed'}, default 'dispersed'
|
|
239
|
-
Whether to display the bars stacked or dispersed.
|
|
240
|
-
orientation : {'va', 'ha'}, default 'va'
|
|
241
|
-
The orientation of the bars, 'va' for vertical and 'ha' for horizontal.
|
|
242
|
-
ax : plt.Axes or None, default None
|
|
243
|
-
The Axes object to plot on. If None, a new figure and Axes are created.
|
|
244
|
-
symbol : bool, default True
|
|
245
|
-
Whether to display values for each bar.
|
|
246
|
-
kwargs : dict
|
|
247
|
-
Additional keyword arguments passed to the barplot function.
|
|
248
|
-
|
|
249
|
-
Returns
|
|
250
|
-
-------
|
|
251
|
-
matplotlib.Axes
|
|
252
|
-
The Axes object containing the plot.
|
|
253
|
-
|
|
254
|
-
"""
|
|
255
|
-
# data process
|
|
256
|
-
data = data_set.values
|
|
257
|
-
|
|
258
|
-
if data_std is None:
|
|
259
|
-
data_std = np.zeros(data.shape)
|
|
260
|
-
else:
|
|
261
|
-
data_std = data_std.values
|
|
262
|
-
|
|
263
|
-
groups, species = data.shape
|
|
264
|
-
groups_arr = np.arange(groups)
|
|
265
|
-
species_arr = np.arange(species)
|
|
266
|
-
|
|
267
|
-
total = np.array([data.sum(axis=1), ] * species).T
|
|
268
|
-
|
|
269
|
-
pct_data = data / total * 100
|
|
270
|
-
data_cum = pct_data.cumsum(axis=1)
|
|
271
|
-
|
|
272
|
-
# figure info
|
|
273
|
-
category_names = kwargs.get('ticks') or list(data_set.index)
|
|
274
|
-
title = kwargs.get('title', '')
|
|
275
|
-
colors = kwargs.get('colors') or (Color.colors1 if species == 6 else Color.getColor(num=species))
|
|
276
|
-
|
|
277
|
-
fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
|
|
278
|
-
|
|
279
|
-
if style == "stacked":
|
|
280
|
-
for i in range(species):
|
|
281
|
-
widths = pct_data[:, i]
|
|
282
|
-
starts = data_cum[:, i] - pct_data[:, i]
|
|
283
|
-
|
|
284
|
-
if orientation == 'va':
|
|
285
|
-
_ = ax.bar(groups_arr, widths, bottom=starts, width=0.7, color=colors[i], label=labels[i],
|
|
286
|
-
edgecolor=None, capsize=None)
|
|
287
|
-
if orientation == 'ha':
|
|
288
|
-
_ = ax.barh(groups_arr, widths, left=starts, height=0.7, color=colors[i], label=labels[i],
|
|
289
|
-
edgecolor=None, capsize=None)
|
|
290
|
-
if symbol:
|
|
291
|
-
ax.bar_label(_, fmt=_auto_label_pct, label_type='center', padding=0, fontsize=10, weight='bold')
|
|
292
|
-
|
|
293
|
-
if style == "dispersed":
|
|
294
|
-
width = 0.1
|
|
295
|
-
block = width / 4
|
|
296
|
-
|
|
297
|
-
for i in range(species):
|
|
298
|
-
val = data[:, i]
|
|
299
|
-
std = (0,) * groups, data_std[:, i]
|
|
300
|
-
if orientation == 'va':
|
|
301
|
-
_ = ax.bar(groups_arr + (i + 1) * (width + block), val, yerr=std, width=width, color=colors[i],
|
|
302
|
-
edgecolor=None, capsize=None)
|
|
303
|
-
if orientation == 'ha':
|
|
304
|
-
_ = ax.barh(groups_arr + (i + 1) * (width + block), val, xerr=std, height=width, color=colors[i],
|
|
305
|
-
edgecolor=None, capsize=None)
|
|
306
|
-
if symbol:
|
|
307
|
-
ax.bar_label(_, fmt=_auto_label_pct, label_type='center', padding=0, fontsize=8, weight='bold')
|
|
308
|
-
|
|
309
|
-
if orientation == 'va':
|
|
310
|
-
xticks = groups_arr + (species / 2 + 0.5) * (width + block) if style == "dispersed" else groups_arr
|
|
311
|
-
ax.set_xticks(xticks, category_names, weight='bold')
|
|
312
|
-
ax.set_ylabel(Unit(unit) if style == "dispersed" else '$Contribution (\\%)$')
|
|
313
|
-
ax.set_ylim(0, None if style == "dispersed" else 100)
|
|
314
|
-
ax.legend(labels, bbox_to_anchor=(1, 1), loc='upper left', prop={'size': 12})
|
|
315
|
-
|
|
316
|
-
if orientation == 'ha':
|
|
317
|
-
ax.invert_yaxis()
|
|
318
|
-
yticks = groups_arr + 3.5 * (width + block) if style == "dispersed" else groups_arr
|
|
319
|
-
ax.set_yticks(yticks, category_names, weight='bold')
|
|
320
|
-
ax.set_xlabel(Unit(unit) if style == "dispersed" else '$Contribution (\\%)$')
|
|
321
|
-
ax.set_xlim(0, None if style == "dispersed" else 100)
|
|
322
|
-
ax.legend(labels, bbox_to_anchor=(1, 1), loc='upper left', prop={'size': 12})
|
|
323
|
-
|
|
324
|
-
# fig.savefig(f"Barplot_{title}")
|
|
325
|
-
|
|
326
|
-
plt.show()
|
|
327
|
-
|
|
328
|
-
return fig, ax
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
@set_figure
|
|
332
|
-
def violin(data_set: DataFrame | dict,
|
|
333
|
-
unit: str,
|
|
334
|
-
ax: Axes | None = None,
|
|
335
|
-
**kwargs
|
|
336
|
-
) -> tuple[Figure, Axes]:
|
|
337
|
-
"""
|
|
338
|
-
Generate a violin plot for multiple data sets.
|
|
339
|
-
|
|
340
|
-
Parameters
|
|
341
|
-
----------
|
|
342
|
-
data_set : pd.DataFrame or dict
|
|
343
|
-
A mapping from category names to pandas DataFrames containing the data.
|
|
344
|
-
unit : str
|
|
345
|
-
The unit for the data being plotted.
|
|
346
|
-
ax : matplotlib.axes.Axes, optional
|
|
347
|
-
The Axes object to draw the plot onto. If not provided, a new figure will be created.
|
|
348
|
-
**kwargs : dict
|
|
349
|
-
Additional keyword arguments to be passed to the violinplot function.
|
|
350
|
-
|
|
351
|
-
Returns
|
|
352
|
-
-------
|
|
353
|
-
matplotlib.axes.Axes
|
|
354
|
-
The Axes object containing the violin plot.
|
|
355
|
-
|
|
356
|
-
"""
|
|
357
|
-
fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
|
|
358
|
-
|
|
359
|
-
data = data_set.to_numpy()
|
|
360
|
-
|
|
361
|
-
data = data[~np.isnan(data).any(axis=1)]
|
|
362
|
-
|
|
363
|
-
grps = data.shape[1]
|
|
364
|
-
|
|
365
|
-
width = 0.6
|
|
366
|
-
block = width / 2
|
|
367
|
-
x_position = np.arange(grps)
|
|
368
|
-
|
|
369
|
-
plt.boxplot(data, positions=x_position, widths=0.15,
|
|
370
|
-
showfliers=False, showmeans=True, meanline=False, patch_artist=True,
|
|
371
|
-
capprops=dict(linewidth=0),
|
|
372
|
-
whiskerprops=dict(linewidth=1.5, color='k', alpha=1),
|
|
373
|
-
boxprops=dict(linewidth=1.5, color='k', facecolor='#4778D3', alpha=1),
|
|
374
|
-
meanprops=dict(marker='o', markeredgecolor='black', markerfacecolor='white', markersize=6),
|
|
375
|
-
medianprops=dict(linewidth=1.5, ls='-', color='k', alpha=1))
|
|
376
|
-
|
|
377
|
-
sns.violinplot(data=data, density_norm='area', color='#4778D3', inner=None)
|
|
378
|
-
|
|
379
|
-
for violin, alpha in zip(ax.collections[:], [0.5] * len(ax.collections[:])):
|
|
380
|
-
violin.set_alpha(alpha)
|
|
381
|
-
violin.set_edgecolor(None)
|
|
382
|
-
|
|
383
|
-
plt.scatter(x_position, data.mean(), marker='o', facecolor='white', edgecolor='k', s=10)
|
|
384
|
-
|
|
385
|
-
xlim = kwargs.get('xlim') or (x_position[0] - (width / 2 + block), x_position[-1] + (width / 2 + block))
|
|
386
|
-
ylim = kwargs.get('ylim') or (0, None)
|
|
387
|
-
xlabel = kwargs.get('xlabel') or ''
|
|
388
|
-
ylabel = kwargs.get('ylabel') or Unit(unit)
|
|
389
|
-
xticks = kwargs.get('xticks') or [x.replace('-', '\n') for x in list(data_set.keys())]
|
|
390
|
-
|
|
391
|
-
ax.set(xlim=xlim, ylim=ylim, xlabel=xlabel, ylabel=ylabel, title=kwargs.get('title'))
|
|
392
|
-
ax.set_xticks(x_position, xticks, fontweight='bold', fontsize=12)
|
|
393
|
-
|
|
394
|
-
# fig.savefig(f'Violin_{unit}')
|
|
395
|
-
|
|
396
|
-
plt.show()
|
|
397
|
-
|
|
398
|
-
return fig, ax
|
AeroViz/plot/utils/_decorator.py
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
from functools import wraps
|
|
2
|
-
|
|
3
|
-
import matplotlib.pyplot as plt
|
|
4
|
-
|
|
5
|
-
__all__ = ['set_figure']
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# For more details please see https://matplotlib.org/stable/users/explain/customizing.html
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def set_figure(func=None,
|
|
12
|
-
*,
|
|
13
|
-
figsize: tuple | None = None,
|
|
14
|
-
fs: int | None = None,
|
|
15
|
-
fw: str = None,
|
|
16
|
-
autolayout: bool = True
|
|
17
|
-
):
|
|
18
|
-
def decorator(_func):
|
|
19
|
-
@wraps(_func)
|
|
20
|
-
def wrapper(*args, **kwargs):
|
|
21
|
-
print(f'\t\t Plot: \033[96m{_func.__name__}\033[0m')
|
|
22
|
-
|
|
23
|
-
plt.rcParams['mathtext.fontset'] = 'custom'
|
|
24
|
-
plt.rcParams['mathtext.rm'] = 'Times New Roman'
|
|
25
|
-
plt.rcParams['mathtext.it'] = 'Times New Roman: italic'
|
|
26
|
-
plt.rcParams['mathtext.bf'] = 'Times New Roman: bold'
|
|
27
|
-
plt.rcParams['mathtext.default'] = 'regular'
|
|
28
|
-
|
|
29
|
-
# The font properties used by `text.Text`.
|
|
30
|
-
# The text, annotate, label, title, ticks, are used to create text
|
|
31
|
-
plt.rcParams['font.family'] = 'Times New Roman'
|
|
32
|
-
plt.rcParams['font.weight'] = fw or 'normal'
|
|
33
|
-
plt.rcParams['font.size'] = fs or 8
|
|
34
|
-
|
|
35
|
-
plt.rcParams['axes.titlesize'] = 'large'
|
|
36
|
-
plt.rcParams['axes.titleweight'] = 'bold'
|
|
37
|
-
plt.rcParams['axes.labelweight'] = 'bold'
|
|
38
|
-
|
|
39
|
-
# color
|
|
40
|
-
plt.rcParams['axes.prop_cycle'] = plt.cycler(color=['b', 'g', 'r', 'c', 'm', 'y', 'k'])
|
|
41
|
-
|
|
42
|
-
plt.rcParams['xtick.labelsize'] = 'medium'
|
|
43
|
-
plt.rcParams['ytick.labelsize'] = 'medium'
|
|
44
|
-
|
|
45
|
-
# matplotlib.font_manager.FontProperties ---> matplotlib.rcParams
|
|
46
|
-
plt.rcParams['legend.loc'] = 'best'
|
|
47
|
-
plt.rcParams['legend.frameon'] = False
|
|
48
|
-
plt.rcParams['legend.fontsize'] = 'small'
|
|
49
|
-
plt.rcParams['legend.title_fontsize'] = 'medium'
|
|
50
|
-
plt.rcParams['legend.handlelength'] = 1.5
|
|
51
|
-
plt.rcParams['legend.labelspacing'] = 0.7
|
|
52
|
-
|
|
53
|
-
plt.rcParams['figure.figsize'] = figsize or (5, 4)
|
|
54
|
-
plt.rcParams['figure.dpi'] = 200
|
|
55
|
-
plt.rcParams['figure.autolayout'] = autolayout
|
|
56
|
-
|
|
57
|
-
if ~autolayout:
|
|
58
|
-
plt.rcParams['figure.subplot.left'] = 0.1
|
|
59
|
-
plt.rcParams['figure.subplot.right'] = 0.875
|
|
60
|
-
plt.rcParams['figure.subplot.top'] = 0.875
|
|
61
|
-
plt.rcParams['figure.subplot.bottom'] = 0.125
|
|
62
|
-
|
|
63
|
-
# plt.rcParams['figure.constrained_layout.use'] = True
|
|
64
|
-
|
|
65
|
-
plt.rcParams['savefig.transparent'] = True
|
|
66
|
-
|
|
67
|
-
return _func(*args, **kwargs)
|
|
68
|
-
|
|
69
|
-
return wrapper
|
|
70
|
-
|
|
71
|
-
if func is None:
|
|
72
|
-
return decorator
|
|
73
|
-
|
|
74
|
-
return decorator(func)
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
# read meteorological data from google sheet
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import numpy as np
|
|
5
|
-
from pandas import read_csv, concat, to_datetime
|
|
6
|
-
|
|
7
|
-
from AeroViz.rawDataReader.core import AbstractReader
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Reader(AbstractReader):
|
|
11
|
-
nam = 'IGAC_TH'
|
|
12
|
-
|
|
13
|
-
def _raw_reader(self, _file):
|
|
14
|
-
|
|
15
|
-
self.meta['freq'] = self._oth_set.get('data_freq') or self.meta['freq']
|
|
16
|
-
|
|
17
|
-
with (_file).open('r', encoding='utf-8-sig', errors='ignore') as f:
|
|
18
|
-
_df = read_csv(f, low_memory=False, index_col=0)
|
|
19
|
-
|
|
20
|
-
_df.index = to_datetime(_df.index, errors='coerce', format=self._oth_set.get('date_format') or 'mixed')
|
|
21
|
-
_df.index.name = 'time'
|
|
22
|
-
|
|
23
|
-
_df.columns = _df.keys().str.strip(' ')
|
|
24
|
-
|
|
25
|
-
_df = _df.loc[_df.index.dropna()].copy()
|
|
26
|
-
|
|
27
|
-
return _df.loc[~_df.index.duplicated()]
|
|
28
|
-
|
|
29
|
-
## QC data
|
|
30
|
-
def _QC(self, _df):
|
|
31
|
-
|
|
32
|
-
## QC parameter, function (MDL SE LE)
|
|
33
|
-
_mdl = {
|
|
34
|
-
'Na+': 0.05,
|
|
35
|
-
'NH4+': 0.05,
|
|
36
|
-
'K+': 0.05,
|
|
37
|
-
'Mg2+': 0.05,
|
|
38
|
-
'Ca2+': 0.05,
|
|
39
|
-
'Cl-': 0.05,
|
|
40
|
-
'NO2-': 0.05,
|
|
41
|
-
'NO3-': 0.05,
|
|
42
|
-
'SO42-': 0.05,
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
def _se_le(_df_, _log=False):
|
|
46
|
-
_df_ = np.log10(_df_) if _log else _df_
|
|
47
|
-
|
|
48
|
-
_df_qua = _df_.quantile([.25, .75])
|
|
49
|
-
_df_q1, _df_q3 = _df_qua.loc[.25].copy(), _df_qua.loc[.75].copy()
|
|
50
|
-
_df_iqr = _df_q3 - _df_q1
|
|
51
|
-
|
|
52
|
-
_se = concat([_df_q1 - 1.5 * _df_iqr] * len(_df_), axis=1).T.set_index(_df_.index)
|
|
53
|
-
_le = concat([_df_q3 + 1.5 * _df_iqr] * len(_df_), axis=1).T.set_index(_df_.index)
|
|
54
|
-
|
|
55
|
-
if _log:
|
|
56
|
-
return 10 ** _se, 10 ** _le
|
|
57
|
-
return _se, _le
|
|
58
|
-
|
|
59
|
-
_cation, _anion, _main = ['Na+', 'NH4+', 'K+', 'Mg2+', 'Ca2+'], ['Cl-', 'NO2-', 'NO3-', 'SO42-', ], ['SO42-',
|
|
60
|
-
'NO3-',
|
|
61
|
-
'NH4+']
|
|
62
|
-
|
|
63
|
-
_df_salt = _df[_mdl.keys()].copy()
|
|
64
|
-
_df_pm = _df['PM2.5'].copy()
|
|
65
|
-
|
|
66
|
-
## lower than PM2.5
|
|
67
|
-
## conc. of main salt should be present at the same time (NH4+, SO42-, NO3-)
|
|
68
|
-
_df_salt = _df_salt.mask(_df_salt.sum(axis=1, min_count=1) > _df_pm).dropna(subset=_main).copy()
|
|
69
|
-
|
|
70
|
-
## mdl
|
|
71
|
-
for (_key, _df_col), _mdl_val in zip(_df_salt.items(), _mdl.values()):
|
|
72
|
-
_df_salt[_key] = _df_col.mask(_df_col < _mdl_val, _mdl_val / 2)
|
|
73
|
-
|
|
74
|
-
## group by time (per month)
|
|
75
|
-
_df_salt['tm'] = _df_salt.index.strftime('%Y-%m')
|
|
76
|
-
|
|
77
|
-
_df_lst = []
|
|
78
|
-
for _ky, _df_grp in _df_salt.groupby('tm'):
|
|
79
|
-
_df_grp = _df_grp[_mdl.keys()].copy()
|
|
80
|
-
|
|
81
|
-
## calculate SE LE
|
|
82
|
-
## salt < LE
|
|
83
|
-
_se, _le = _se_le(_df_grp, _log=True)
|
|
84
|
-
_df_grp = _df_grp.mask(_df_grp > _le).copy()
|
|
85
|
-
|
|
86
|
-
## C/A, A/C
|
|
87
|
-
_rat_CA = (_df_grp[_cation].sum(axis=1) / _df_grp[_anion].sum(axis=1)).to_frame()
|
|
88
|
-
_rat_AC = (1 / _rat_CA).copy()
|
|
89
|
-
|
|
90
|
-
_se, _le = _se_le(_rat_CA, )
|
|
91
|
-
_cond_CA = (_rat_CA < _le) & (_rat_CA > 0)
|
|
92
|
-
|
|
93
|
-
_se, _le = _se_le(_rat_AC, )
|
|
94
|
-
_cond_AC = (_rat_AC < _le) & (_rat_AC > 0)
|
|
95
|
-
|
|
96
|
-
_df_grp = _df_grp.where((_cond_CA * _cond_AC)[0]).copy()
|
|
97
|
-
|
|
98
|
-
## conc. of main salt > SE
|
|
99
|
-
_se, _le = _se_le(_df_grp[_main], _log=True)
|
|
100
|
-
_df_grp[_main] = _df_grp[_main].mask(_df_grp[_main] < _se).copy()
|
|
101
|
-
|
|
102
|
-
_df_lst.append(_df_grp)
|
|
103
|
-
|
|
104
|
-
return concat(_df_lst).reindex(_df.index)
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# read meteorological data from google sheet
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import numpy as np
|
|
5
|
-
from pandas import read_csv, concat, to_numeric
|
|
6
|
-
|
|
7
|
-
from AeroViz.rawDataReader.core import AbstractReader
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Reader(AbstractReader):
|
|
11
|
-
nam = 'IGAC_ZM'
|
|
12
|
-
|
|
13
|
-
def _raw_reader(self, _file):
|
|
14
|
-
|
|
15
|
-
with (_file).open('r', encoding='utf-8-sig', errors='ignore') as f:
|
|
16
|
-
_df = read_csv(f, parse_dates=[0], index_col=[0], na_values=['-']).apply(to_numeric, errors='coerce')
|
|
17
|
-
|
|
18
|
-
_df.columns = _df.keys().str.strip(' ')
|
|
19
|
-
_df.index.name = 'time'
|
|
20
|
-
|
|
21
|
-
return _df.loc[_df.index.dropna()].loc[~_df.index.duplicated()]
|
|
22
|
-
|
|
23
|
-
## QC data
|
|
24
|
-
def _QC(self, _df):
|
|
25
|
-
|
|
26
|
-
## QC parameter, function (MDL SE LE)
|
|
27
|
-
_mdl = {
|
|
28
|
-
'Na+': 0.06,
|
|
29
|
-
'NH4+': 0.05,
|
|
30
|
-
'K+': 0.05,
|
|
31
|
-
'Mg2+': 0.12,
|
|
32
|
-
'Ca2+': 0.07,
|
|
33
|
-
'Cl-': 0.07,
|
|
34
|
-
'NO2-': 0.05,
|
|
35
|
-
'NO3-': 0.11,
|
|
36
|
-
'SO42-': 0.08,
|
|
37
|
-
}
|
|
38
|
-
_mdl.update(self._oth_set.get('mdl', {}))
|
|
39
|
-
|
|
40
|
-
def _se_le(_df_, _log=False):
|
|
41
|
-
_df_ = np.log10(_df_) if _log else _df_
|
|
42
|
-
|
|
43
|
-
_df_qua = _df_.quantile([.25, .75])
|
|
44
|
-
_df_q1, _df_q3 = _df_qua.loc[.25].copy(), _df_qua.loc[.75].copy()
|
|
45
|
-
_df_iqr = _df_q3 - _df_q1
|
|
46
|
-
|
|
47
|
-
_se = concat([_df_q1 - 1.5 * _df_iqr] * len(_df_), axis=1).T.set_index(_df_.index)
|
|
48
|
-
_le = concat([_df_q3 + 1.5 * _df_iqr] * len(_df_), axis=1).T.set_index(_df_.index)
|
|
49
|
-
|
|
50
|
-
if _log:
|
|
51
|
-
return 10 ** _se, 10 ** _le
|
|
52
|
-
return _se, _le
|
|
53
|
-
|
|
54
|
-
_cation, _anion, _main = ['Na+', 'NH4+', 'K+', 'Mg2+', 'Ca2+'], ['Cl-', 'NO2-', 'NO3-', 'SO42-', ], ['SO42-',
|
|
55
|
-
'NO3-',
|
|
56
|
-
'NH4+']
|
|
57
|
-
|
|
58
|
-
_df_salt = _df[_mdl.keys()].copy()
|
|
59
|
-
_df_pm = _df['PM2.5'].copy()
|
|
60
|
-
|
|
61
|
-
## lower than PM2.5
|
|
62
|
-
## conc. of main salt should be present at the same time (NH4+, SO42-, NO3-)
|
|
63
|
-
_df_salt = _df_salt.mask(_df_salt.sum(axis=1, min_count=1) > _df_pm).dropna(subset=_main).copy()
|
|
64
|
-
|
|
65
|
-
## mdl
|
|
66
|
-
for (_key, _df_col), _mdl_val in zip(_df_salt.items(), _mdl.values()):
|
|
67
|
-
_df_salt[_key] = _df_col.mask(_df_col < _mdl_val, _mdl_val / 2)
|
|
68
|
-
|
|
69
|
-
## calculate SE LE
|
|
70
|
-
## salt < LE
|
|
71
|
-
_se, _le = _se_le(_df_salt, _log=True)
|
|
72
|
-
_df_salt = _df_salt.mask(_df_salt > _le).copy()
|
|
73
|
-
|
|
74
|
-
## C/A, A/C
|
|
75
|
-
_rat_CA = (_df_salt[_cation].sum(axis=1) / _df_salt[_anion].sum(axis=1)).to_frame()
|
|
76
|
-
_rat_AC = (1 / _rat_CA).copy()
|
|
77
|
-
|
|
78
|
-
_se, _le = _se_le(_rat_CA, )
|
|
79
|
-
_cond_CA = (_rat_CA < _le) & (_rat_CA > 0)
|
|
80
|
-
|
|
81
|
-
_se, _le = _se_le(_rat_AC, )
|
|
82
|
-
_cond_AC = (_rat_AC < _le) & (_rat_AC > 0)
|
|
83
|
-
|
|
84
|
-
_df_salt = _df_salt.where((_cond_CA * _cond_AC)[0]).copy()
|
|
85
|
-
|
|
86
|
-
## conc. of main salt > SE
|
|
87
|
-
_se, _le = _se_le(_df_salt[_main], _log=True)
|
|
88
|
-
_df_salt[_main] = _df_salt[_main].mask(_df_salt[_main] < _se).copy()
|
|
89
|
-
|
|
90
|
-
return _df_salt.reindex(_df.index)
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
from pandas import to_datetime, read_csv
|
|
2
|
-
|
|
3
|
-
from AeroViz.rawDataReader.core import AbstractReader
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Reader(AbstractReader):
|
|
7
|
-
nam = 'OCEC_LCRES'
|
|
8
|
-
|
|
9
|
-
def _raw_reader(self, _file):
|
|
10
|
-
with open(_file, 'r', encoding='utf-8', errors='ignore') as f:
|
|
11
|
-
_df = read_csv(f, skiprows=3)
|
|
12
|
-
|
|
13
|
-
_col = {'Thermal/Optical OC (ugC/LCm^3)': 'Thermal_OC',
|
|
14
|
-
'Thermal/Optical EC (ugC/LCm^3)': 'Thermal_EC',
|
|
15
|
-
'OC=TC-BC (ugC/LCm^3)': 'Optical_OC',
|
|
16
|
-
'BC (ugC/LCm^3)': 'Optical_EC',
|
|
17
|
-
'Sample Volume Local Condition Actual m^3': 'Sample_Volume',
|
|
18
|
-
'TC (ugC/LCm^3)': 'TC', }
|
|
19
|
-
|
|
20
|
-
_tm_idx = to_datetime(_df['Start Date/Time'], errors='coerce')
|
|
21
|
-
_df['time'] = _tm_idx
|
|
22
|
-
|
|
23
|
-
_df = _df.dropna(subset='time').loc[~_tm_idx.duplicated()].set_index('time')
|
|
24
|
-
|
|
25
|
-
return _df[_col.keys()].rename(columns=_col)
|
|
26
|
-
|
|
27
|
-
## QC data
|
|
28
|
-
def _QC(self, _df):
|
|
29
|
-
_df[['Thermal_OC', 'Optical_OC']] = _df[['Thermal_OC', 'Optical_OC']].where(
|
|
30
|
-
_df[['Thermal_OC', 'Optical_OC']] > 0.3).copy()
|
|
31
|
-
_df[['Thermal_EC', 'Optical_EC']] = _df[['Thermal_EC', 'Optical_EC']].where(
|
|
32
|
-
_df[['Thermal_EC', 'Optical_EC']] > .015).copy()
|
|
33
|
-
|
|
34
|
-
return _df
|