AeroViz 0.1.3b0__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 +5 -3
- AeroViz/{config → data}/DEFAULT_DATA.csv +1 -1
- AeroViz/dataProcess/Chemistry/__init__.py +7 -7
- AeroViz/dataProcess/Chemistry/_isoropia.py +5 -2
- AeroViz/dataProcess/Chemistry/_mass_volume.py +15 -18
- AeroViz/dataProcess/Chemistry/_ocec.py +2 -2
- AeroViz/dataProcess/Chemistry/_teom.py +2 -1
- AeroViz/dataProcess/Chemistry/isrpia.cnf +21 -0
- AeroViz/dataProcess/Optical/Angstrom_exponent.py +20 -0
- AeroViz/dataProcess/Optical/_IMPROVE.py +13 -15
- AeroViz/dataProcess/Optical/__init__.py +15 -30
- AeroViz/dataProcess/Optical/_absorption.py +21 -47
- AeroViz/dataProcess/Optical/_extinction.py +20 -15
- AeroViz/dataProcess/Optical/_mie.py +0 -1
- AeroViz/dataProcess/Optical/_scattering.py +19 -20
- AeroViz/dataProcess/SizeDistr/__init__.py +7 -7
- AeroViz/dataProcess/SizeDistr/_merge.py +2 -2
- AeroViz/dataProcess/SizeDistr/_merge_v1.py +2 -2
- AeroViz/dataProcess/SizeDistr/_merge_v2.py +2 -2
- AeroViz/dataProcess/SizeDistr/_merge_v3.py +1 -1
- AeroViz/dataProcess/SizeDistr/_merge_v4.py +1 -1
- AeroViz/dataProcess/VOC/__init__.py +3 -3
- AeroViz/dataProcess/__init__.py +28 -6
- AeroViz/dataProcess/core/__init__.py +10 -17
- AeroViz/plot/__init__.py +1 -1
- AeroViz/plot/box.py +2 -1
- AeroViz/plot/optical/optical.py +4 -4
- AeroViz/plot/regression.py +25 -39
- AeroViz/plot/scatter.py +68 -2
- AeroViz/plot/templates/__init__.py +2 -1
- AeroViz/plot/templates/ammonium_rich.py +34 -0
- AeroViz/plot/templates/diurnal_pattern.py +11 -9
- AeroViz/plot/templates/koschmieder.py +51 -115
- AeroViz/plot/templates/metal_heatmap.py +115 -17
- AeroViz/plot/timeseries/__init__.py +1 -0
- AeroViz/plot/timeseries/template.py +47 -0
- AeroViz/plot/timeseries/timeseries.py +275 -208
- AeroViz/plot/utils/plt_utils.py +2 -2
- AeroViz/plot/utils/units.json +5 -0
- AeroViz/plot/violin.py +9 -8
- AeroViz/process/__init__.py +2 -2
- AeroViz/process/script/AbstractDistCalc.py +1 -1
- AeroViz/process/script/Chemical.py +5 -4
- AeroViz/process/script/Others.py +1 -1
- AeroViz/rawDataReader/__init__.py +17 -22
- AeroViz/rawDataReader/{utils/config.py → config/supported_instruments.py} +38 -52
- AeroViz/rawDataReader/core/__init__.py +104 -229
- AeroViz/rawDataReader/script/AE33.py +10 -11
- AeroViz/rawDataReader/script/AE43.py +8 -11
- AeroViz/rawDataReader/script/APS_3321.py +6 -6
- AeroViz/rawDataReader/script/Aurora.py +18 -19
- AeroViz/rawDataReader/script/BC1054.py +11 -15
- AeroViz/rawDataReader/script/EPA_vertical.py +35 -7
- AeroViz/rawDataReader/script/GRIMM.py +2 -9
- AeroViz/rawDataReader/script/{IGAC_ZM.py → IGAC.py} +17 -17
- AeroViz/rawDataReader/script/MA350.py +7 -14
- AeroViz/rawDataReader/script/Minion.py +103 -0
- AeroViz/rawDataReader/script/NEPH.py +24 -29
- AeroViz/rawDataReader/script/SMPS_TH.py +4 -4
- AeroViz/rawDataReader/script/SMPS_aim11.py +6 -6
- AeroViz/rawDataReader/script/SMPS_genr.py +6 -6
- AeroViz/rawDataReader/script/Sunset_OCEC.py +60 -0
- AeroViz/rawDataReader/script/TEOM.py +8 -6
- AeroViz/rawDataReader/script/Table.py +7 -8
- AeroViz/rawDataReader/script/VOC.py +26 -0
- AeroViz/rawDataReader/script/__init__.py +10 -12
- AeroViz/tools/database.py +7 -9
- AeroViz/tools/datareader.py +3 -3
- {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.4.dist-info}/METADATA +1 -1
- AeroViz-0.1.4.dist-info/RECORD +112 -0
- AeroViz/rawDataReader/script/IGAC_TH.py +0 -104
- 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-0.1.3b0.dist-info/RECORD +0 -110
- /AeroViz/{config → data}/DEFAULT_PNSD_DATA.csv +0 -0
- /AeroViz/rawDataReader/{utils → config}/__init__.py +0 -0
- {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.4.dist-info}/LICENSE +0 -0
- {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.4.dist-info}/WHEEL +0 -0
- {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.4.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from typing import Literal
|
|
2
1
|
|
|
3
2
|
import matplotlib.pyplot as plt
|
|
4
3
|
import numpy as np
|
|
@@ -11,146 +10,83 @@ from AeroViz.plot.utils import *
|
|
|
11
10
|
__all__ = ['koschmieder']
|
|
12
11
|
|
|
13
12
|
|
|
14
|
-
@set_figure
|
|
13
|
+
@set_figure
|
|
15
14
|
def koschmieder(df: pd.DataFrame,
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
vis: str,
|
|
16
|
+
ext: list[str],
|
|
18
17
|
ax: Axes | None = None,
|
|
19
|
-
**kwargs
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
y_log = np.log(y)
|
|
18
|
+
**kwargs
|
|
19
|
+
) -> tuple[Figure, Axes]:
|
|
20
|
+
"""
|
|
21
|
+
Plot Koschmieder relationship between Visibility and Extinction.
|
|
24
22
|
|
|
23
|
+
x = Visibility, y = Extinction, log-log fit!!
|
|
24
|
+
"""
|
|
25
|
+
def _log_fit(x, y, func=lambda x, a: -x + a):
|
|
26
|
+
x_log, y_log = np.log(x), np.log(y)
|
|
25
27
|
popt, pcov = curve_fit(func, x_log, y_log)
|
|
26
28
|
|
|
27
|
-
residuals = y_log - func(x_log, *popt)
|
|
28
|
-
ss_res = np.sum(residuals ** 2)
|
|
29
|
-
ss_total = np.sum((y_log - np.mean(y_log)) ** 2)
|
|
30
|
-
r_squared = 1 - (ss_res / ss_total)
|
|
31
|
-
print(f'Const_Log = {popt[0].round(3)}')
|
|
32
|
-
print(f'Const = {np.exp(popt)[0].round(3)}')
|
|
33
|
-
print(f'R^2 = {r_squared.round(3)}')
|
|
34
29
|
return np.exp(popt)[0], pcov
|
|
35
30
|
|
|
36
|
-
def _reciprocal_fit(x, y, func=lambda x, a, b: a / (x ** b)):
|
|
37
|
-
popt, pcov = curve_fit(func, x, y)
|
|
38
|
-
|
|
39
|
-
residuals = y - func(x, *popt)
|
|
40
|
-
ss_res = np.sum(residuals ** 2)
|
|
41
|
-
ss_total = np.sum((y - np.mean(y)) ** 2)
|
|
42
|
-
r_squared = 1 - (ss_res / ss_total)
|
|
43
|
-
print(f'Const = {popt.round(3)}')
|
|
44
|
-
print(f' R^2 = {r_squared.round(3)}')
|
|
45
|
-
return popt, pcov
|
|
46
|
-
|
|
47
31
|
fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
|
|
48
32
|
|
|
49
|
-
_df1 = df[['Extinction', 'ExtinctionByGas', y]].dropna().copy()
|
|
50
|
-
_df2 = df[['total_ext_dry', 'ExtinctionByGas', y]].dropna().copy()
|
|
51
|
-
|
|
52
|
-
x_data1 = _df1[y]
|
|
53
|
-
y_data1 = _df1['Extinction'] + _df1['ExtinctionByGas']
|
|
54
|
-
|
|
55
|
-
x_data2 = _df2[y]
|
|
56
|
-
y_data2 = _df2['total_ext_dry'] + _df2['ExtinctionByGas']
|
|
57
|
-
|
|
58
|
-
para_coeff = []
|
|
59
33
|
boxcolors = ['#3f83bf', '#a5bf6b']
|
|
34
|
+
scattercolor = ['blue', 'green']
|
|
35
|
+
arts = []
|
|
36
|
+
labels = []
|
|
60
37
|
|
|
61
|
-
for i,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
df_grp = df_.groupby(f'{y}')
|
|
66
|
-
|
|
67
|
-
vals, median_vals, vis = [], [], []
|
|
68
|
-
for j, (name, subdf) in enumerate(df_grp):
|
|
69
|
-
if len(subdf['Total_Ext'].dropna()) > 20:
|
|
70
|
-
vis.append('{:.0f}'.format(name))
|
|
71
|
-
vals.append(subdf['Total_Ext'].dropna().values)
|
|
72
|
-
median_vals.append(subdf['Total_Ext'].dropna().median())
|
|
38
|
+
for i, ext_col in enumerate(ext):
|
|
39
|
+
_df = df[[ext_col, vis]].dropna().copy()
|
|
40
|
+
x_data = _df[vis]
|
|
41
|
+
y_data = _df[ext_col]
|
|
73
42
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
boxprops=dict(facecolor=boxcolors[i], alpha=.7),
|
|
77
|
-
meanprops=dict(marker='o', markerfacecolor='white', markeredgecolor='k', markersize=4),
|
|
78
|
-
medianprops=dict(color='#000000', ls='-'))
|
|
43
|
+
bins = np.linspace(0, 50, 25)
|
|
44
|
+
wid = (bins + (bins[1] - bins[0]) / 2)[0:-1]
|
|
79
45
|
|
|
80
|
-
|
|
46
|
+
_df[f'{vis}_bins'] = pd.cut(x_data, bins=bins, labels=wid)
|
|
81
47
|
|
|
82
|
-
|
|
83
|
-
bins = np.linspace(0, 70, 36)
|
|
84
|
-
wid = (bins + (bins[1] - bins[0]) / 2)[0:-1]
|
|
48
|
+
grouped = _df.groupby(f'{vis}_bins', observed=False)
|
|
85
49
|
|
|
86
|
-
|
|
50
|
+
vis_labels, vals, median_vals = [], [], []
|
|
51
|
+
for _, subdf in grouped:
|
|
52
|
+
if len(subdf[ext_col].dropna()) > 3:
|
|
53
|
+
vis_labels.append(subdf[vis].mean())
|
|
54
|
+
vals.append(subdf[ext_col].dropna().values)
|
|
55
|
+
median_vals.append(subdf[ext_col].mean())
|
|
87
56
|
|
|
88
|
-
|
|
57
|
+
plt.boxplot(vals, labels=vis_labels, positions=np.array(vis_labels, dtype='float'),
|
|
58
|
+
widths=(bins[1] - bins[0]) / 2.5,
|
|
59
|
+
showfliers=False, showmeans=True, meanline=False, patch_artist=True,
|
|
60
|
+
boxprops=dict(facecolor=boxcolors[i], alpha=.7),
|
|
61
|
+
meanprops=dict(marker='o', markerfacecolor='white', markeredgecolor='k', markersize=4),
|
|
62
|
+
medianprops=dict(color='#000000', ls='-'))
|
|
89
63
|
|
|
90
|
-
|
|
91
|
-
for j, (name, subdf) in enumerate(grouped):
|
|
92
|
-
if len(subdf['Total_Ext'].dropna()) > 20:
|
|
93
|
-
vis.append('{:.1f}'.format(name))
|
|
94
|
-
vals.append(subdf['Total_Ext'].dropna().values)
|
|
95
|
-
median_vals.append(subdf['Total_Ext'].dropna().mean())
|
|
96
|
-
|
|
97
|
-
plt.boxplot(vals, labels=vis, positions=np.array(vis, dtype='float'), widths=(bins[1] - bins[0]) / 2.5,
|
|
98
|
-
showfliers=False, showmeans=True, meanline=False, patch_artist=True,
|
|
99
|
-
boxprops=dict(facecolor=boxcolors[i], alpha=.7),
|
|
100
|
-
meanprops=dict(marker='o', markerfacecolor='white', markeredgecolor='k', markersize=4),
|
|
101
|
-
medianprops=dict(color='#000000', ls='-'))
|
|
102
|
-
|
|
103
|
-
plt.scatter(x_data, y_data, marker='.', s=10, facecolor='white', edgecolor=boxcolors[i], alpha=0.1)
|
|
64
|
+
plt.scatter(x_data, y_data, marker='.', s=10, facecolor='white', edgecolor=boxcolors[i], alpha=0.1)
|
|
104
65
|
|
|
105
66
|
# fit curve
|
|
106
|
-
|
|
107
|
-
_y = np.array(median_vals, dtype='float')
|
|
108
|
-
|
|
109
|
-
if function == 'log':
|
|
110
|
-
func = lambda x, a: a / x
|
|
111
|
-
coeff, pcov = _log_fit(_x, _y)
|
|
112
|
-
|
|
113
|
-
else:
|
|
114
|
-
func = lambda x, a, b: a / (x ** b)
|
|
115
|
-
coeff, pcov = _reciprocal_fit(_x, _y)
|
|
116
|
-
|
|
117
|
-
para_coeff.append(coeff)
|
|
67
|
+
coeff, _ = _log_fit(np.array(vis_labels, dtype='float'), np.array(median_vals, dtype='float'))
|
|
118
68
|
|
|
119
|
-
|
|
120
|
-
|
|
69
|
+
# Plot lines (ref & Measurement)
|
|
70
|
+
x_fit = np.linspace(0.1, 50, 1000)
|
|
121
71
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
72
|
+
func = lambda x, a: a / x
|
|
73
|
+
line, = ax.plot(x_fit, func(x_fit, coeff), c=scattercolor[i], lw=3,
|
|
74
|
+
label=f'Vis (km) = {round(coeff)} / Ext')
|
|
125
75
|
|
|
126
|
-
|
|
127
|
-
|
|
76
|
+
arts.append(line)
|
|
77
|
+
labels.append(f'Vis (km) = {round(coeff)} / Ext')
|
|
128
78
|
|
|
129
|
-
|
|
130
|
-
x_fit = np.linspace(0.1, 70, 1000)
|
|
131
|
-
line1, = ax.plot(x_fit, func(x_fit, *para_coeff[0]), c='b', lw=3)
|
|
132
|
-
line2, = ax.plot(x_fit, func(x_fit, *para_coeff[1]), c='g', lw=3)
|
|
79
|
+
ax.legend(handles=arts, labels=labels, loc='upper right', prop=dict(weight='bold'), bbox_to_anchor=(0.99, 0.99))
|
|
133
80
|
|
|
134
|
-
|
|
135
|
-
|
|
81
|
+
ax.set(xlabel=kwargs.get('xlim', 'Visibility (km)'),
|
|
82
|
+
ylabel=kwargs.get('xlim', 'Extinction (1/Mm)'),
|
|
83
|
+
title=kwargs.get('ylim', 'Koschmieder relationship'),
|
|
84
|
+
xlim=kwargs.get('xlim', (0, 30)),
|
|
85
|
+
ylim=kwargs.get('ylim', (0, 500))
|
|
86
|
+
)
|
|
136
87
|
|
|
137
|
-
plt.
|
|
138
|
-
bbox_to_anchor=(0.99, 0.99))
|
|
139
|
-
|
|
140
|
-
plt.xticks(ticks=np.array(range(0, 51, 5)), labels=np.array(range(0, 51, 5)))
|
|
141
|
-
plt.xlim(0, 50)
|
|
142
|
-
plt.ylim(0, 700)
|
|
143
|
-
plt.title(r'$\bf Koschmieder\ relationship$')
|
|
144
|
-
plt.xlabel(f'{y} (km)')
|
|
145
|
-
plt.ylabel(r'$\bf Extinction\ coefficient\ (1/Mm)$')
|
|
88
|
+
plt.xticks(ticks=np.array(range(0, 31, 5)), labels=np.array(range(0, 31, 5)))
|
|
146
89
|
|
|
147
90
|
plt.show()
|
|
148
91
|
|
|
149
92
|
return fig, ax
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if __name__ == '__main__':
|
|
153
|
-
from AeroViz.tools import DataBase
|
|
154
|
-
|
|
155
|
-
koschmieder(DataBase(), 'Vis_LPV', 'log')
|
|
156
|
-
# koschmieder(DataBase, 'Vis_Naked', 'reciprocal')
|
|
@@ -2,41 +2,139 @@ import matplotlib.pyplot as plt
|
|
|
2
2
|
import numpy as np
|
|
3
3
|
import seaborn as sns
|
|
4
4
|
from matplotlib.pyplot import Figure, Axes
|
|
5
|
-
from pandas import DataFrame, date_range
|
|
5
|
+
from pandas import DataFrame, date_range, concat
|
|
6
6
|
from sklearn.preprocessing import StandardScaler
|
|
7
7
|
|
|
8
8
|
from AeroViz.plot.utils import *
|
|
9
9
|
|
|
10
|
+
__all__ = ['metal_heatmaps', 'process_data_with_two_df']
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def process_data(df, detected_limit=True, outlier_threshold=5, smoothing_window=6, fill_method='MDL'):
|
|
14
|
+
# Fill missing values based on the specified method
|
|
15
|
+
df = fill_missing_values(df.copy(), method=fill_method)
|
|
10
16
|
|
|
11
|
-
def process_data(df):
|
|
12
|
-
# detected_limit = 0.0001
|
|
13
|
-
df = df.where(df >= 0.0001, np.nan)
|
|
14
17
|
# Normalize the data
|
|
15
|
-
df =
|
|
18
|
+
df = normalize_data(df)
|
|
19
|
+
|
|
16
20
|
# Remove outliers
|
|
17
|
-
df =
|
|
18
|
-
|
|
21
|
+
df = remove_outliers(df, threshold=outlier_threshold)
|
|
22
|
+
|
|
23
|
+
# Interpolate missing values
|
|
19
24
|
df = df.interpolate(method='linear')
|
|
25
|
+
|
|
20
26
|
# Smooth the data
|
|
21
|
-
df = df
|
|
27
|
+
df = smooth_data(df, window=smoothing_window)
|
|
22
28
|
|
|
23
29
|
return df
|
|
24
30
|
|
|
25
31
|
|
|
32
|
+
def process_data_with_two_df(df, df2, outlier_threshold=5, smoothing_window=6, fill_method='MDL'):
|
|
33
|
+
# Shift the first DataFrame by 30 minutes
|
|
34
|
+
df = df.shift(freq='30min')
|
|
35
|
+
|
|
36
|
+
# Fill missing values for both DataFrames
|
|
37
|
+
df = fill_missing_values(df.copy(), method=fill_method)
|
|
38
|
+
df2 = fill_missing_values(df2.copy(), method=fill_method)
|
|
39
|
+
|
|
40
|
+
# Normalize both DataFrames together
|
|
41
|
+
df, df2 = normalize_and_split(df, df2)
|
|
42
|
+
|
|
43
|
+
# Shift the first DataFrame back by 30 minutes
|
|
44
|
+
df = df.shift(freq='-30min')
|
|
45
|
+
|
|
46
|
+
# Remove outliers for both DataFrames
|
|
47
|
+
df = remove_outliers(df, threshold=outlier_threshold)
|
|
48
|
+
df2 = remove_outliers(df2, threshold=outlier_threshold)
|
|
49
|
+
|
|
50
|
+
# Interpolate missing values
|
|
51
|
+
df = df.interpolate(method='linear')
|
|
52
|
+
df2 = df2.interpolate(method='linear')
|
|
53
|
+
|
|
54
|
+
# Smooth the data
|
|
55
|
+
df = smooth_data(df, window=smoothing_window)
|
|
56
|
+
df2 = smooth_data(df2, window=smoothing_window)
|
|
57
|
+
|
|
58
|
+
return df, df2
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def fill_missing_values(df, method='MDL'):
|
|
62
|
+
if method == 'interpolate':
|
|
63
|
+
return df.interpolate(method='linear')
|
|
64
|
+
else:
|
|
65
|
+
return fill_with_mdl(df)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def fill_with_mdl(df):
|
|
69
|
+
# Minimum detection limit (MDL) dictionary
|
|
70
|
+
MDL = {
|
|
71
|
+
'Al': 100, 'Si': 18, 'P': 5.2, 'S': 3.2,
|
|
72
|
+
'Cl': 1.7, 'K': 1.2, 'Ca': 0.3, 'Ti': 1.6,
|
|
73
|
+
'V': 0.12, 'Cr': 0.12, 'Mn': 0.14, 'Fe': 0.17,
|
|
74
|
+
'Co': 0.14, 'Ni': 0.096, 'Cu': 0.079, 'Zn': 0.067,
|
|
75
|
+
'Ga': 0.059, 'Ge': 0.056, 'As': 0.063, 'Se': 0.081,
|
|
76
|
+
'Br': 0.1, 'Rb': 0.19, 'Sr': 0.22, 'Y': 0.28,
|
|
77
|
+
'Zr': 0.33, 'Nb': 0.41, 'Mo': 0.48, 'Pd': 2.2,
|
|
78
|
+
'Ag': 1.9, 'Cd': 2.5, 'In': 3.1, 'Sn': 4.1,
|
|
79
|
+
'Sb': 5.2, 'Te': 0.6, 'I': 0.49, 'Cs': 0.37,
|
|
80
|
+
'Ba': 0.39, 'La': 0.36, 'Ce': 0.3, 'Pt': 0.12,
|
|
81
|
+
'Au': 0.1, 'Hg': 0.12, 'Tl': 0.12, 'Pb': 0.13,
|
|
82
|
+
'Bi': 0.13
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# Replace values below MDL with 5/6 * MDL
|
|
86
|
+
for element, threshold in MDL.items():
|
|
87
|
+
if element in df.columns:
|
|
88
|
+
df.loc[:, element] = df[element].where(df[element] >= threshold, 5 / 6 * threshold)
|
|
89
|
+
|
|
90
|
+
return df
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def normalize_data(df):
|
|
94
|
+
# Standardize the data (z-score normalization)
|
|
95
|
+
return DataFrame(StandardScaler().fit_transform(df), index=df.index, columns=df.columns)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def remove_outliers(df, threshold=5):
|
|
99
|
+
# Remove rows where any column value exceeds the threshold
|
|
100
|
+
return df[(np.abs(df) < threshold)]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def smooth_data(df, window=6):
|
|
104
|
+
# Apply rolling mean to smooth the data
|
|
105
|
+
return df.rolling(window=window, min_periods=1).mean()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def normalize_and_split(df, df2):
|
|
109
|
+
# Concatenate DataFrames for combined normalization
|
|
110
|
+
combined_df = concat([df, df2])
|
|
111
|
+
normalized_combined_df = normalize_data(combined_df)
|
|
112
|
+
|
|
113
|
+
# Split the normalized DataFrame back into df and df2
|
|
114
|
+
df = normalized_combined_df.loc[df.index]
|
|
115
|
+
df2 = normalized_combined_df.loc[df2.index]
|
|
116
|
+
|
|
117
|
+
return df, df2
|
|
118
|
+
|
|
119
|
+
|
|
26
120
|
@set_figure(figsize=(12, 3), fs=6)
|
|
27
|
-
def metal_heatmaps(df,
|
|
121
|
+
def metal_heatmaps(df,
|
|
122
|
+
process=True,
|
|
123
|
+
major_freq='24h',
|
|
124
|
+
minor_freq='12h',
|
|
125
|
+
cmap='jet',
|
|
126
|
+
ax: Axes | None = None,
|
|
127
|
+
**kwargs
|
|
28
128
|
) -> tuple[Figure, Axes]:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
'As', 'Co', 'Se', 'Br', 'Cd', 'Sb', 'In', 'Pb', 'Ni']
|
|
32
|
-
|
|
33
|
-
df = df[items]
|
|
129
|
+
if process:
|
|
130
|
+
df = process_data(df)
|
|
34
131
|
|
|
35
132
|
fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
|
|
36
133
|
|
|
37
|
-
sns.heatmap(df.T, vmax=3, cmap=
|
|
38
|
-
cbar_kws={'label': 'Z score'})
|
|
134
|
+
sns.heatmap(df.T, vmin=None, vmax=3, cmap=cmap, xticklabels=False, yticklabels=True,
|
|
135
|
+
cbar_kws={'label': 'Z score', "pad": 0.02})
|
|
39
136
|
ax.grid(color='gray', linestyle='-', linewidth=0.3)
|
|
137
|
+
|
|
40
138
|
# Set x-tick positions and labels
|
|
41
139
|
major_tick = date_range(start=df.index[0], end=df.index[-1], freq=major_freq)
|
|
42
140
|
minor_tick = date_range(start=df.index[0], end=df.index[-1], freq=minor_freq)
|
|
@@ -47,9 +145,9 @@ def metal_heatmaps(df, major_freq='24h', minor_freq='12h', ax: Axes | None = Non
|
|
|
47
145
|
ax.set_xticklabels(major_tick.strftime('%F'))
|
|
48
146
|
ax.tick_params(axis='y', rotation=0)
|
|
49
147
|
|
|
50
|
-
ax.set_title(f"{title}", fontsize=10)
|
|
51
148
|
ax.set(xlabel='',
|
|
52
149
|
ylabel='',
|
|
150
|
+
title=kwargs.get('title', None)
|
|
53
151
|
)
|
|
54
152
|
|
|
55
153
|
plt.show()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
from matplotlib.pyplot import Figure, Axes
|
|
3
|
+
from pandas import DataFrame
|
|
4
|
+
|
|
5
|
+
from AeroViz.plot.timeseries import timeseries
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def timeseries_template(df: DataFrame) -> tuple[Figure, Axes]:
|
|
9
|
+
fig, ax = plt.subplots(5, 1, figsize=(len(df.index) * 0.01, 4))
|
|
10
|
+
(ax1, ax2, ax3, ax4, ax5) = ax
|
|
11
|
+
|
|
12
|
+
timeseries(df,
|
|
13
|
+
y=['Extinction', 'Scattering', 'Absorption'],
|
|
14
|
+
rolling=30,
|
|
15
|
+
ax=ax1,
|
|
16
|
+
ylabel='Coefficient',
|
|
17
|
+
ylim=[0., None],
|
|
18
|
+
set_xaxis_visible=False,
|
|
19
|
+
legend_ncol=3,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Temp, RH
|
|
23
|
+
timeseries(df,
|
|
24
|
+
y='AT',
|
|
25
|
+
y2='RH',
|
|
26
|
+
rolling=30,
|
|
27
|
+
ax=ax2,
|
|
28
|
+
ax_plot_kws=dict(color='r'),
|
|
29
|
+
ax2_plot_kws=dict(color='b'),
|
|
30
|
+
ylim=[10, 30],
|
|
31
|
+
ylim2=[20, 100],
|
|
32
|
+
set_xaxis_visible=False,
|
|
33
|
+
legend_ncol=2,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
timeseries(df, y='WS', color='WD', style='scatter', ax=ax3, scatter_kws=dict(cmap='hsv'),
|
|
37
|
+
cbar_kws=dict(ticks=[0, 90, 180, 270, 360]),
|
|
38
|
+
ylim=[0, None], set_xaxis_visible=False)
|
|
39
|
+
|
|
40
|
+
timeseries(df, y='VC', color='PBLH', style='bar', ax=ax4, bar_kws=dict(cmap='Blues'), set_xaxis_visible=False,
|
|
41
|
+
ylim=[0, 5000])
|
|
42
|
+
|
|
43
|
+
timeseries(df, y='PM25', color='PM1/PM25', style='scatter', ax=ax5, ylim=[0, None])
|
|
44
|
+
|
|
45
|
+
plt.show()
|
|
46
|
+
|
|
47
|
+
return fig, ax
|