apmtools 0.0.1__tar.gz

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.
apmtools-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 federlorenz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.3
2
+ Name: apmtools
3
+ Version: 0.0.1
4
+ Summary: A collection of tools for processing air pollution monitoring data
5
+ Project-URL: Homepage, https://github.com/federlorenz/apmtools
6
+ Author-email: Federico Lorenzetti <lorenzetti.federico@gmail.com>
7
+ License-File: LICENSE
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+
14
+ # apmtools
15
+ A collection of tools for processing air pollution monitoring data
@@ -0,0 +1,2 @@
1
+ # apmtools
2
+ A collection of tools for processing air pollution monitoring data
@@ -0,0 +1,21 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "apmtools"
7
+ version = "0.0.1"
8
+ authors = [
9
+ { name="Federico Lorenzetti", email="lorenzetti.federico@gmail.com" },
10
+ ]
11
+ description = "A collection of tools for processing air pollution monitoring data"
12
+ readme = "README.md"
13
+ requires-python = ">=3.8"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+
20
+ [project.urls]
21
+ Homepage = "https://github.com/federlorenz/apmtools"
File without changes
@@ -0,0 +1,274 @@
1
+ import pandas as pd
2
+ import numpy as np
3
+
4
+
5
+ class DictionaryPlus(dict):
6
+ def __init__(self, *args, **kwargs):
7
+ dict.__init__(self, *args, **kwargs)
8
+
9
+ @property
10
+ def _constructor(self):
11
+ return DictionaryPlus
12
+
13
+ def show(self, number=0):
14
+ """
15
+ return an element of a dictionary
16
+ If number is not specified, returns the values associated with the first key
17
+ """
18
+ try:
19
+ return (self[list(self.keys())[number]])
20
+ except:
21
+ print("something's wrong")
22
+
23
+ def subset(self, filter_dict):
24
+ """
25
+ Return a subset of a dictionary, specified in filter_dict (itself a dictionary)
26
+ filter_dict is {attrib:["attrib_value_x","attrib_value_y",..]}, where
27
+ attrib is an attribute of the elements of dictionary, and attrib_value is a list
28
+ of the values of such attrib that the elements of returned dictionary can have
29
+ """
30
+ if type(filter_dict) != type(dict()):
31
+ print("subset function error: type filter_dict should be dict")
32
+ return
33
+ return_dict = self
34
+ for i, j in filter_dict.items():
35
+ a = {}
36
+ for key, value in return_dict.items():
37
+ if hasattr(value, 'metadata') & (type(value.metadata) == type({})) & (i in value.metadata.keys()):
38
+ try:
39
+ if value.__getattr__('metadata')[i] in j:
40
+ a[key] = value
41
+ except:
42
+ pass
43
+ else:
44
+ try:
45
+ if value.__getattr__(i) in j:
46
+ a[key] = value
47
+ except:
48
+ pass
49
+
50
+ return DictionaryPlus(return_dict)
51
+
52
+ def set_attrib(self, attribute):
53
+ """
54
+ returns the set of attribute values for dictionary
55
+ """
56
+ return_set = set()
57
+ for i in self.values():
58
+ if hasattr(i, 'metadata') & (type(i.metadata) == type({})) & (attribute in i.metadata.keys()):
59
+ try:
60
+ return_set.add(i.__getattr__('metadata')[attribute])
61
+ except:
62
+ pass
63
+ else:
64
+ try:
65
+ return_set.add(i.__getattr__(attribute))
66
+ except:
67
+ pass
68
+
69
+ return return_set
70
+
71
+ class Apm(pd.DataFrame):
72
+
73
+ def __init__(self, *args, **kwargs):
74
+ pd.DataFrame.__init__(self, *args, **kwargs)
75
+ self.meta = {}
76
+ _metadata = ['meta']
77
+
78
+ @property
79
+ def _constructor(self):
80
+ return Apm
81
+
82
+ @property
83
+ def _constructor_sliced(self):
84
+ return ApmSeries
85
+
86
+ @property
87
+ def end(self):
88
+ if len(self) == 0:
89
+ return np.nan
90
+ else:
91
+ return self.index[-1]
92
+
93
+ @property
94
+ def start(self):
95
+ if len(self) == 0:
96
+ return np.nan
97
+ else:
98
+ return self.index[0]
99
+
100
+ @property
101
+ def length(self):
102
+ if len(self) == 0:
103
+ return np.nan
104
+ else:
105
+ return len(self)*(self.index[1]-self.index[0])
106
+
107
+ def date_time_filter(
108
+ self,
109
+ time_start=None,
110
+ time_end=None,
111
+ date_start=None,
112
+ date_end=None,
113
+ day=None):
114
+ """Filters a file by time or date\n
115
+ Input time as dt.time(hrs,min), and date as dt.date(year,month,day),\n
116
+ and day as [1,2] list of days, with 1 Monday and 7 Sunday,\n
117
+ if selecting a specific date interval that includes time, just specify\n
118
+ that as dt.datetime interval under date_start and date_end"""
119
+ if date_start is not None:
120
+ self = self.loc[self.index >= date_start]
121
+ if date_end is not None:
122
+ self = self.loc[self.index <= date_end]
123
+ if (time_start is not None) & (time_end is not None):
124
+ if time_start > time_end:
125
+ self = self.loc[(self.index.time >= time_start)
126
+ | (self.index.time < time_end)]
127
+ else:
128
+ self = self.loc[(self.index.time >= time_start)
129
+ & (self.index.time < time_end)]
130
+ if (time_start is not None) & (time_end is None):
131
+ self = self.loc[self.index.time >= time_start]
132
+ if (time_start is None) & (time_end is not None):
133
+ self = self.loc[self.index.time <= time_end]
134
+
135
+ if day is not None:
136
+ self = self.loc[[a in day for a in [self.index[i].date().isoweekday()
137
+ for i in range(len(self.index))]]]
138
+
139
+ return self
140
+
141
+ class ApmSeries(pd.Series):
142
+ def __init__(self, *args, **kwargs):
143
+ pd.Series.__init__(self, *args, **kwargs)
144
+ _metadata = ['meta']
145
+
146
+ @property
147
+ def _constructor(self):
148
+ return ApmSeries
149
+
150
+ @property
151
+ def end(self):
152
+ if len(self) == 0:
153
+ return np.nan
154
+ else:
155
+ return self.index[-1]
156
+
157
+ @property
158
+ def start(self):
159
+ if len(self) == 0:
160
+ return np.nan
161
+ else:
162
+ return self.index[0]
163
+
164
+ @property
165
+ def length(self):
166
+ if len(self) == 0:
167
+ return np.nan
168
+ else:
169
+ return len(self)*(self.index[1]-self.index[0])
170
+
171
+ def date_time_filter(
172
+ self,
173
+ time_start=None,
174
+ time_end=None,
175
+ date_start=None,
176
+ date_end=None,
177
+ day=None):
178
+ """Filters a file by time or date\n
179
+ Input time as dt.time(hrs,min), and date as dt.date(year,month,day),\n
180
+ and day as [1,2] list of days, with 1 Monday and 7 Sunday,\n
181
+ if selecting a specific date interval that includes time, just specify\n
182
+ that as dt.datetime interval under date_start and date_end"""
183
+ if date_start is not None:
184
+ self = self.loc[self.index >= date_start]
185
+ if date_end is not None:
186
+ self = self.loc[self.index <= date_end]
187
+ if (time_start is not None) & (time_end is not None):
188
+ if time_start > time_end:
189
+ self = self.loc[(self.index.time >= time_start)
190
+ | (self.index.time < time_end)]
191
+ else:
192
+ self = self.loc[(self.index.time >= time_start)
193
+ & (self.index.time < time_end)]
194
+ if (time_start is not None) & (time_end is None):
195
+ self = self.loc[self.index.time >= time_start]
196
+ if (time_start is None) & (time_end is not None):
197
+ self = self.loc[self.index.time <= time_end]
198
+
199
+ if day is not None:
200
+ self = self.loc[[a in day for a in [self.index[i].date().isoweekday()
201
+ for i in range(len(self.index))]]]
202
+
203
+ return self
204
+
205
+ class Sum(Apm):
206
+ def __init__(self, *args, **kwargs):
207
+ Apm.__init__(self, *args, **kwargs)
208
+ self.metadata = {}
209
+ _metadata = ['meta']
210
+
211
+ @property
212
+ def _constructor(self):
213
+ return Sum
214
+
215
+ @property
216
+ def _constructor_sliced(self):
217
+ return SumSeries
218
+
219
+ @property
220
+ def number_of_events(self):
221
+ if len(self) == 0:
222
+ return np.nan
223
+ else:
224
+ return len(self["cooking_counter"].value_counts())
225
+
226
+ @property
227
+ def max_event_length(self):
228
+ if len(self) == 0:
229
+ return np.nan
230
+ else:
231
+ return (self["cooking_counter"].value_counts().max())*((self.index[1]-self.index[0]))
232
+
233
+ @property
234
+ def min_event_length(self):
235
+ if len(self) == 0:
236
+ return np.nan
237
+ else:
238
+ return (self["cooking_counter"].value_counts().min())*((self.index[1]-self.index[0]))
239
+
240
+ @property
241
+ def mean_event_length(self):
242
+ if len(self) == 0:
243
+ return np.nan
244
+ else:
245
+ return (self["cooking_counter"].value_counts().mean())*((self.index[1]-self.index[0]))
246
+
247
+ @property
248
+ def cooking_time_per_day(self):
249
+ if len(self) == 0:
250
+ return np.nan
251
+ elif len(self["cooking_counter"].value_counts()) == 0:
252
+ return pd.Timedelta("00:00:00")
253
+ else:
254
+ return ((self["cooking_counter"].value_counts().sum())*((self.index[1]-self.index[0])) / self.length) * \
255
+ pd.Timedelta("24:00:00")
256
+
257
+ @property
258
+ def cooking_events_per_day(self):
259
+ if len(self) == 0:
260
+ return np.nan
261
+ elif len(self["cooking_counter"].value_counts()) == 0:
262
+ return 0
263
+ else:
264
+ return self.number_of_events / \
265
+ (self.length.total_seconds() / (3600 * 24))
266
+
267
+ class SumSeries(ApmSeries):
268
+ def __init__(self, *args, **kwargs):
269
+ ApmSeries.__init__(self, *args, **kwargs)
270
+ _metadata = ['meta']
271
+
272
+ @property
273
+ def _constructor(self):
274
+ return SumSeries
@@ -0,0 +1,61 @@
1
+ def show(dictionary, number=0):
2
+ """
3
+ return an element of a dictionary
4
+ If number is not specified, returns the values associated with the first key
5
+ """
6
+ try:
7
+ return(dictionary[list(dictionary.keys())[number]])
8
+ except:
9
+ print("something's wrong")
10
+
11
+ def subset(dictionary, filter_dict):
12
+ """
13
+ Return a subset of a dictionary, specified in filter_dict (itself a dictionary)
14
+ filter_dict is {attrib:["attrib_value_x","attrib_value_y",..]}, where
15
+ attrib is an attribute of the elements of dictionary, or a metadata attrib and attrib_value is a list
16
+ of the values of such attrib that the elements of returned dictionary can have
17
+ """
18
+ if type(dictionary) != type(dict()):
19
+ print("subset function error: type dictionary should be dict")
20
+ return
21
+ if type(filter_dict) != type(dict()):
22
+ print("subset function error: type filter_dict should be dict")
23
+ return
24
+ return_dict = dictionary
25
+ for i, j in filter_dict.items():
26
+ a = {}
27
+ for key,value in return_dict.items():
28
+ if hasattr(value,'meta') & (type(value.meta) == type({})) & (i in value.meta.keys()):
29
+ try:
30
+ if value.__getattr__('meta')[i] in j:
31
+ a[key] = value
32
+ except:
33
+ pass
34
+ else:
35
+ try:
36
+ if value.__getattr__(i) in j:
37
+ a[key] = value
38
+ except:
39
+ pass
40
+ return_dict = a
41
+
42
+ return return_dict
43
+
44
+ def set_attrib(dictionary, attribute):
45
+ """
46
+ returns the set of attribute values for dictionary
47
+ """
48
+ return_set = set()
49
+ for i in dictionary.values():
50
+ if hasattr(i, 'meta') & (type(i.meta) == type({})) & (attribute in i.meta.keys()):
51
+ try:
52
+ return_set.add(i.__getattr__('meta')[attribute])
53
+ except:
54
+ pass
55
+ else:
56
+ try:
57
+ return_set.add(i.__getattr__(attribute))
58
+ except:
59
+ pass
60
+
61
+ return return_set