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.

Files changed (81) hide show
  1. AeroViz/__init__.py +5 -3
  2. AeroViz/{config → data}/DEFAULT_DATA.csv +1 -1
  3. AeroViz/dataProcess/Chemistry/__init__.py +7 -7
  4. AeroViz/dataProcess/Chemistry/_isoropia.py +5 -2
  5. AeroViz/dataProcess/Chemistry/_mass_volume.py +15 -18
  6. AeroViz/dataProcess/Chemistry/_ocec.py +2 -2
  7. AeroViz/dataProcess/Chemistry/_teom.py +2 -1
  8. AeroViz/dataProcess/Chemistry/isrpia.cnf +21 -0
  9. AeroViz/dataProcess/Optical/Angstrom_exponent.py +20 -0
  10. AeroViz/dataProcess/Optical/_IMPROVE.py +13 -15
  11. AeroViz/dataProcess/Optical/__init__.py +15 -30
  12. AeroViz/dataProcess/Optical/_absorption.py +21 -47
  13. AeroViz/dataProcess/Optical/_extinction.py +20 -15
  14. AeroViz/dataProcess/Optical/_mie.py +0 -1
  15. AeroViz/dataProcess/Optical/_scattering.py +19 -20
  16. AeroViz/dataProcess/SizeDistr/__init__.py +7 -7
  17. AeroViz/dataProcess/SizeDistr/_merge.py +2 -2
  18. AeroViz/dataProcess/SizeDistr/_merge_v1.py +2 -2
  19. AeroViz/dataProcess/SizeDistr/_merge_v2.py +2 -2
  20. AeroViz/dataProcess/SizeDistr/_merge_v3.py +1 -1
  21. AeroViz/dataProcess/SizeDistr/_merge_v4.py +1 -1
  22. AeroViz/dataProcess/VOC/__init__.py +3 -3
  23. AeroViz/dataProcess/__init__.py +28 -6
  24. AeroViz/dataProcess/core/__init__.py +10 -17
  25. AeroViz/plot/__init__.py +1 -1
  26. AeroViz/plot/box.py +2 -1
  27. AeroViz/plot/optical/optical.py +4 -4
  28. AeroViz/plot/regression.py +25 -39
  29. AeroViz/plot/scatter.py +68 -2
  30. AeroViz/plot/templates/__init__.py +2 -1
  31. AeroViz/plot/templates/ammonium_rich.py +34 -0
  32. AeroViz/plot/templates/diurnal_pattern.py +11 -9
  33. AeroViz/plot/templates/koschmieder.py +51 -115
  34. AeroViz/plot/templates/metal_heatmap.py +115 -17
  35. AeroViz/plot/timeseries/__init__.py +1 -0
  36. AeroViz/plot/timeseries/template.py +47 -0
  37. AeroViz/plot/timeseries/timeseries.py +275 -208
  38. AeroViz/plot/utils/plt_utils.py +2 -2
  39. AeroViz/plot/utils/units.json +5 -0
  40. AeroViz/plot/violin.py +9 -8
  41. AeroViz/process/__init__.py +2 -2
  42. AeroViz/process/script/AbstractDistCalc.py +1 -1
  43. AeroViz/process/script/Chemical.py +5 -4
  44. AeroViz/process/script/Others.py +1 -1
  45. AeroViz/rawDataReader/__init__.py +17 -22
  46. AeroViz/rawDataReader/{utils/config.py → config/supported_instruments.py} +38 -52
  47. AeroViz/rawDataReader/core/__init__.py +104 -229
  48. AeroViz/rawDataReader/script/AE33.py +10 -11
  49. AeroViz/rawDataReader/script/AE43.py +8 -11
  50. AeroViz/rawDataReader/script/APS_3321.py +6 -6
  51. AeroViz/rawDataReader/script/Aurora.py +18 -19
  52. AeroViz/rawDataReader/script/BC1054.py +11 -15
  53. AeroViz/rawDataReader/script/EPA_vertical.py +35 -7
  54. AeroViz/rawDataReader/script/GRIMM.py +2 -9
  55. AeroViz/rawDataReader/script/{IGAC_ZM.py → IGAC.py} +17 -17
  56. AeroViz/rawDataReader/script/MA350.py +7 -14
  57. AeroViz/rawDataReader/script/Minion.py +103 -0
  58. AeroViz/rawDataReader/script/NEPH.py +24 -29
  59. AeroViz/rawDataReader/script/SMPS_TH.py +4 -4
  60. AeroViz/rawDataReader/script/SMPS_aim11.py +6 -6
  61. AeroViz/rawDataReader/script/SMPS_genr.py +6 -6
  62. AeroViz/rawDataReader/script/Sunset_OCEC.py +60 -0
  63. AeroViz/rawDataReader/script/TEOM.py +8 -6
  64. AeroViz/rawDataReader/script/Table.py +7 -8
  65. AeroViz/rawDataReader/script/VOC.py +26 -0
  66. AeroViz/rawDataReader/script/__init__.py +10 -12
  67. AeroViz/tools/database.py +7 -9
  68. AeroViz/tools/datareader.py +3 -3
  69. {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.4.dist-info}/METADATA +1 -1
  70. AeroViz-0.1.4.dist-info/RECORD +112 -0
  71. AeroViz/rawDataReader/script/IGAC_TH.py +0 -104
  72. AeroViz/rawDataReader/script/OCEC_LCRES.py +0 -34
  73. AeroViz/rawDataReader/script/OCEC_RES.py +0 -28
  74. AeroViz/rawDataReader/script/VOC_TH.py +0 -30
  75. AeroViz/rawDataReader/script/VOC_ZM.py +0 -37
  76. AeroViz-0.1.3b0.dist-info/RECORD +0 -110
  77. /AeroViz/{config → data}/DEFAULT_PNSD_DATA.csv +0 -0
  78. /AeroViz/rawDataReader/{utils → config}/__init__.py +0 -0
  79. {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.4.dist-info}/LICENSE +0 -0
  80. {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.4.dist-info}/WHEEL +0 -0
  81. {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(fs=12)
13
+ @set_figure
15
14
  def koschmieder(df: pd.DataFrame,
16
- y: Literal['Vis_Naked', 'Vis_LPV'],
17
- function: Literal['log', 'reciprocal'] = 'log',
15
+ vis: str,
16
+ ext: list[str],
18
17
  ax: Axes | None = None,
19
- **kwargs) -> tuple[Figure, Axes]:
20
- # x = Visibility, y = Extinction, log-log fit!!
21
- def _log_fit(x, y, func=lambda x, a: -x + a):
22
- x_log = np.log(x)
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, (df_, x_data, y_data) in enumerate(zip([_df1, _df2], [x_data1, x_data2], [y_data1, y_data2])):
62
- df_['Total_Ext'] = y_data
63
-
64
- if y == 'Vis_Naked':
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
- plt.boxplot(vals, labels=vis, positions=np.array(vis, dtype='int'), widths=0.4,
75
- showfliers=False, showmeans=True, meanline=False, patch_artist=True,
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
- plt.scatter(x_data, y_data, marker='.', s=10, facecolor='white', edgecolor=boxcolors[i], alpha=0.1)
46
+ _df[f'{vis}_bins'] = pd.cut(x_data, bins=bins, labels=wid)
81
47
 
82
- if y == 'Vis_LPV':
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
- df_[f'{x_data.name}' + '_bins'] = pd.cut(x=x_data, bins=bins, labels=wid)
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
- grouped = df_.groupby(f'{x_data.name}' + '_bins', observed=False)
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
- vals, median_vals, vis = [], [], []
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
- _x = np.array(vis, dtype='float')
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
- # Plot lines (ref & Measurement)
120
- x_fit = np.linspace(0.1, 70, 1000)
69
+ # Plot lines (ref & Measurement)
70
+ x_fit = np.linspace(0.1, 50, 1000)
121
71
 
122
- if function == 'log':
123
- line1, = ax.plot(x_fit, func(x_fit, para_coeff[0]), c='b', lw=3)
124
- line2, = ax.plot(x_fit, func(x_fit, para_coeff[1]), c='g', lw=3)
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
- labels = ['Vis (km) = ' + f'{round(para_coeff[0])}' + ' / Ext (Dry Extinction)',
127
- 'Vis (km) = ' + f'{round(para_coeff[1])}' + ' / Ext (Amb Extinction)']
76
+ arts.append(line)
77
+ labels.append(f'Vis (km) = {round(coeff)} / Ext')
128
78
 
129
- else:
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
- labels = [f'Ext = ' + '{:.0f} / Vis ^ {:.3f}'.format(*para_coeff[0]) + ' (Dry Extinction)',
135
- f'Ext = ' + '{:.0f} / Vis ^ {:.3f}'.format(*para_coeff[1]) + ' (Amb Extinction)']
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.legend(handles=[line1, line2], labels=labels, loc='upper right', prop=dict(size=10, weight='bold'),
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 = DataFrame(StandardScaler().fit_transform(df), index=df.index, columns=df.columns)
18
+ df = normalize_data(df)
19
+
16
20
  # Remove outliers
17
- df = df[(np.abs(df) < 6)]
18
- # Interpolate the missing values
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.rolling(window=3, min_periods=1).mean()
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, major_freq='24h', minor_freq='12h', ax: Axes | None = None, title=None, **kwargs
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
- items = ['Al', 'Zr', 'Si', 'Ca', 'Ti', 'Mn', 'Fe', 'V', 'Cl', 'K',
30
- 'Sr', 'Ba', 'Bi', 'Pd', 'Sn', 'Cr', 'W', 'Cu', 'Zn',
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="jet", xticklabels=False, yticklabels=True,
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()
@@ -1 +1,2 @@
1
+ from .template import *
1
2
  from .timeseries import *
@@ -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