AeroViz 0.1.3b0__py3-none-any.whl → 0.1.5__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 (85) hide show
  1. AeroViz/__init__.py +5 -3
  2. AeroViz/{config → data}/DEFAULT_DATA.csv +1 -1
  3. AeroViz/dataProcess/Chemistry/__init__.py +28 -27
  4. AeroViz/dataProcess/Chemistry/_isoropia.py +11 -11
  5. AeroViz/dataProcess/Chemistry/_mass_volume.py +15 -18
  6. AeroViz/dataProcess/Chemistry/_ocec.py +21 -46
  7. AeroViz/dataProcess/Chemistry/_teom.py +2 -1
  8. AeroViz/dataProcess/Chemistry/isrpia.cnf +21 -0
  9. AeroViz/dataProcess/Chemistry/isrpia2.exe +0 -0
  10. AeroViz/dataProcess/Optical/Angstrom_exponent.py +20 -0
  11. AeroViz/dataProcess/Optical/_IMPROVE.py +13 -15
  12. AeroViz/dataProcess/Optical/__init__.py +15 -30
  13. AeroViz/dataProcess/Optical/_absorption.py +21 -47
  14. AeroViz/dataProcess/Optical/_extinction.py +20 -15
  15. AeroViz/dataProcess/Optical/_mie.py +0 -1
  16. AeroViz/dataProcess/Optical/_scattering.py +19 -20
  17. AeroViz/dataProcess/Optical/fRH.pkl +0 -0
  18. AeroViz/dataProcess/SizeDistr/__init__.py +7 -7
  19. AeroViz/dataProcess/SizeDistr/_merge.py +2 -2
  20. AeroViz/dataProcess/SizeDistr/_merge_v1.py +2 -2
  21. AeroViz/dataProcess/SizeDistr/_merge_v2.py +2 -2
  22. AeroViz/dataProcess/SizeDistr/_merge_v3.py +1 -1
  23. AeroViz/dataProcess/SizeDistr/_merge_v4.py +1 -1
  24. AeroViz/dataProcess/VOC/__init__.py +4 -9
  25. AeroViz/dataProcess/VOC/_potential_par.py +71 -37
  26. AeroViz/dataProcess/VOC/{voc_par.json → support_voc.json} +321 -339
  27. AeroViz/dataProcess/__init__.py +28 -6
  28. AeroViz/dataProcess/core/__init__.py +10 -17
  29. AeroViz/plot/__init__.py +1 -1
  30. AeroViz/plot/box.py +2 -1
  31. AeroViz/plot/optical/optical.py +4 -4
  32. AeroViz/plot/regression.py +25 -39
  33. AeroViz/plot/scatter.py +68 -2
  34. AeroViz/plot/templates/__init__.py +2 -1
  35. AeroViz/plot/templates/ammonium_rich.py +34 -0
  36. AeroViz/plot/templates/diurnal_pattern.py +11 -9
  37. AeroViz/plot/templates/koschmieder.py +51 -115
  38. AeroViz/plot/templates/metal_heatmap.py +115 -17
  39. AeroViz/plot/timeseries/__init__.py +1 -0
  40. AeroViz/plot/timeseries/template.py +47 -0
  41. AeroViz/plot/timeseries/timeseries.py +275 -208
  42. AeroViz/plot/utils/plt_utils.py +2 -2
  43. AeroViz/plot/utils/units.json +5 -0
  44. AeroViz/plot/violin.py +9 -8
  45. AeroViz/process/__init__.py +2 -2
  46. AeroViz/process/script/AbstractDistCalc.py +1 -1
  47. AeroViz/process/script/Chemical.py +5 -4
  48. AeroViz/process/script/Others.py +1 -1
  49. AeroViz/rawDataReader/__init__.py +66 -22
  50. AeroViz/rawDataReader/{utils/config.py → config/supported_instruments.py} +33 -54
  51. AeroViz/rawDataReader/core/__init__.py +116 -231
  52. AeroViz/rawDataReader/script/AE33.py +12 -13
  53. AeroViz/rawDataReader/script/AE43.py +10 -13
  54. AeroViz/rawDataReader/script/APS_3321.py +8 -8
  55. AeroViz/rawDataReader/script/Aurora.py +21 -19
  56. AeroViz/rawDataReader/script/BC1054.py +13 -17
  57. AeroViz/rawDataReader/script/EPA_vertical.py +36 -8
  58. AeroViz/rawDataReader/script/GRIMM.py +6 -13
  59. AeroViz/rawDataReader/script/{IGAC_ZM.py → IGAC.py} +18 -18
  60. AeroViz/rawDataReader/script/MA350.py +9 -16
  61. AeroViz/rawDataReader/script/Minion.py +103 -0
  62. AeroViz/rawDataReader/script/NEPH.py +28 -38
  63. AeroViz/rawDataReader/script/SMPS_TH.py +6 -6
  64. AeroViz/rawDataReader/script/SMPS_aim11.py +8 -8
  65. AeroViz/rawDataReader/script/SMPS_genr.py +8 -8
  66. AeroViz/rawDataReader/script/Sunset_OCEC.py +66 -0
  67. AeroViz/rawDataReader/script/TEOM.py +10 -8
  68. AeroViz/rawDataReader/script/Table.py +9 -10
  69. AeroViz/rawDataReader/script/VOC.py +33 -0
  70. AeroViz/rawDataReader/script/__init__.py +10 -12
  71. AeroViz/tools/database.py +7 -9
  72. AeroViz/tools/datareader.py +3 -3
  73. {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.5.dist-info}/METADATA +1 -1
  74. AeroViz-0.1.5.dist-info/RECORD +114 -0
  75. AeroViz/rawDataReader/script/IGAC_TH.py +0 -104
  76. AeroViz/rawDataReader/script/OCEC_LCRES.py +0 -34
  77. AeroViz/rawDataReader/script/OCEC_RES.py +0 -28
  78. AeroViz/rawDataReader/script/VOC_TH.py +0 -30
  79. AeroViz/rawDataReader/script/VOC_ZM.py +0 -37
  80. AeroViz-0.1.3b0.dist-info/RECORD +0 -110
  81. /AeroViz/{config → data}/DEFAULT_PNSD_DATA.csv +0 -0
  82. /AeroViz/rawDataReader/{utils → config}/__init__.py +0 -0
  83. {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.5.dist-info}/LICENSE +0 -0
  84. {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.5.dist-info}/WHEEL +0 -0
  85. {AeroViz-0.1.3b0.dist-info → AeroViz-0.1.5.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,33 @@
1
+ from pathlib import Path
2
+
1
3
  from .Chemistry import Chemistry
2
4
  from .Optical import Optical
3
5
  from .SizeDistr import SizeDistr
4
6
  from .VOC import VOC
5
7
 
6
- __all__ = [
7
- 'Optical',
8
- 'SizeDistr',
9
- 'Chemistry',
10
- 'VOC',
11
- ]
8
+ __all__ = ['DataProcess']
9
+
10
+
11
+ def DataProcess(method: str,
12
+ path_out: Path,
13
+ excel: bool = False,
14
+ csv: bool = True,
15
+ ):
16
+ # Mapping of method names to their respective classes
17
+ method_class_map = {
18
+ 'Chemistry': Chemistry,
19
+ 'Optical': Optical,
20
+ 'SizeDistr': SizeDistr,
21
+ 'VOC': VOC
22
+ }
23
+
24
+ if method not in method_class_map.keys():
25
+ raise ValueError(f"Method name '{method}' is not valid. \nMust be one of: {list(method_class_map.keys())}")
26
+
27
+ writer_module = method_class_map[method](
28
+ path_out=path_out,
29
+ excel=excel,
30
+ csv=csv
31
+ )
32
+
33
+ return writer_module
@@ -5,17 +5,16 @@ from pathlib import Path
5
5
  from pandas import concat
6
6
 
7
7
 
8
- class _writter:
8
+ class Writer:
9
9
 
10
10
  def __init__(self, path_out=None, excel=True, csv=False):
11
-
12
11
  self.path_out = Path(path_out) if path_out is not None else path_out
13
12
  self.excel = excel
14
13
  self.csv = csv
15
14
 
16
- def _pre_process(self, _out):
17
-
18
- if type(_out) == dict:
15
+ @staticmethod
16
+ def pre_process(_out):
17
+ if isinstance(_out, dict):
19
18
  for _ky, _df in _out.items():
20
19
  _df.index.name = 'time'
21
20
  else:
@@ -23,8 +22,7 @@ class _writter:
23
22
 
24
23
  return _out
25
24
 
26
- def _save_out(self, _nam, _out):
27
-
25
+ def save_out(self, _nam, _out):
28
26
  _check = True
29
27
  while _check:
30
28
 
@@ -44,7 +42,7 @@ class _writter:
44
42
  _out.to_excel(f, sheet_name=f'{_nam}')
45
43
 
46
44
  if self.csv:
47
- if type(_out) == dict:
45
+ if isinstance(_out, dict):
48
46
  _path_out = self.path_out / _nam
49
47
  _path_out.mkdir(exist_ok=True, parents=True)
50
48
 
@@ -60,7 +58,7 @@ class _writter:
60
58
  input('\t\t\33[41m Please Close The File And Press "Enter" \33[0m\n')
61
59
 
62
60
 
63
- def _run_process(*_ini_set):
61
+ def run_process(*_ini_set):
64
62
  def _decorator(_prcs_fc):
65
63
  def _wrap(*arg, **kwarg):
66
64
  _fc_name, _nam = _ini_set
@@ -71,9 +69,9 @@ def _run_process(*_ini_set):
71
69
  print(f"\n\t{dtm.now().strftime('%m/%d %X')} : Process \033[92m{_fc_name}\033[0m -> {_nam}")
72
70
 
73
71
  _class, _out = _prcs_fc(*arg, **kwarg)
74
- _out = _class._pre_process(_out)
72
+ _out = _class.pre_process(_out)
75
73
 
76
- _class._save_out(_nam, _out)
74
+ _class.save_out(_nam, _out)
77
75
 
78
76
  return _out
79
77
 
@@ -82,12 +80,7 @@ def _run_process(*_ini_set):
82
80
  return _decorator
83
81
 
84
82
 
85
- def _union_index(*_df_arg):
83
+ def union_index(*_df_arg):
86
84
  _idx = concat(_df_arg, axis=1).index
87
85
 
88
- # _idx = DatetimeIndex([])
89
-
90
- # for _df in _df_arg:
91
- # _idx = _idx.union(DataFrame(_df).index)
92
-
93
86
  return [_df.reindex(_idx) if _df is not None else None for _df in _df_arg]
AeroViz/plot/__init__.py CHANGED
@@ -1,12 +1,12 @@
1
1
  from . import distribution
2
2
  from . import meteorology
3
3
  from . import optical
4
- from . import timeseries
5
4
  from .bar import bar
6
5
  from .box import box
7
6
  from .pie import pie, donuts
8
7
  from .regression import linear_regression, multiple_linear_regression
9
8
  from .scatter import scatter
10
9
  from .templates import *
10
+ from .timeseries import timeseries, timeseries_template, timeseries_stacked
11
11
  from .utils import *
12
12
  from .violin import violin
AeroViz/plot/box.py CHANGED
@@ -15,7 +15,8 @@ def box(df: pd.DataFrame,
15
15
  x_bins: list | np.ndarray = None,
16
16
  add_scatter: bool = True,
17
17
  ax: Axes | None = None,
18
- **kwargs) -> tuple[Figure, Axes]:
18
+ **kwargs
19
+ ) -> tuple[Figure, Axes]:
19
20
  fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
20
21
 
21
22
  df = df.dropna(subset=[x, y]).copy()
@@ -381,8 +381,8 @@ def response_surface(real_range=(1.33, 1.7),
381
381
 
382
382
 
383
383
  if __name__ == '__main__':
384
- Q_plot(['AS', 'AN', 'OM', 'Soil', 'SS', 'BC'], x='dp', y='MEE')
385
- Q_plot(['AS', 'AN', 'OM', 'Soil', 'SS', 'BC'], x='dp', y='Q')
384
+ # Q_plot(['AS', 'AN', 'OM', 'Soil', 'SS', 'BC'], x='dp', y='MEE')
385
+ # Q_plot(['AS', 'AN', 'OM', 'Soil', 'SS', 'BC'], x='dp', y='Q')
386
386
 
387
- # RI_couple()
388
- # response_surface()
387
+ # RI_couple()
388
+ response_surface()
@@ -23,53 +23,47 @@ def linear_regression(df: pd.DataFrame,
23
23
  **kwargs
24
24
  ) -> tuple[Figure, Axes]:
25
25
  """
26
- Create a scatter plot with multiple regression lines for the given data.
26
+ Create a scatter plot with regression lines for the given data.
27
27
 
28
28
  Parameters
29
29
  ----------
30
- df : DataFrame
30
+ df : pd.DataFrame
31
31
  Input DataFrame containing the data.
32
-
33
32
  x : str or list of str
34
- Column name(s) for the x-axis variable(s).
35
-
33
+ Column name(s) for the x-axis variable(s). If a list, only the first element is used.
36
34
  y : str or list of str
37
35
  Column name(s) for the y-axis variable(s).
38
-
39
36
  labels : str or list of str, optional
40
37
  Labels for the y-axis variable(s). If None, column names are used as labels. Default is None.
41
-
42
- ax : AxesSubplot, optional
43
- Matplotlib AxesSubplot to use for the plot. If None, a new subplot is created. Default is None.
44
-
38
+ ax : Axes, optional
39
+ Matplotlib Axes object to use for the plot. If None, a new subplot is created. Default is None.
45
40
  diagonal : bool, optional
46
41
  If True, a diagonal line (1:1 line) is added to the plot. Default is False.
47
-
48
42
  positive : bool, optional
49
- Whether to let coefficient positive. Default is True.
50
-
43
+ Whether to constrain the regression coefficients to be positive. Default is True.
51
44
  fit_intercept: bool, optional
52
- Whether to fit intercept. Default is True.
53
-
45
+ Whether to calculate the intercept for this model. Default is True.
54
46
  **kwargs
55
- Additional keyword arguments to customize the plot.
47
+ Additional keyword arguments for plot customization.
56
48
 
57
49
  Returns
58
50
  -------
59
- AxesSubplot
60
- Matplotlib AxesSubplot containing the scatter plot.
51
+ fig : Figure
52
+ The matplotlib Figure object.
53
+ ax : Axes
54
+ The matplotlib Axes object with the scatter plot.
61
55
 
62
56
  Notes
63
57
  -----
64
- - The function creates a scatter plot with the option to include multiple regression lines.
65
- - If regression is True, regression lines are fitted for each y variable.
66
- - Additional customization can be done using the **kwargs.
58
+ - The function creates a scatter plot with optional regression lines.
59
+ - The regression line is fitted for each y variable.
60
+ - Customization options are provided via **kwargs.
67
61
 
68
62
  Example
69
63
  -------
70
64
  >>> linear_regression(df, x='X', y=['Y1', 'Y2'], labels=['Label1', 'Label2'],
71
- ... regression=True, diagonal=True, xlim=(0, 10), ylim=(0, 20),
72
- ... xlabel="X-axis", ylabel="Y-axis", title="Scatter Plot with Regressions")
65
+ ... diagonal=True, xlim=(0, 10), ylim=(0, 20),
66
+ ... xlabel="X-axis", ylabel="Y-axis", title="Scatter Plot with Regressions")
73
67
  """
74
68
  fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
75
69
 
@@ -140,37 +134,29 @@ def multiple_linear_regression(df: pd.DataFrame,
140
134
 
141
135
  Parameters
142
136
  ----------
143
- df : pandas.DataFrame
137
+ df : pd.DataFrame
144
138
  Input DataFrame containing the data.
145
-
146
139
  x : str or list of str
147
140
  Column name(s) for the independent variable(s). Can be a single string or a list of strings.
148
-
149
141
  y : str or list of str
150
142
  Column name(s) for the dependent variable(s). Can be a single string or a list of strings.
151
-
152
143
  labels : str or list of str, optional
153
144
  Labels for the dependent variable(s). If None, column names are used as labels. Default is None.
154
-
155
- ax : matplotlib.axes.Axes or None, optional
145
+ ax : Axes, optional
156
146
  Matplotlib Axes object to use for the plot. If None, a new subplot is created. Default is None.
157
-
158
147
  diagonal : bool, optional
159
148
  Whether to include a diagonal line (1:1 line) in the plot. Default is False.
160
-
161
149
  positive : bool, optional
162
- Whether to let coefficient positive. Default is True.
163
-
150
+ Whether to constrain the regression coefficients to be positive. Default is True.
164
151
  fit_intercept: bool, optional
165
- Whether to fit intercept. Default is True.
166
-
152
+ Whether to calculate the intercept for this model. Default is True.
167
153
  **kwargs
168
- Additional keyword arguments to customize the plot.
154
+ Additional keyword arguments for plot customization.
169
155
 
170
156
  Returns
171
157
  -------
172
- matplotlib.axes.Axes
173
- Matplotlib Axes object containing the regression plot.
158
+ tuple[Figure, Axes]
159
+ The Figure and Axes containing the regression plot.
174
160
 
175
161
  Notes
176
162
  -----
@@ -180,7 +166,7 @@ def multiple_linear_regression(df: pd.DataFrame,
180
166
  Example
181
167
  -------
182
168
  >>> multiple_linear_regression(df, x=['X1', 'X2'], y='Y', labels=['Y1', 'Y2'],
183
- ... diagonal=True, add_constant=True,
169
+ ... diagonal=True, fit_intercept=True,
184
170
  ... xlabel="X-axis", ylabel="Y-axis", title="Multiple Linear Regression Plot")
185
171
  """
186
172
  fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
AeroViz/plot/scatter.py CHANGED
@@ -11,7 +11,13 @@ from AeroViz.plot.utils import *
11
11
  __all__ = ['scatter']
12
12
 
13
13
 
14
- @set_figure(figsize=(5, 4))
14
+ def check_empty(*arrays):
15
+ for i, arr in enumerate(arrays):
16
+ if arr.size == 0:
17
+ raise ValueError(f"Array is empty!")
18
+
19
+
20
+ @set_figure
15
21
  def scatter(df: pd.DataFrame,
16
22
  x: str,
17
23
  y: str,
@@ -21,12 +27,69 @@ def scatter(df: pd.DataFrame,
21
27
  regression=False,
22
28
  diagonal=False,
23
29
  ax: Axes | None = None,
24
- **kwargs) -> tuple[Figure, Axes]:
30
+ **kwargs
31
+ ) -> tuple[Figure, Axes]:
32
+ """
33
+ Creates a scatter plot with optional color and size encoding.
34
+
35
+ Parameters
36
+ ----------
37
+ df : pd.DataFrame
38
+ The DataFrame containing the data to plot.
39
+ x : str
40
+ The column name for the x-axis values.
41
+ y : str
42
+ The column name for the y-axis values.
43
+ c : str, optional
44
+ The column name for color encoding. Default is None.
45
+ s : str, optional
46
+ The column name for size encoding. Default is None.
47
+ cmap : str, optional
48
+ The colormap to use for the color encoding. Default is 'jet'.
49
+ regression : bool, optional
50
+ If True, fits and plots a linear regression line. Default is False.
51
+ diagonal : bool, optional
52
+ If True, plots a 1:1 diagonal line. Default is False.
53
+ ax : Axes, optional
54
+ The matplotlib Axes to plot on. If not provided, a new figure and axes are created.
55
+ **kwargs : Any
56
+ Additional keyword arguments passed to customize the plot, such as `fig_kws` for figure creation and `xlabel`,
57
+ `ylabel`, `xlim`, `ylim`, `title` for axis labeling and limits.
58
+
59
+ Returns
60
+ -------
61
+ fig : Figure
62
+ The matplotlib Figure object.
63
+ ax : Axes
64
+ The matplotlib Axes object with the scatter plot.
65
+
66
+ Notes
67
+ -----
68
+ - If both `c` and `s` are provided, the scatter plot will encode data points using both color and size.
69
+ - If only `c` is provided, data points will be color-coded according to the values in the `c` column.
70
+ - If only `s` is provided, data points will be sized according to the values in the `s` column.
71
+ - If neither `c` nor `s` is provided, a basic scatter plot is created.
72
+ - The `regression` option will add a linear regression line and display the equation on the plot.
73
+ - The `diagonal` option will add a 1:1 reference line to the plot.
74
+
75
+ Examples
76
+ --------
77
+ >>> import pandas as pd
78
+ >>> from AeroViz.plot import scatter
79
+ >>> df = pd.DataFrame({
80
+ >>> 'x': [1, 2, 3, 4],
81
+ >>> 'y': [1.1, 2.0, 2.9, 4.1],
82
+ >>> 'color': [10, 20, 30, 40],
83
+ >>> 'size': [100, 200, 300, 400]
84
+ >>> })
85
+ >>> fig, ax = scatter(df, x='x', y='y', c='color', s='size', regression=True, diagonal=True)
86
+ """
25
87
  fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
26
88
 
27
89
  if c is not None and s is not None:
28
90
  df_ = df.dropna(subset=[x, y, c, s]).copy()
29
91
  x_data, y_data, c_data, s_data = df_[x].to_numpy(), df_[y].to_numpy(), df_[c].to_numpy(), df_[s].to_numpy()
92
+ check_empty(x_data, y_data, c_data, s_data)
30
93
 
31
94
  scatter = ax.scatter(x_data, y_data, c=c_data,
32
95
  norm=Normalize(vmin=np.percentile(c_data, 10), vmax=np.percentile(c_data, 90)),
@@ -43,6 +106,7 @@ def scatter(df: pd.DataFrame,
43
106
  elif c is not None:
44
107
  df_ = df.dropna(subset=[x, y, c]).copy()
45
108
  x_data, y_data, c_data = df_[x].to_numpy(), df_[y].to_numpy(), df_[c].to_numpy()
109
+ check_empty(x_data, y_data, c_data)
46
110
 
47
111
  scatter = ax.scatter(x_data, y_data, c=c_data, vmin=c_data.min(), vmax=np.percentile(c_data, 90), cmap=cmap,
48
112
  alpha=0.7,
@@ -52,6 +116,7 @@ def scatter(df: pd.DataFrame,
52
116
  elif s is not None:
53
117
  df_ = df.dropna(subset=[x, y, s]).copy()
54
118
  x_data, y_data, s_data = df_[x].to_numpy(), df_[y].to_numpy(), df_[s].to_numpy()
119
+ check_empty(x_data, y_data, s_data)
55
120
 
56
121
  scatter = ax.scatter(x_data, y_data, s=50 * (s_data / s_data.max()) ** 1.5, color='#7a97c9', alpha=0.7,
57
122
  edgecolors='white')
@@ -68,6 +133,7 @@ def scatter(df: pd.DataFrame,
68
133
  else:
69
134
  df_ = df.dropna(subset=[x, y]).copy()
70
135
  x_data, y_data = df_[x].to_numpy(), df_[y].to_numpy()
136
+ check_empty(x_data, y_data)
71
137
 
72
138
  scatter = ax.scatter(x_data, y_data, s=30, color='#7a97c9', alpha=0.7, edgecolors='white')
73
139
  colorbar = False
@@ -1,5 +1,6 @@
1
+ from .ammonium_rich import ammonium_rich
1
2
  from .contour import *
2
3
  from .corr_matrix import corr_matrix
3
4
  from .diurnal_pattern import *
4
5
  from .koschmieder import *
5
- from .metal_heatmap import metal_heatmaps, process_data
6
+ from .metal_heatmap import metal_heatmaps, process_data_with_two_df
@@ -0,0 +1,34 @@
1
+ import matplotlib.pyplot as plt
2
+ from matplotlib.pyplot import Figure, Axes
3
+ from pandas import DataFrame
4
+
5
+ from AeroViz.plot.utils import set_figure, Unit
6
+
7
+
8
+ @set_figure(figsize=(5, 4))
9
+ def ammonium_rich(df: DataFrame,
10
+ **kwargs
11
+ ) -> tuple[Figure, Axes]:
12
+ df = df[['NH4+', 'SO42-', 'NO3-', 'PM2.5']].dropna().copy().div([18, 96, 62, 1])
13
+ df['required_ammonium'] = df['NO3-'] + 2 * df['SO42-']
14
+
15
+ fig, ax = plt.subplots()
16
+
17
+ scatter = ax.scatter(df['required_ammonium'].to_numpy(), df['NH4+'].to_numpy(), c=df['PM2.5'].to_numpy(),
18
+ vmin=0, vmax=70, cmap='jet', marker='o', s=10, alpha=1)
19
+
20
+ ax.axline((0, 0), slope=1., color='k', lw=2, ls='--', alpha=0.5, label='1:1')
21
+ plt.text(0.97, 0.97, r'$\bf 1:1\ Line$', color='k', ha='right', va='top', transform=ax.transAxes)
22
+
23
+ ax.set(xlim=(0, 1.2),
24
+ ylim=(0, 1.2),
25
+ xlabel=r'$\bf NO_{3}^{-}\ +\ 2\ \times\ SO_{4}^{2-}\ (mole\ m^{-3})$',
26
+ ylabel=r'$\bf NH_{4}^{+}\ (mole\ m^{-3})$',
27
+ title=kwargs.get('title', ''))
28
+
29
+ color_bar = plt.colorbar(scatter, label=Unit('PM2.5'), extend='both')
30
+
31
+ # fig.savefig(f'Ammonium_rich_{title}')
32
+ plt.show()
33
+
34
+ return fig, ax
@@ -1,7 +1,7 @@
1
1
  import matplotlib.pyplot as plt
2
- import pandas as pd
3
2
  from matplotlib.pyplot import Figure, Axes
4
3
  from matplotlib.ticker import AutoMinorLocator
4
+ from pandas import DataFrame
5
5
 
6
6
  from AeroViz.plot.utils import *
7
7
 
@@ -9,22 +9,24 @@ __all__ = ['diurnal_pattern']
9
9
 
10
10
 
11
11
  @set_figure
12
- def diurnal_pattern(data_set: pd.DataFrame,
13
- data_std: pd.DataFrame,
12
+ def diurnal_pattern(df: DataFrame,
14
13
  y: str | list[str],
15
- std_area=0.5,
14
+ std_area: float = 0.5,
16
15
  ax: Axes | None = None,
17
- **kwargs) -> tuple[Figure, Axes]:
18
- fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
16
+ **kwargs
17
+ ) -> tuple[Figure, Axes]:
18
+ if 'hour' or 'Hour' not in df.columns:
19
+ df['Hour'] = df.index.hour
19
20
 
20
21
  Hour = range(0, 24)
22
+ mean = df.groupby('Hour')[y].mean()
23
+ std = df.groupby('Hour')[y].std() * std_area
21
24
 
22
- mean = data_set[y]
23
- std = data_std[y] * std_area
25
+ fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
24
26
 
25
27
  # Plot Diurnal pattern
26
28
  ax.plot(Hour, mean, 'blue')
27
- ax.fill_between(Hour, y1=mean + std, y2=mean - std, alpha=0.5, color='blue', edgecolor=None)
29
+ ax.fill_between(Hour, y1=mean + std, y2=mean - std, alpha=0.2, color='blue', edgecolor=None)
28
30
 
29
31
  ax.set(xlabel=kwargs.get('xlabel', 'Hours'),
30
32
  ylabel=kwargs.get('ylabel', Unit(y)),