AeroViz 0.1.13__py3-none-any.whl → 0.1.15__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 (89) hide show
  1. AeroViz/__pycache__/__init__.cpython-312.pyc +0 -0
  2. AeroViz/dataProcess/Chemistry/__pycache__/__init__.cpython-312.pyc +0 -0
  3. AeroViz/dataProcess/Optical/__pycache__/PyMieScatt_update.cpython-312.pyc +0 -0
  4. AeroViz/dataProcess/Optical/__pycache__/__init__.cpython-312.pyc +0 -0
  5. AeroViz/dataProcess/Optical/__pycache__/mie_theory.cpython-312.pyc +0 -0
  6. AeroViz/dataProcess/Optical/_absorption.py +2 -0
  7. AeroViz/dataProcess/SizeDistr/__pycache__/__init__.cpython-312.pyc +0 -0
  8. AeroViz/dataProcess/VOC/__pycache__/__init__.cpython-312.pyc +0 -0
  9. AeroViz/dataProcess/__pycache__/__init__.cpython-312.pyc +0 -0
  10. AeroViz/dataProcess/core/__pycache__/__init__.cpython-312.pyc +0 -0
  11. AeroViz/plot/__pycache__/__init__.cpython-312.pyc +0 -0
  12. AeroViz/plot/__pycache__/bar.cpython-312.pyc +0 -0
  13. AeroViz/plot/__pycache__/box.cpython-312.pyc +0 -0
  14. AeroViz/plot/__pycache__/pie.cpython-312.pyc +0 -0
  15. AeroViz/plot/__pycache__/radar.cpython-312.pyc +0 -0
  16. AeroViz/plot/__pycache__/regression.cpython-312.pyc +0 -0
  17. AeroViz/plot/__pycache__/scatter.cpython-312.pyc +0 -0
  18. AeroViz/plot/__pycache__/violin.cpython-312.pyc +0 -0
  19. AeroViz/plot/distribution/__pycache__/__init__.cpython-312.pyc +0 -0
  20. AeroViz/plot/distribution/__pycache__/distribution.cpython-312.pyc +0 -0
  21. AeroViz/plot/meteorology/__pycache__/CBPF.cpython-312.pyc +0 -0
  22. AeroViz/plot/meteorology/__pycache__/__init__.cpython-312.pyc +0 -0
  23. AeroViz/plot/meteorology/__pycache__/hysplit.cpython-312.pyc +0 -0
  24. AeroViz/plot/meteorology/__pycache__/wind_rose.cpython-312.pyc +0 -0
  25. AeroViz/plot/optical/__pycache__/__init__.cpython-312.pyc +0 -0
  26. AeroViz/plot/optical/__pycache__/optical.cpython-312.pyc +0 -0
  27. AeroViz/plot/templates/__init__.py +1 -1
  28. AeroViz/plot/templates/__pycache__/__init__.cpython-312.pyc +0 -0
  29. AeroViz/plot/templates/__pycache__/ammonium_rich.cpython-312.pyc +0 -0
  30. AeroViz/plot/templates/__pycache__/contour.cpython-312.pyc +0 -0
  31. AeroViz/plot/templates/__pycache__/corr_matrix.cpython-312.pyc +0 -0
  32. AeroViz/plot/templates/__pycache__/diurnal_pattern.cpython-312.pyc +0 -0
  33. AeroViz/plot/templates/__pycache__/koschmieder.cpython-312.pyc +0 -0
  34. AeroViz/plot/templates/__pycache__/metal_heatmap.cpython-312.pyc +0 -0
  35. AeroViz/plot/templates/corr_matrix.py +168 -2
  36. AeroViz/plot/templates/koschmieder.py +1 -1
  37. AeroViz/plot/templates/metal_heatmap.py +15 -6
  38. AeroViz/plot/timeseries/__pycache__/__init__.cpython-312.pyc +0 -0
  39. AeroViz/plot/timeseries/__pycache__/template.cpython-312.pyc +0 -0
  40. AeroViz/plot/timeseries/__pycache__/timeseries.cpython-312.pyc +0 -0
  41. AeroViz/plot/timeseries/timeseries.py +96 -52
  42. AeroViz/plot/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  43. AeroViz/plot/utils/__pycache__/_color.cpython-312.pyc +0 -0
  44. AeroViz/plot/utils/__pycache__/_unit.cpython-312.pyc +0 -0
  45. AeroViz/plot/utils/__pycache__/plt_utils.cpython-312.pyc +0 -0
  46. AeroViz/plot/utils/__pycache__/sklearn_utils.cpython-312.pyc +0 -0
  47. AeroViz/rawDataReader/__init__.py +154 -59
  48. AeroViz/rawDataReader/__pycache__/__init__.cpython-312.pyc +0 -0
  49. AeroViz/rawDataReader/config/__pycache__/__init__.cpython-312.pyc +0 -0
  50. AeroViz/rawDataReader/config/__pycache__/supported_instruments.cpython-312.pyc +0 -0
  51. AeroViz/rawDataReader/config/supported_instruments.py +7 -4
  52. AeroViz/rawDataReader/core/__init__.py +176 -86
  53. AeroViz/rawDataReader/core/__pycache__/__init__.cpython-312.pyc +0 -0
  54. AeroViz/rawDataReader/core/__pycache__/logger.cpython-312.pyc +0 -0
  55. AeroViz/rawDataReader/core/__pycache__/qc.cpython-312.pyc +0 -0
  56. AeroViz/rawDataReader/core/logger.py +14 -10
  57. AeroViz/rawDataReader/core/qc.py +1 -1
  58. AeroViz/rawDataReader/script/AE33.py +1 -1
  59. AeroViz/rawDataReader/script/BAM1020.py +35 -0
  60. AeroViz/rawDataReader/script/NEPH.py +6 -10
  61. AeroViz/rawDataReader/script/SMPS.py +20 -6
  62. AeroViz/rawDataReader/script/TEOM.py +15 -3
  63. AeroViz/rawDataReader/script/__init__.py +1 -0
  64. AeroViz/rawDataReader/script/__pycache__/AE33.cpython-312.pyc +0 -0
  65. AeroViz/rawDataReader/script/__pycache__/AE43.cpython-312.pyc +0 -0
  66. AeroViz/rawDataReader/script/__pycache__/APS.cpython-312.pyc +0 -0
  67. AeroViz/rawDataReader/script/__pycache__/Aurora.cpython-312.pyc +0 -0
  68. AeroViz/rawDataReader/script/__pycache__/BAM1020.cpython-312.pyc +0 -0
  69. AeroViz/rawDataReader/script/__pycache__/BC1054.cpython-312.pyc +0 -0
  70. AeroViz/rawDataReader/script/__pycache__/EPA.cpython-312.pyc +0 -0
  71. AeroViz/rawDataReader/script/__pycache__/GRIMM.cpython-312.pyc +0 -0
  72. AeroViz/rawDataReader/script/__pycache__/IGAC.cpython-312.pyc +0 -0
  73. AeroViz/rawDataReader/script/__pycache__/MA350.cpython-312.pyc +0 -0
  74. AeroViz/rawDataReader/script/__pycache__/Minion.cpython-312.pyc +0 -0
  75. AeroViz/rawDataReader/script/__pycache__/NEPH.cpython-312.pyc +0 -0
  76. AeroViz/rawDataReader/script/__pycache__/OCEC.cpython-312.pyc +0 -0
  77. AeroViz/rawDataReader/script/__pycache__/SMPS.cpython-312.pyc +0 -0
  78. AeroViz/rawDataReader/script/__pycache__/TEOM.cpython-312.pyc +0 -0
  79. AeroViz/rawDataReader/script/__pycache__/VOC.cpython-312.pyc +0 -0
  80. AeroViz/rawDataReader/script/__pycache__/XRF.cpython-312.pyc +0 -0
  81. AeroViz/rawDataReader/script/__pycache__/__init__.cpython-312.pyc +0 -0
  82. AeroViz/tools/__pycache__/__init__.cpython-312.pyc +0 -0
  83. AeroViz/tools/__pycache__/database.cpython-312.pyc +0 -0
  84. AeroViz/tools/__pycache__/dataclassifier.cpython-312.pyc +0 -0
  85. {AeroViz-0.1.13.dist-info → AeroViz-0.1.15.dist-info}/METADATA +14 -15
  86. {AeroViz-0.1.13.dist-info → AeroViz-0.1.15.dist-info}/RECORD +89 -87
  87. {AeroViz-0.1.13.dist-info → AeroViz-0.1.15.dist-info}/WHEEL +1 -1
  88. {AeroViz-0.1.13.dist-info → AeroViz-0.1.15.dist-info}/LICENSE +0 -0
  89. {AeroViz-0.1.13.dist-info → AeroViz-0.1.15.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  from datetime import datetime
2
2
  from pathlib import Path
3
- from typing import Any
3
+ from typing import Literal
4
4
 
5
5
  from pandas import Grouper, Timedelta
6
6
 
@@ -10,66 +10,124 @@ from AeroViz.rawDataReader.script import *
10
10
  __all__ = ['RawDataReader']
11
11
 
12
12
  SUPPORTED_INSTRUMENTS = [
13
- NEPH, Aurora, SMPS, GRIMM, APS, AE33, AE43, BC1054,
14
- MA350, TEOM, OCEC, IGAC, VOC, EPA, Minion
13
+ NEPH, Aurora, SMPS, APS, GRIMM, AE33, AE43, BC1054,
14
+ MA350, BAM1020, TEOM, OCEC, IGAC, VOC, EPA, Minion
15
15
  ]
16
16
 
17
+ SIZE_RANGE_INSTRUMENTS = ['SMPS', 'APS', 'GRIMM']
17
18
 
18
- def RawDataReader(instrument_name: str,
19
+
20
+ def RawDataReader(instrument: str,
19
21
  path: Path | str,
20
- reset: bool = False,
22
+ reset: bool | str = False,
21
23
  qc: bool | str = True,
22
- qc_freq: str | None = None,
23
- rate: bool = True,
24
- append_data: bool = False,
25
- start: datetime = None,
26
- end: datetime = None,
24
+ start: datetime | str = None,
25
+ end: datetime | str = None,
27
26
  mean_freq: str = '1h',
28
- csv_out: bool = True,
29
- **kwargs: Any):
27
+ size_range: tuple[float, float] | None = None,
28
+ suppress_warnings: bool = False,
29
+ log_level: Literal['DEBUG', 'INFO', 'WARNING', 'ERROR'] = 'INFO',
30
+ **kwargs):
30
31
  """
31
32
  Factory function to instantiate the appropriate reader module for a given instrument and
32
33
  return the processed data over the specified time range.
33
34
 
34
- :param instrument_name: The name of the instrument for which to read data. Must be a valid key in the `meta` dictionary.
35
- :param path: The directory where raw data files for the instrument are stored.
36
- :param reset: If True, reset the state and reprocess the data from scratch.
37
- :param qc: If True, apply quality control (QC) to the raw data.
38
- :param qc_freq: Frequency at which to perform QC. Must be one of 'W', 'M', 'Q', 'Y' for weekly, monthly, quarterly, or yearly.
39
- :param rate: If True, calculate rates from the data.
40
- :param append_data: If True, append new data to the existing dataset instead of overwriting it.
41
- :param start: Start time for filtering the data. If None, no start time filtering will be applied.
42
- :param end: End time for filtering the data. If None, no end time filtering will be applied.
43
- :param mean_freq: Resampling frequency for averaging the data. Example: '1h' for hourly mean.
44
- :param csv_out: If True, output the processed data as a CSV file.
45
-
46
- :return: An instance of the reader module corresponding to the specified instrument, which processes the data and returns it in a usable format.
47
-
48
- :raises ValueError: If the `instrument_name` provided is not a valid key in the `meta` dictionary.
49
- :raises ValueError: If the specified path does not exist or is not a directory.
50
- :raises ValueError: If the QC frequency is invalid.
51
- :raises ValueError: If start and end times are not both provided or are invalid.
52
- :raises ValueError: If the mean_freq is not a valid frequency string.
53
-
54
- :Example:
55
-
56
- To read and process data for the BC1054 instrument:
57
-
35
+ Parameters
36
+ ----------
37
+ instrument : str
38
+ The instrument name for which to read data, must be a valid key in the meta dictionary
39
+
40
+ path : Path or str
41
+ The directory where raw data files for the instrument are stored
42
+
43
+ reset : bool or str
44
+ Data processing control mode:
45
+ False (default) - Use existing processed data if available
46
+ True - Force reprocess all data from raw files
47
+ 'append' - Add new data to existing processed data
48
+
49
+ qc : bool or str
50
+ Quality control and rate calculation mode:
51
+ True (default) - Apply QC and calculate overall rates
52
+ False - Skip QC and return raw data only
53
+ str - Calculate rates at specified intervals:
54
+ 'W' - Weekly rates
55
+ 'MS' - Month start rates
56
+ 'QS' - Quarter start rates
57
+ 'YS' - Year start rates
58
+ Can add number prefix (e.g., '2MS' for bi-monthly)
59
+
60
+ start : datetime
61
+ Start time for filtering the data
62
+
63
+ end : datetime
64
+ End time for filtering the data
65
+
66
+ mean_freq : str
67
+ Resampling frequency for averaging the data (e.g., '1h' for hourly mean)
68
+
69
+ size_range : tuple[float, float], optional
70
+ Size range in nanometers (min_size, max_size) for SMPS/APS data filtering
71
+
72
+ suppress_warnings : bool, optional
73
+ Whether to suppress warning messages (default: False)
74
+
75
+ log_level : {'DEBUG', 'INFO', 'WARNING', 'ERROR'}
76
+ Logging level (default: 'INFO')
77
+
78
+ **kwargs
79
+ Additional arguments to pass to the reader module
80
+
81
+ Returns
82
+ -------
83
+ pd.DataFrame
84
+ Processed data with specified QC and time range
85
+
86
+ Raises
87
+ ------
88
+ ValueError
89
+ If instrument name is invalid
90
+ If path does not exist
91
+ If QC frequency is invalid
92
+ If time range is invalid
93
+ If mean_freq format is invalid
94
+
95
+ Examples
96
+ --------
97
+ >>> from AeroViz import RawDataReader
98
+ >>>
99
+ >>> # Using string inputs
100
+ >>> df_ae33 = RawDataReader(
101
+ ... instrument='AE33',
102
+ ... path='/path/to/your/data/folder',
103
+ ... reset=True,
104
+ ... qc='1MS',
105
+ ... start='2024-01-01',
106
+ ... end='2024-06-30',
107
+ ... mean_freq='1h',
108
+ ... )
109
+
110
+ >>> # Using Path and datetime objects
58
111
  >>> from pathlib import Path
59
112
  >>> from datetime import datetime
60
113
  >>>
61
- >>> data = RawDataReader(
62
- ... instrument_name='BC1054',
63
- ... path=Path('/path/to/data'),
64
- ... start=datetime(2024, 2, 1),
65
- ... end=datetime(2024, 7, 31))
114
+ >>> df_ae33 = RawDataReader(
115
+ ... instrument='AE33',
116
+ ... path=Path('/path/to/your/data/folder'),
117
+ ... reset=True,
118
+ ... qc='1MS',
119
+ ... start=datetime(2024, 1, 1),
120
+ ... end=datetime(2024, 6, 30),
121
+ ... mean_freq='1h',
122
+ ... )
66
123
  """
124
+
67
125
  # Mapping of instrument names to their respective classes
68
126
  instrument_class_map = {cls.__name__.split('.')[-1]: cls for cls in SUPPORTED_INSTRUMENTS}
69
127
 
70
128
  # Check if the instrument name is in the map
71
- if instrument_name not in meta.keys():
72
- raise ValueError(f"Instrument name '{instrument_name}' is not valid. \nMust be one of: {list(meta.keys())}")
129
+ if instrument not in meta.keys():
130
+ raise ValueError(f"Instrument name '{instrument}' is not valid. \nMust be one of: {list(meta.keys())}")
73
131
 
74
132
  # Check if path exists and is a directory
75
133
  if not isinstance(path, Path):
@@ -78,22 +136,38 @@ def RawDataReader(instrument_name: str,
78
136
  raise FileNotFoundError(f"The specified path '{path}' does not exist or is not a directory.")
79
137
 
80
138
  # Validate the QC frequency
81
- if qc_freq is not None:
139
+ if isinstance(qc, str):
82
140
  try:
83
- Grouper(freq=qc_freq)
84
- except ValueError as e:
85
- raise ValueError(f"Invalid frequency: {qc_freq}. Error: {str(e)}")
86
- except TypeError as e:
87
- raise ValueError(f"Invalid frequency type: {qc_freq}. Frequency should be a string.")
88
-
89
- if start and end:
90
- if end.hour == 0 and end.minute == 0 and end.second == 0:
91
- end = end.replace(hour=23, minute=59, second=59)
92
- else:
141
+ Grouper(freq=qc)
142
+ except (ValueError, TypeError):
143
+ raise ValueError(f"Invalid frequency: {qc}. Must be one of: "
144
+ f"W (week), MS (month start), QS (quarter start), YS (year start)")
145
+
146
+ # Convert and verify input times
147
+ if not (start and end):
93
148
  raise ValueError("Both start and end times must be provided.")
149
+
150
+ # Convert start time if it's a string
151
+ if isinstance(start, str):
152
+ try:
153
+ start = datetime.fromisoformat(start.replace('Z', '+00:00'))
154
+ except ValueError as e:
155
+ raise ValueError(
156
+ f"Invalid start time format. Please use ISO format (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS): {e}")
157
+
158
+ # Convert end time if it's a string
159
+ if isinstance(end, str):
160
+ try:
161
+ end = datetime.fromisoformat(end.replace('Z', '+00:00'))
162
+ except ValueError as e:
163
+ raise ValueError(
164
+ f"Invalid end time format. Please use ISO format (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS): {e}")
165
+
94
166
  if end <= start:
95
167
  raise ValueError(f"Invalid time range: start {start} is after end {end}")
96
168
 
169
+ end = end.replace(hour=23, minute=59, second=59) if end.hour == 0 and end.minute == 0 else end
170
+
97
171
  # Verify that mean_freq format
98
172
  try:
99
173
  Timedelta(mean_freq)
@@ -101,19 +175,40 @@ def RawDataReader(instrument_name: str,
101
175
  raise ValueError(
102
176
  f"Invalid mean_freq: '{mean_freq}'. It should be a valid frequency string (e.g., '1h', '30min', '1D').")
103
177
 
178
+ # Validate size range
179
+ if size_range is not None:
180
+ if instrument not in SIZE_RANGE_INSTRUMENTS:
181
+ raise ValueError(f"Size range filtering is only supported for {SIZE_RANGE_INSTRUMENTS}")
182
+
183
+ min_size, max_size = size_range
184
+ if not isinstance(min_size, (int, float)) or not isinstance(max_size, (int, float)):
185
+ raise ValueError("Size range values must be numeric")
186
+ if min_size >= max_size:
187
+ raise ValueError("Minimum size must be less than maximum size")
188
+
189
+ if instrument == 'SMPS':
190
+ if not (1 <= min_size <= 1000) or not (1 <= max_size <= 1000):
191
+ raise ValueError("SMPS size range must be between 1 and 1000 nm")
192
+ elif instrument == 'APS':
193
+ if not (500 <= min_size <= 20000) or not (500 <= max_size <= 20000):
194
+ raise ValueError("APS size range must be between 500 and 20000 nm")
195
+
196
+ kwargs.update({'size_range': size_range})
197
+
198
+ kwargs.update({
199
+ 'suppress_warnings': suppress_warnings,
200
+ 'log_level': log_level
201
+ })
202
+
104
203
  # Instantiate the class and return the instance
105
- reader_module = instrument_class_map[instrument_name].Reader(
204
+ reader_module = instrument_class_map[instrument].Reader(
106
205
  path=path,
107
206
  reset=reset,
108
207
  qc=qc,
109
- qc_freq=qc_freq,
110
- rate=rate,
111
- append_data=append_data,
112
208
  **kwargs
113
209
  )
114
210
  return reader_module(
115
211
  start=start,
116
212
  end=end,
117
213
  mean_freq=mean_freq,
118
- csv_out=csv_out,
119
214
  )
@@ -58,6 +58,13 @@ meta = {
58
58
  "deter_key": {"BC Mass Conc. (880 nm)": ["BC5"]},
59
59
  },
60
60
 
61
+ "BAM1020": {
62
+ "pattern": ["*.csv"],
63
+ "freq": "1h",
64
+ "deter_key": {
65
+ "Mass Conc.": ["Conc"]},
66
+ },
67
+
61
68
  "TEOM": {
62
69
  "pattern": ["*.csv"],
63
70
  "freq": "6min",
@@ -71,10 +78,6 @@ meta = {
71
78
  "pattern": ["*LCRes.csv"],
72
79
  "freq": "1h",
73
80
  "deter_key": {
74
- "Thermal OC": ["Thermal_OC"],
75
- "Thermal EC": ["Thermal_EC"],
76
- "Optical OC": ["Optical_OC"],
77
- "Optical EC": ["Optical_EC"],
78
81
  "Thermal OC & EC": ["Thermal_OC", "Thermal_EC"],
79
82
  "Optical OC & EC": ["Optical_OC", "Optical_EC"],
80
83
  },