AeroViz 0.1.21__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.
- AeroViz/__init__.py +13 -0
- AeroViz/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/data/DEFAULT_DATA.csv +1417 -0
- AeroViz/data/DEFAULT_PNSD_DATA.csv +1417 -0
- AeroViz/data/hysplit_example_data.txt +101 -0
- AeroViz/dataProcess/Chemistry/__init__.py +149 -0
- AeroViz/dataProcess/Chemistry/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/Chemistry/_calculate.py +557 -0
- AeroViz/dataProcess/Chemistry/_isoropia.py +150 -0
- AeroViz/dataProcess/Chemistry/_mass_volume.py +487 -0
- AeroViz/dataProcess/Chemistry/_ocec.py +172 -0
- AeroViz/dataProcess/Chemistry/isrpia.cnf +21 -0
- AeroViz/dataProcess/Chemistry/isrpia2.exe +0 -0
- AeroViz/dataProcess/Optical/PyMieScatt_update.py +577 -0
- AeroViz/dataProcess/Optical/_IMPROVE.py +452 -0
- AeroViz/dataProcess/Optical/__init__.py +281 -0
- AeroViz/dataProcess/Optical/__pycache__/PyMieScatt_update.cpython-312.pyc +0 -0
- AeroViz/dataProcess/Optical/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/Optical/__pycache__/mie_theory.cpython-312.pyc +0 -0
- AeroViz/dataProcess/Optical/_derived.py +518 -0
- AeroViz/dataProcess/Optical/_extinction.py +123 -0
- AeroViz/dataProcess/Optical/_mie_sd.py +912 -0
- AeroViz/dataProcess/Optical/_retrieve_RI.py +243 -0
- AeroViz/dataProcess/Optical/coefficient.py +72 -0
- AeroViz/dataProcess/Optical/fRH.pkl +0 -0
- AeroViz/dataProcess/Optical/mie_theory.py +260 -0
- AeroViz/dataProcess/README.md +271 -0
- AeroViz/dataProcess/SizeDistr/__init__.py +245 -0
- AeroViz/dataProcess/SizeDistr/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/SizeDistr/__pycache__/_size_dist.cpython-312.pyc +0 -0
- AeroViz/dataProcess/SizeDistr/_size_dist.py +810 -0
- AeroViz/dataProcess/SizeDistr/merge/README.md +93 -0
- AeroViz/dataProcess/SizeDistr/merge/__init__.py +20 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v0.py +251 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v0_1.py +246 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v1.py +255 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v2.py +244 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v3.py +518 -0
- AeroViz/dataProcess/SizeDistr/merge/_merge_v4.py +422 -0
- AeroViz/dataProcess/SizeDistr/prop.py +62 -0
- AeroViz/dataProcess/VOC/__init__.py +14 -0
- AeroViz/dataProcess/VOC/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/VOC/_potential_par.py +108 -0
- AeroViz/dataProcess/VOC/support_voc.json +446 -0
- AeroViz/dataProcess/__init__.py +66 -0
- AeroViz/dataProcess/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/dataProcess/core/__init__.py +272 -0
- AeroViz/dataProcess/core/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/mcp_server.py +352 -0
- AeroViz/plot/__init__.py +13 -0
- AeroViz/plot/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/bar.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/box.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/pie.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/radar.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/regression.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/scatter.cpython-312.pyc +0 -0
- AeroViz/plot/__pycache__/violin.cpython-312.pyc +0 -0
- AeroViz/plot/bar.py +126 -0
- AeroViz/plot/box.py +69 -0
- AeroViz/plot/distribution/__init__.py +1 -0
- AeroViz/plot/distribution/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/distribution/__pycache__/distribution.cpython-312.pyc +0 -0
- AeroViz/plot/distribution/distribution.py +576 -0
- AeroViz/plot/meteorology/CBPF.py +295 -0
- AeroViz/plot/meteorology/__init__.py +3 -0
- AeroViz/plot/meteorology/__pycache__/CBPF.cpython-312.pyc +0 -0
- AeroViz/plot/meteorology/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/meteorology/__pycache__/hysplit.cpython-312.pyc +0 -0
- AeroViz/plot/meteorology/__pycache__/wind_rose.cpython-312.pyc +0 -0
- AeroViz/plot/meteorology/hysplit.py +93 -0
- AeroViz/plot/meteorology/wind_rose.py +77 -0
- AeroViz/plot/optical/__init__.py +1 -0
- AeroViz/plot/optical/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/optical/__pycache__/optical.cpython-312.pyc +0 -0
- AeroViz/plot/optical/optical.py +388 -0
- AeroViz/plot/pie.py +210 -0
- AeroViz/plot/radar.py +184 -0
- AeroViz/plot/regression.py +200 -0
- AeroViz/plot/scatter.py +174 -0
- AeroViz/plot/templates/__init__.py +6 -0
- AeroViz/plot/templates/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/ammonium_rich.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/contour.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/corr_matrix.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/diurnal_pattern.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/koschmieder.cpython-312.pyc +0 -0
- AeroViz/plot/templates/__pycache__/metal_heatmap.cpython-312.pyc +0 -0
- AeroViz/plot/templates/ammonium_rich.py +34 -0
- AeroViz/plot/templates/contour.py +47 -0
- AeroViz/plot/templates/corr_matrix.py +267 -0
- AeroViz/plot/templates/diurnal_pattern.py +61 -0
- AeroViz/plot/templates/koschmieder.py +95 -0
- AeroViz/plot/templates/metal_heatmap.py +164 -0
- AeroViz/plot/timeseries/__init__.py +2 -0
- AeroViz/plot/timeseries/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/timeseries/__pycache__/template.cpython-312.pyc +0 -0
- AeroViz/plot/timeseries/__pycache__/timeseries.cpython-312.pyc +0 -0
- AeroViz/plot/timeseries/template.py +47 -0
- AeroViz/plot/timeseries/timeseries.py +446 -0
- AeroViz/plot/utils/__init__.py +4 -0
- AeroViz/plot/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/plot/utils/__pycache__/_color.cpython-312.pyc +0 -0
- AeroViz/plot/utils/__pycache__/_unit.cpython-312.pyc +0 -0
- AeroViz/plot/utils/__pycache__/plt_utils.cpython-312.pyc +0 -0
- AeroViz/plot/utils/__pycache__/sklearn_utils.cpython-312.pyc +0 -0
- AeroViz/plot/utils/_color.py +71 -0
- AeroViz/plot/utils/_unit.py +55 -0
- AeroViz/plot/utils/fRH.json +390 -0
- AeroViz/plot/utils/plt_utils.py +92 -0
- AeroViz/plot/utils/sklearn_utils.py +49 -0
- AeroViz/plot/utils/units.json +89 -0
- AeroViz/plot/violin.py +80 -0
- AeroViz/rawDataReader/FLOW.md +138 -0
- AeroViz/rawDataReader/__init__.py +220 -0
- AeroViz/rawDataReader/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/config/__init__.py +0 -0
- AeroViz/rawDataReader/config/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/config/__pycache__/supported_instruments.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/config/supported_instruments.py +135 -0
- AeroViz/rawDataReader/core/__init__.py +658 -0
- AeroViz/rawDataReader/core/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/__pycache__/logger.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/__pycache__/pre_process.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/__pycache__/qc.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/__pycache__/report.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/core/logger.py +171 -0
- AeroViz/rawDataReader/core/pre_process.py +308 -0
- AeroViz/rawDataReader/core/qc.py +961 -0
- AeroViz/rawDataReader/core/report.py +579 -0
- AeroViz/rawDataReader/script/AE33.py +173 -0
- AeroViz/rawDataReader/script/AE43.py +151 -0
- AeroViz/rawDataReader/script/APS.py +339 -0
- AeroViz/rawDataReader/script/Aurora.py +191 -0
- AeroViz/rawDataReader/script/BAM1020.py +90 -0
- AeroViz/rawDataReader/script/BC1054.py +161 -0
- AeroViz/rawDataReader/script/EPA.py +79 -0
- AeroViz/rawDataReader/script/GRIMM.py +68 -0
- AeroViz/rawDataReader/script/IGAC.py +140 -0
- AeroViz/rawDataReader/script/MA350.py +179 -0
- AeroViz/rawDataReader/script/Minion.py +218 -0
- AeroViz/rawDataReader/script/NEPH.py +199 -0
- AeroViz/rawDataReader/script/OCEC.py +173 -0
- AeroViz/rawDataReader/script/Q-ACSM.py +12 -0
- AeroViz/rawDataReader/script/SMPS.py +389 -0
- AeroViz/rawDataReader/script/TEOM.py +181 -0
- AeroViz/rawDataReader/script/VOC.py +106 -0
- AeroViz/rawDataReader/script/Xact.py +244 -0
- AeroViz/rawDataReader/script/__init__.py +28 -0
- AeroViz/rawDataReader/script/__pycache__/AE33.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/AE43.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/APS.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/Aurora.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/BAM1020.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/BC1054.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/EPA.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/GRIMM.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/IGAC.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/MA350.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/Minion.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/NEPH.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/OCEC.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/Q-ACSM.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/SMPS.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/TEOM.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/VOC.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/Xact.cpython-312.pyc +0 -0
- AeroViz/rawDataReader/script/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/tools/__init__.py +2 -0
- AeroViz/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- AeroViz/tools/__pycache__/database.cpython-312.pyc +0 -0
- AeroViz/tools/__pycache__/dataclassifier.cpython-312.pyc +0 -0
- AeroViz/tools/database.py +95 -0
- AeroViz/tools/dataclassifier.py +117 -0
- AeroViz/tools/dataprinter.py +58 -0
- aeroviz-0.1.21.dist-info/METADATA +294 -0
- aeroviz-0.1.21.dist-info/RECORD +180 -0
- aeroviz-0.1.21.dist-info/WHEEL +5 -0
- aeroviz-0.1.21.dist-info/licenses/LICENSE +21 -0
- aeroviz-0.1.21.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import seaborn as sns
|
|
5
|
+
from matplotlib import colormaps
|
|
6
|
+
from matplotlib.pyplot import Figure, Axes
|
|
7
|
+
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
|
8
|
+
from scipy.stats import pearsonr
|
|
9
|
+
|
|
10
|
+
from AeroViz.plot.utils import *
|
|
11
|
+
|
|
12
|
+
__all__ = ['corr_matrix', 'cross_corr_matrix']
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@set_figure
|
|
16
|
+
def corr_matrix(data: pd.DataFrame,
|
|
17
|
+
cmap: str = "RdBu",
|
|
18
|
+
ax: Axes | None = None,
|
|
19
|
+
items_order: list = None, # 新增參數用於指定順序
|
|
20
|
+
**kwargs
|
|
21
|
+
) -> tuple[Figure, Axes]:
|
|
22
|
+
fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
|
|
23
|
+
|
|
24
|
+
_corr = data.corr()
|
|
25
|
+
breakpoint()
|
|
26
|
+
corr = pd.melt(_corr.reset_index(), id_vars='index')
|
|
27
|
+
corr.columns = ['x', 'y', 'value']
|
|
28
|
+
|
|
29
|
+
p_values = _corr.apply(lambda col1: _corr.apply(lambda col2: pearsonr(col1, col2)[1]))
|
|
30
|
+
p_values = p_values.mask(p_values > 0.05)
|
|
31
|
+
p_values = pd.melt(p_values.reset_index(), id_vars='index').dropna()
|
|
32
|
+
p_values.columns = ['x', 'y', 'value']
|
|
33
|
+
|
|
34
|
+
# Mapping from column names to integer coordinates
|
|
35
|
+
x_labels = [v for v in sorted(corr['x'].unique())]
|
|
36
|
+
y_labels = [v for v in sorted(corr['y'].unique())]
|
|
37
|
+
x_to_num = {p[1]: p[0] for p in enumerate(x_labels)}
|
|
38
|
+
y_to_num = {p[1]: p[0] for p in enumerate(y_labels)}
|
|
39
|
+
|
|
40
|
+
# Show column labels on the axes
|
|
41
|
+
ax.set_xticks([x_to_num[v] for v in x_labels])
|
|
42
|
+
ax.set_xticklabels(x_labels, rotation=90, horizontalalignment='center')
|
|
43
|
+
ax.set_yticks([y_to_num[v] for v in y_labels])
|
|
44
|
+
ax.set_yticklabels(y_labels)
|
|
45
|
+
|
|
46
|
+
# ax.tick_params(axis='both', which='major', direction='out', top=True, left=True)
|
|
47
|
+
|
|
48
|
+
ax.grid(False, 'major')
|
|
49
|
+
ax.grid(True, 'minor')
|
|
50
|
+
ax.set_xticks([t + 0.5 for t in ax.get_xticks()], minor=True)
|
|
51
|
+
ax.set_yticks([t + 0.5 for t in ax.get_yticks()], minor=True)
|
|
52
|
+
|
|
53
|
+
ax.set_xlim([-0.5, max([v for v in x_to_num.values()]) + 0.5])
|
|
54
|
+
ax.set_ylim([-0.5, max([v for v in y_to_num.values()]) + 0.5])
|
|
55
|
+
|
|
56
|
+
n_colors = 256 # Use 256 colors for the diverging color palette
|
|
57
|
+
palette = sns.color_palette(cmap, n_colors=n_colors) # Create the palette
|
|
58
|
+
|
|
59
|
+
# Range of values that will be mapped to the palette, i.e. min and max possible correlation
|
|
60
|
+
color_min, color_max = [-1, 1]
|
|
61
|
+
|
|
62
|
+
def value_to_color(val):
|
|
63
|
+
val_position = float((val - color_min)) / (color_max - color_min)
|
|
64
|
+
ind = int(val_position * (n_colors - 1)) # target index in the color palette
|
|
65
|
+
return palette[ind]
|
|
66
|
+
|
|
67
|
+
point = ax.scatter(
|
|
68
|
+
x=corr['x'].map(x_to_num),
|
|
69
|
+
y=corr['y'].map(y_to_num),
|
|
70
|
+
s=corr['value'].abs() * 70,
|
|
71
|
+
c=corr['value'].apply(value_to_color), # Vector of square color values, mapped to color palette
|
|
72
|
+
marker='s',
|
|
73
|
+
label='$R^{2}$'
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
axes_image = plt.cm.ScalarMappable(cmap=colormaps[cmap])
|
|
77
|
+
|
|
78
|
+
cax = inset_axes(ax, width="5%",
|
|
79
|
+
height="100%",
|
|
80
|
+
loc='lower left',
|
|
81
|
+
bbox_to_anchor=(1.02, 0., 1, 1),
|
|
82
|
+
bbox_transform=ax.transAxes,
|
|
83
|
+
borderpad=0)
|
|
84
|
+
|
|
85
|
+
cbar = plt.colorbar(mappable=axes_image, cax=cax, label=r'$R^{2}$')
|
|
86
|
+
|
|
87
|
+
cbar.set_ticks([0, 0.25, 0.5, 0.75, 1])
|
|
88
|
+
cbar.set_ticklabels(np.linspace(-1, 1, 5))
|
|
89
|
+
|
|
90
|
+
point2 = ax.scatter(
|
|
91
|
+
x=p_values['x'].map(x_to_num),
|
|
92
|
+
y=p_values['y'].map(y_to_num),
|
|
93
|
+
s=10,
|
|
94
|
+
marker='*',
|
|
95
|
+
color='k',
|
|
96
|
+
label='p < 0.05'
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
ax.legend(handles=[point2], labels=['p < 0.05'], bbox_to_anchor=(0.02, 1, 0.05, 0.05))
|
|
100
|
+
|
|
101
|
+
plt.show()
|
|
102
|
+
|
|
103
|
+
return fig, ax
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@set_figure(figsize=(6, 6))
|
|
107
|
+
def cross_corr_matrix(data1: pd.DataFrame,
|
|
108
|
+
data2: pd.DataFrame,
|
|
109
|
+
cmap: str = "RdBu",
|
|
110
|
+
ax: Axes | None = None,
|
|
111
|
+
items_order: list = None, # 新增參數用於指定順序
|
|
112
|
+
**kwargs
|
|
113
|
+
) -> tuple[Figure, Axes]:
|
|
114
|
+
"""
|
|
115
|
+
Create a correlation matrix between two different DataFrames.
|
|
116
|
+
|
|
117
|
+
Parameters:
|
|
118
|
+
-----------
|
|
119
|
+
data1 : pd.DataFrame
|
|
120
|
+
First DataFrame
|
|
121
|
+
data2 : pd.DataFrame
|
|
122
|
+
Second DataFrame
|
|
123
|
+
cmap : str, optional
|
|
124
|
+
Color map for the correlation matrix
|
|
125
|
+
ax : Axes, optional
|
|
126
|
+
Matplotlib axes to plot on
|
|
127
|
+
items_order : list, optional
|
|
128
|
+
List specifying the order of items to display
|
|
129
|
+
**kwargs : dict
|
|
130
|
+
Additional keyword arguments
|
|
131
|
+
"""
|
|
132
|
+
if ax is None:
|
|
133
|
+
fig_kws = kwargs.get('fig_kws', {})
|
|
134
|
+
default_figsize = fig_kws.get('figsize', (8, 8))
|
|
135
|
+
fig = plt.figure(figsize=default_figsize)
|
|
136
|
+
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
|
|
137
|
+
else:
|
|
138
|
+
fig = ax.get_figure()
|
|
139
|
+
|
|
140
|
+
# 如果沒有指定順序,使用原始列名順序
|
|
141
|
+
if items_order is None:
|
|
142
|
+
x_labels = list(data1.columns)
|
|
143
|
+
y_labels = list(data2.columns)
|
|
144
|
+
else:
|
|
145
|
+
# 使用指定順序,但只包含實際存在於數據中的列
|
|
146
|
+
x_labels = [item for item in items_order if item in data1.columns]
|
|
147
|
+
y_labels = [item for item in items_order if item in data2.columns]
|
|
148
|
+
|
|
149
|
+
# Calculate cross-correlation between the two DataFrames
|
|
150
|
+
correlations = []
|
|
151
|
+
p_values_list = []
|
|
152
|
+
|
|
153
|
+
for col1 in x_labels: # 使用指定順序的列名
|
|
154
|
+
for col2 in y_labels:
|
|
155
|
+
try:
|
|
156
|
+
mask = ~(np.isnan(data1[col1]) | np.isnan(data2[col2]))
|
|
157
|
+
if mask.sum() > 2:
|
|
158
|
+
corr, p_val = pearsonr(data1[col1][mask], data2[col2][mask])
|
|
159
|
+
else:
|
|
160
|
+
corr, p_val = np.nan, np.nan
|
|
161
|
+
except Exception as e:
|
|
162
|
+
print(f"Error calculating correlation for {col1} and {col2}: {str(e)}")
|
|
163
|
+
corr, p_val = np.nan, np.nan
|
|
164
|
+
|
|
165
|
+
correlations.append({
|
|
166
|
+
'x': col1,
|
|
167
|
+
'y': col2,
|
|
168
|
+
'value': corr
|
|
169
|
+
})
|
|
170
|
+
if p_val is not None and p_val < 0.05:
|
|
171
|
+
p_values_list.append({
|
|
172
|
+
'x': col1,
|
|
173
|
+
'y': col2,
|
|
174
|
+
'value': p_val
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
corr = pd.DataFrame(correlations)
|
|
178
|
+
p_values = pd.DataFrame(p_values_list)
|
|
179
|
+
|
|
180
|
+
# Create mapping using the specified order
|
|
181
|
+
x_to_num = {label: i for i, label in enumerate(x_labels)}
|
|
182
|
+
y_to_num = {label: i for i, label in enumerate(y_labels)}
|
|
183
|
+
|
|
184
|
+
# 調整標籤顯示
|
|
185
|
+
ax.set_xticks([x_to_num[v] for v in x_labels])
|
|
186
|
+
ax.set_xticklabels(x_labels, rotation=45, ha='right')
|
|
187
|
+
ax.set_yticks([y_to_num[v] for v in y_labels])
|
|
188
|
+
ax.set_yticklabels(y_labels)
|
|
189
|
+
|
|
190
|
+
ax.grid(False, 'major')
|
|
191
|
+
ax.grid(True, 'minor')
|
|
192
|
+
ax.set_xticks([t + 0.5 for t in ax.get_xticks()], minor=True)
|
|
193
|
+
ax.set_yticks([t + 0.5 for t in ax.get_yticks()], minor=True)
|
|
194
|
+
|
|
195
|
+
ax.set_xlim([-0.5, max([v for v in x_to_num.values()]) + 0.5])
|
|
196
|
+
ax.set_ylim([-0.5, max([v for v in y_to_num.values()]) + 0.5])
|
|
197
|
+
|
|
198
|
+
# Color mapping
|
|
199
|
+
n_colors = 256
|
|
200
|
+
palette = sns.color_palette(cmap, n_colors=n_colors)
|
|
201
|
+
color_min, color_max = [-1, 1]
|
|
202
|
+
|
|
203
|
+
def value_to_color(val):
|
|
204
|
+
if pd.isna(val):
|
|
205
|
+
return (1, 1, 1)
|
|
206
|
+
val_position = float((val - color_min)) / (color_max - color_min)
|
|
207
|
+
val_position = np.clip(val_position, 0, 1)
|
|
208
|
+
ind = int(val_position * (n_colors - 1))
|
|
209
|
+
return palette[ind]
|
|
210
|
+
|
|
211
|
+
# Plot correlation squares
|
|
212
|
+
x_coords = corr['x'].map(x_to_num)
|
|
213
|
+
y_coords = corr['y'].map(y_to_num)
|
|
214
|
+
sizes = corr['value'].abs().fillna(0) * 70
|
|
215
|
+
colors = [value_to_color(val) for val in corr['value']]
|
|
216
|
+
|
|
217
|
+
point = ax.scatter(
|
|
218
|
+
x=x_coords,
|
|
219
|
+
y=y_coords,
|
|
220
|
+
s=sizes,
|
|
221
|
+
c=colors,
|
|
222
|
+
marker='s',
|
|
223
|
+
label='$R^{2}$'
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# 調整顏色軸的位置和大小
|
|
227
|
+
cax = fig.add_axes([0.91, 0.1, 0.02, 0.8])
|
|
228
|
+
axes_image = plt.cm.ScalarMappable(cmap=colormaps[cmap])
|
|
229
|
+
cbar = plt.colorbar(mappable=axes_image, cax=cax, label=r'$R^{2}$')
|
|
230
|
+
cbar.set_ticks([0, 0.25, 0.5, 0.75, 1])
|
|
231
|
+
cbar.set_ticklabels(np.linspace(-1, 1, 5))
|
|
232
|
+
|
|
233
|
+
# Plot significance markers
|
|
234
|
+
if not p_values.empty:
|
|
235
|
+
point2 = ax.scatter(
|
|
236
|
+
x=p_values['x'].map(x_to_num),
|
|
237
|
+
y=p_values['y'].map(y_to_num),
|
|
238
|
+
s=10,
|
|
239
|
+
marker='*',
|
|
240
|
+
color='k',
|
|
241
|
+
label='p < 0.05'
|
|
242
|
+
)
|
|
243
|
+
ax.legend(handles=[point2], labels=['p < 0.05'],
|
|
244
|
+
bbox_to_anchor=(0.005, 1.04), loc='upper left')
|
|
245
|
+
|
|
246
|
+
# Add labels
|
|
247
|
+
ax.set_xlabel('NZ', labelpad=10)
|
|
248
|
+
ax.set_ylabel('FS', labelpad=10)
|
|
249
|
+
|
|
250
|
+
plt.show()
|
|
251
|
+
|
|
252
|
+
return fig, ax
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
if __name__ == '__main__':
|
|
256
|
+
import pandas as pd
|
|
257
|
+
from pandas import to_numeric
|
|
258
|
+
|
|
259
|
+
df_NZ = pd.read_csv('/Users/chanchihyu/Desktop/NZ_minion_202402-202411.csv', parse_dates=True, index_col=0)
|
|
260
|
+
df_FS = pd.read_csv('/Users/chanchihyu/Desktop/FS_minion_202402-202411.csv', parse_dates=True, index_col=0)
|
|
261
|
+
|
|
262
|
+
items = ['Ext', 'Sca', 'Abs', 'PNC', 'PSC', 'PVC', 'SO2', 'NO', 'NOx', 'NO2', 'CO', 'O3', 'THC', 'NMHC', 'CH4',
|
|
263
|
+
'PM10', 'PM2.5', 'WS', 'AT', 'RH',
|
|
264
|
+
'OC', 'EC', 'Na+', 'NH4+', 'NO3-', 'SO42-', 'Al', 'Si', 'Ca', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Cu', 'Zn']
|
|
265
|
+
df_NZ = df_NZ.apply(to_numeric, errors='coerce')
|
|
266
|
+
|
|
267
|
+
corr_matrix(df_NZ[items], items_order=items)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
from matplotlib.pyplot import Figure, Axes
|
|
3
|
+
from matplotlib.ticker import AutoMinorLocator
|
|
4
|
+
from pandas import DataFrame
|
|
5
|
+
|
|
6
|
+
from AeroViz.plot.utils import *
|
|
7
|
+
|
|
8
|
+
__all__ = ['diurnal_pattern']
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@set_figure
|
|
12
|
+
def diurnal_pattern(df: DataFrame,
|
|
13
|
+
y: str | list[str],
|
|
14
|
+
std_area: float = 0.5,
|
|
15
|
+
ax: Axes | None = None,
|
|
16
|
+
**kwargs
|
|
17
|
+
) -> tuple[Figure, Axes]:
|
|
18
|
+
if 'hour' not in df.columns and 'Hour' not in df.columns:
|
|
19
|
+
df['Hour'] = df.index.hour
|
|
20
|
+
|
|
21
|
+
Hour = range(0, 24)
|
|
22
|
+
mean = df.groupby('Hour')[y].mean()
|
|
23
|
+
std = df.groupby('Hour')[y].std() * std_area
|
|
24
|
+
|
|
25
|
+
fig, ax = plt.subplots() if ax is None else (ax.get_figure(), ax)
|
|
26
|
+
|
|
27
|
+
# Plot Diurnal pattern
|
|
28
|
+
ax.plot(Hour, mean, 'blue', zorder=3)
|
|
29
|
+
ax.fill_between(Hour, y1=mean + std, y2=mean - std, alpha=0.2, color='blue', edgecolor=None, zorder=2)
|
|
30
|
+
|
|
31
|
+
# Plot Boxplot for each hour
|
|
32
|
+
bp = ax.boxplot([df[df['Hour'] == h][y].dropna() for h in Hour],
|
|
33
|
+
positions=Hour,
|
|
34
|
+
widths=0.5,
|
|
35
|
+
patch_artist=True,
|
|
36
|
+
showfliers=False,
|
|
37
|
+
zorder=1)
|
|
38
|
+
|
|
39
|
+
# Customize boxplot colors
|
|
40
|
+
for element in ['boxes', 'whiskers', 'fliers', 'means', 'medians', 'caps']:
|
|
41
|
+
plt.setp(bp[element], color='gray')
|
|
42
|
+
|
|
43
|
+
for patch in bp['boxes']:
|
|
44
|
+
patch.set(facecolor='lightgray', alpha=0.5)
|
|
45
|
+
|
|
46
|
+
ax.set(xlabel=kwargs.get('xlabel', 'Hours'),
|
|
47
|
+
ylabel=kwargs.get('ylabel', Unit(y)),
|
|
48
|
+
xlim=kwargs.get('xlim', (-0.5, 23.5)),
|
|
49
|
+
ylim=kwargs.get('ylim', (None, None)),
|
|
50
|
+
xticks=kwargs.get('xticks', range(0, 24, 4)),
|
|
51
|
+
xticklabels=kwargs.get('xticklabels', range(0, 24, 4)))
|
|
52
|
+
|
|
53
|
+
ax.tick_params(axis='both', which='major')
|
|
54
|
+
ax.tick_params(axis='x', which='minor')
|
|
55
|
+
ax.xaxis.set_minor_locator(AutoMinorLocator())
|
|
56
|
+
ax.ticklabel_format(axis='y', style='sci', scilimits=(-2, 3), useMathText=True)
|
|
57
|
+
|
|
58
|
+
plt.tight_layout()
|
|
59
|
+
plt.show()
|
|
60
|
+
|
|
61
|
+
return fig, ax
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
from matplotlib.pyplot import Figure, Axes
|
|
6
|
+
from scipy.optimize import curve_fit
|
|
7
|
+
|
|
8
|
+
from AeroViz.plot.utils import *
|
|
9
|
+
|
|
10
|
+
__all__ = ['koschmieder']
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@set_figure(figsize=(2.4, 3))
|
|
14
|
+
def koschmieder(df: pd.DataFrame,
|
|
15
|
+
vis: str,
|
|
16
|
+
ext: list[str],
|
|
17
|
+
ax: Axes | None = None,
|
|
18
|
+
**kwargs
|
|
19
|
+
) -> tuple[Figure, Axes]:
|
|
20
|
+
"""
|
|
21
|
+
Plot Koschmieder relationship between Visibility and Extinction.
|
|
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)
|
|
27
|
+
popt, pcov = curve_fit(func, x_log, y_log)
|
|
28
|
+
|
|
29
|
+
return np.exp(popt)[0], pcov
|
|
30
|
+
|
|
31
|
+
fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
|
|
32
|
+
|
|
33
|
+
boxcolors = ['#a5bf6b', '#3f83bf']
|
|
34
|
+
scattercolor = ['green', 'blue']
|
|
35
|
+
arts = []
|
|
36
|
+
labels = []
|
|
37
|
+
|
|
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]
|
|
42
|
+
|
|
43
|
+
bins = np.linspace(0, 50, 25)
|
|
44
|
+
wid = (bins + (bins[1] - bins[0]) / 2)[0:-1]
|
|
45
|
+
|
|
46
|
+
_df[f'{vis}_bins'] = pd.cut(x_data, bins=bins, labels=wid)
|
|
47
|
+
|
|
48
|
+
grouped = _df.groupby(f'{vis}_bins', observed=False)
|
|
49
|
+
|
|
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())
|
|
56
|
+
|
|
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='-'))
|
|
63
|
+
|
|
64
|
+
plt.scatter(x_data, y_data, marker='.', s=10, facecolor='white', edgecolor=boxcolors[i], alpha=0.1)
|
|
65
|
+
|
|
66
|
+
# fit curve
|
|
67
|
+
coeff, _ = _log_fit(np.array(vis_labels, dtype='float'), np.array(median_vals, dtype='float'))
|
|
68
|
+
|
|
69
|
+
# Plot lines (ref & Measurement)
|
|
70
|
+
x_fit = np.linspace(0.1, 50, 1000)
|
|
71
|
+
|
|
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')
|
|
75
|
+
|
|
76
|
+
arts.append(line)
|
|
77
|
+
if 'dry' in ext_col:
|
|
78
|
+
labels.append(f'Vis (km) = {round(coeff)} / Ext (dry)')
|
|
79
|
+
else:
|
|
80
|
+
labels.append(f'Vis (km) = {round(coeff)} / Ext (amb)')
|
|
81
|
+
|
|
82
|
+
ax.legend(handles=arts, labels=labels, loc='upper right', prop=dict(weight='bold'), bbox_to_anchor=(0.99, 0.99))
|
|
83
|
+
|
|
84
|
+
ax.set(xlabel=kwargs.get('xlabel', 'Visibility (km)'),
|
|
85
|
+
ylabel=kwargs.get('ylabel', 'Extinction (1/Mm)'),
|
|
86
|
+
title=kwargs.get('title', 'Koschmieder relationship'),
|
|
87
|
+
xlim=kwargs.get('xlim', (0, 30)),
|
|
88
|
+
ylim=kwargs.get('ylim', (0, 800))
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
plt.xticks(ticks=np.array(range(0, 31, 5)), labels=np.array(range(0, 31, 5)))
|
|
92
|
+
fig.savefig('koschmieder.png', dpi=600)
|
|
93
|
+
plt.show()
|
|
94
|
+
|
|
95
|
+
return fig, ax
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import numpy as np
|
|
3
|
+
import seaborn as sns
|
|
4
|
+
from matplotlib.pyplot import Figure, Axes
|
|
5
|
+
from pandas import DataFrame, date_range, concat
|
|
6
|
+
from sklearn.preprocessing import StandardScaler
|
|
7
|
+
|
|
8
|
+
from AeroViz.plot.utils import *
|
|
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)
|
|
16
|
+
|
|
17
|
+
# Normalize the data
|
|
18
|
+
df = normalize_data(df)
|
|
19
|
+
|
|
20
|
+
# Remove outliers
|
|
21
|
+
df = remove_outliers(df, threshold=outlier_threshold)
|
|
22
|
+
|
|
23
|
+
# Interpolate missing values
|
|
24
|
+
df = df.interpolate(method='linear')
|
|
25
|
+
|
|
26
|
+
# Smooth the data
|
|
27
|
+
df = smooth_data(df, window=smoothing_window)
|
|
28
|
+
|
|
29
|
+
return df
|
|
30
|
+
|
|
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
|
+
|
|
120
|
+
@set_figure(figsize=(6, 3), fs=8, fw='normal')
|
|
121
|
+
def metal_heatmaps(df,
|
|
122
|
+
process=True,
|
|
123
|
+
major_freq='10d',
|
|
124
|
+
minor_freq='1d',
|
|
125
|
+
cmap='jet',
|
|
126
|
+
ax: Axes | None = None,
|
|
127
|
+
**kwargs
|
|
128
|
+
) -> tuple[Figure, Axes]:
|
|
129
|
+
if process:
|
|
130
|
+
df = process_data(df)
|
|
131
|
+
|
|
132
|
+
fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
|
|
133
|
+
|
|
134
|
+
sns.heatmap(df.T, vmin=None, vmax=3, cmap=cmap, xticklabels=True, yticklabels=True,
|
|
135
|
+
cbar_kws={'label': 'Z score', "pad": 0.02})
|
|
136
|
+
ax.grid(color='gray', linestyle='-', linewidth=0.3)
|
|
137
|
+
|
|
138
|
+
# Set x-tick positions and labels
|
|
139
|
+
major_tick = date_range(start=df.index[0], end=df.index[-1], freq=major_freq)
|
|
140
|
+
minor_tick = date_range(start=df.index[0], end=df.index[-1], freq=minor_freq)
|
|
141
|
+
|
|
142
|
+
# Set the major and minor ticks
|
|
143
|
+
ax.set_xticks(ticks=[df.index.get_loc(t) for t in major_tick])
|
|
144
|
+
ax.set_xticks(ticks=[df.index.get_loc(t) for t in minor_tick], minor=True)
|
|
145
|
+
ax.set_xticklabels(major_tick.strftime('%F'), rotation=0)
|
|
146
|
+
ax.tick_params(axis='y', rotation=0)
|
|
147
|
+
|
|
148
|
+
ax.set(xlabel='',
|
|
149
|
+
ylabel='Trace metals',
|
|
150
|
+
title=kwargs.get('title', None)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
if kwargs.get('savefig'):
|
|
154
|
+
plt.savefig(kwargs.get('savefig'), dpi=600)
|
|
155
|
+
|
|
156
|
+
plt.show()
|
|
157
|
+
|
|
158
|
+
return fig, ax
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
if __name__ == '__main__':
|
|
162
|
+
fig, ax = plt.subplots(1, 1, figsize=(6, 6))
|
|
163
|
+
plt.title('text', font={'weight': 'bold'})
|
|
164
|
+
plt.show()
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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.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='PM2.5', color='PM1/PM25', style='scatter', ax=ax5, ylim=[0, None])
|
|
44
|
+
|
|
45
|
+
plt.show()
|
|
46
|
+
|
|
47
|
+
return fig, ax
|