apmtools 0.2.32__tar.gz → 0.2.34__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.2.32 → apmtools-0.2.34}/PKG-INFO +1 -1
- {apmtools-0.2.32 → apmtools-0.2.34}/pyproject.toml +1 -1
- {apmtools-0.2.32 → apmtools-0.2.34}/src/apmtools/classes.py +110 -4
- {apmtools-0.2.32 → apmtools-0.2.34}/src/apmtools/data_processing.py +14 -1
- {apmtools-0.2.32 → apmtools-0.2.34}/src/apmtools/units.py +4 -0
- {apmtools-0.2.32 → apmtools-0.2.34}/.gitignore +0 -0
- {apmtools-0.2.32 → apmtools-0.2.34}/LICENSE +0 -0
- {apmtools-0.2.32 → apmtools-0.2.34}/README.md +0 -0
- {apmtools-0.2.32 → apmtools-0.2.34}/src/apmtools/__init__.py +0 -0
- {apmtools-0.2.32 → apmtools-0.2.34}/src/apmtools/functions.py +0 -0
- {apmtools-0.2.32 → apmtools-0.2.34}/src/apmtools/legacy.py +0 -0
- {apmtools-0.2.32 → apmtools-0.2.34}/src/apmtools/shiny/__init__.py +0 -0
- {apmtools-0.2.32 → apmtools-0.2.34}/src/apmtools/shiny/summary.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: apmtools
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.34
|
|
4
4
|
Summary: A collection of tools for processing air pollution monitoring data
|
|
5
5
|
Project-URL: Homepage, https://github.com/federlorenz/apmtools
|
|
6
6
|
Author-email: Federico Lorenzetti <lorenzetti.federico@gmail.com>
|
|
@@ -8,7 +8,7 @@ from io import StringIO
|
|
|
8
8
|
from csv import writer
|
|
9
9
|
from dateutil.parser import parse
|
|
10
10
|
|
|
11
|
-
from .units import upas_units,lascar_units,purple_units
|
|
11
|
+
from .units import upas_units, lascar_units, purple_units, lcm_units
|
|
12
12
|
|
|
13
13
|
class DictionaryPlus(dict):
|
|
14
14
|
def __init__(self, *args, **kwargs):
|
|
@@ -451,11 +451,11 @@ class Dataset(DictionaryPlus):
|
|
|
451
451
|
|
|
452
452
|
def scan_folder(self, directory="./", levels=[], level=0, monitor=None, levels_dict=None, gmt_timezone_shift=0, interpolate=False, add_m={}):
|
|
453
453
|
|
|
454
|
-
from .data_processing import upas_processing, lascar_processing, purple_processing
|
|
454
|
+
from .data_processing import upas_processing, lascar_processing, purple_processing, lcm_processing
|
|
455
455
|
|
|
456
|
-
if len(set(levels).intersection(set(["identifier", "start", "end", "length", "time", "pm25", "pm25correctedrh", "pm25correctedrhandgrav", "filterid", "grav_not", "grav"]))) > 0:
|
|
456
|
+
if len(set(levels).intersection(set(["identifier", "start", "end", "length", "time", "pm25", "pm25correctedrh", "pm25correctedrhandgrav", "filterid", "grav_not", "grav","PM2.5","PM10","C02","NO2"]))) > 0:
|
|
457
457
|
print(
|
|
458
|
-
f"the following levels names are not allowed: {set(levels).intersection(set(["identifier", "start", "end", "length", "time", "pm25", "pm25correctedrh", "pm25correctedrhandgrav", "filterid", "grav_not", "grav"]))}. Please choose different level names")
|
|
458
|
+
f"the following levels names are not allowed: {set(levels).intersection(set(["identifier", "start", "end", "length", "time", "pm25", "pm25correctedrh", "pm25correctedrhandgrav", "filterid", "grav_not", "grav","PM2.5","PM10","C02","NO2"]))}. Please choose different level names")
|
|
459
459
|
return
|
|
460
460
|
if levels_dict == None:
|
|
461
461
|
levels_dict = dict(
|
|
@@ -473,6 +473,8 @@ class Dataset(DictionaryPlus):
|
|
|
473
473
|
return "purple"
|
|
474
474
|
case ['Time', 'CO(ppm)']:
|
|
475
475
|
return "lascar"
|
|
476
|
+
case ['date','sensorName']:
|
|
477
|
+
return "lcm"
|
|
476
478
|
case _:
|
|
477
479
|
return None
|
|
478
480
|
except:
|
|
@@ -518,6 +520,21 @@ class Dataset(DictionaryPlus):
|
|
|
518
520
|
except:
|
|
519
521
|
print(
|
|
520
522
|
f"processing of file {directory}{j} failed. Is this a {monitor} file?")
|
|
523
|
+
case "lcm":
|
|
524
|
+
try:
|
|
525
|
+
processed = lcm_processing(
|
|
526
|
+
directory, file=j, interpolate_data=interpolate)
|
|
527
|
+
for k, v in levels_dict.items():
|
|
528
|
+
if (v not in ["None", "_", "-", None]) and (k not in ["monitor", "", None, "-", "_"]):
|
|
529
|
+
processed.m[k] = v
|
|
530
|
+
processed.m["rejected"] = False
|
|
531
|
+
processed.m["filename"] = j
|
|
532
|
+
for key, value in add_m.items():
|
|
533
|
+
processed.m[key] = value
|
|
534
|
+
self[str(uuid.uuid4())] = processed
|
|
535
|
+
except:
|
|
536
|
+
print(
|
|
537
|
+
f"processing of file {directory}{j} failed. Is this a {monitor} file?")
|
|
521
538
|
case "purple":
|
|
522
539
|
try:
|
|
523
540
|
processed = purple_processing(
|
|
@@ -559,6 +576,8 @@ class Dataset(DictionaryPlus):
|
|
|
559
576
|
return ("lascar", run_lascar())
|
|
560
577
|
elif x is Purple:
|
|
561
578
|
return ("purple", run_purple())
|
|
579
|
+
elif x is Lcm:
|
|
580
|
+
return ("lcm", run_lcm())
|
|
562
581
|
# elif x is Apm:
|
|
563
582
|
# return "Apm"
|
|
564
583
|
# elif x is PolarH10:
|
|
@@ -572,6 +591,8 @@ class Dataset(DictionaryPlus):
|
|
|
572
591
|
return "Upas"
|
|
573
592
|
case Lascar():
|
|
574
593
|
return "Lascar"
|
|
594
|
+
case Lcm():
|
|
595
|
+
return "Lcm"
|
|
575
596
|
case Purple():
|
|
576
597
|
return "Purple"
|
|
577
598
|
case Apm():
|
|
@@ -702,6 +723,58 @@ class Dataset(DictionaryPlus):
|
|
|
702
723
|
out["time"] = pd.to_datetime(out["time"])
|
|
703
724
|
return (Summary(out, metadata=set(columns2)))
|
|
704
725
|
|
|
726
|
+
def run_lcm():
|
|
727
|
+
a = 0.524
|
|
728
|
+
b = -0.0862
|
|
729
|
+
c = 5.75
|
|
730
|
+
d = self.subset(condition=lambda x: match_monitor(x) == "Lcm")
|
|
731
|
+
columns1 = ["identifier", "monitor",
|
|
732
|
+
"start", "end", "length", "time"]
|
|
733
|
+
columns2 = list(set(d.meta()))
|
|
734
|
+
columns3 = ["sensorName", "deviceId", "resolution",
|
|
735
|
+
"PM2.5", "PM10", "CO2", "NO2", "Temperature", "Humidity"]
|
|
736
|
+
columns4 = ["pm25correctedrh"]
|
|
737
|
+
|
|
738
|
+
buffer = StringIO()
|
|
739
|
+
with buffer as file:
|
|
740
|
+
df = writer(file, delimiter=",")
|
|
741
|
+
df.writerow(columns1+columns2+columns3+columns4)
|
|
742
|
+
count = 0
|
|
743
|
+
for k, v in d.items():
|
|
744
|
+
print(f"processing Lcm {count+1} out of {len(d)}")
|
|
745
|
+
v = v.dropna(subset="PM2.5")
|
|
746
|
+
identifier = k
|
|
747
|
+
start = v.start
|
|
748
|
+
end = v.end
|
|
749
|
+
length = v.length
|
|
750
|
+
for i in range(len(v)):
|
|
751
|
+
app = []
|
|
752
|
+
app.append(identifier)
|
|
753
|
+
app.append("lcm")
|
|
754
|
+
app.append(start)
|
|
755
|
+
app.append(end)
|
|
756
|
+
app.append(length)
|
|
757
|
+
app.append(v.index[i])
|
|
758
|
+
for m in columns2:
|
|
759
|
+
if m in v.m.keys():
|
|
760
|
+
app.append(v.m[m] if v.m[m] != None else "")
|
|
761
|
+
else:
|
|
762
|
+
app.append("")
|
|
763
|
+
for m in columns3:
|
|
764
|
+
app.append(v[m].iloc[i])
|
|
765
|
+
xx = (a*v["PM2.5"].iloc[i])+(b*v["Humidity"].iloc[i])+c
|
|
766
|
+
app.append(xx)
|
|
767
|
+
df.writerow(list(map(str, app)))
|
|
768
|
+
count += 1
|
|
769
|
+
file.seek(0)
|
|
770
|
+
out = pd.read_csv(file)
|
|
771
|
+
out["start"] = pd.to_datetime(out["start"])
|
|
772
|
+
out["end"] = pd.to_datetime(out["end"])
|
|
773
|
+
out["length"] = pd.to_timedelta(out["length"])
|
|
774
|
+
out["time"] = pd.to_datetime(out["time"])
|
|
775
|
+
return (Summary(out, metadata=set(columns2)))
|
|
776
|
+
|
|
777
|
+
|
|
705
778
|
def run_purple():
|
|
706
779
|
d = self.subset(condition=lambda x: match_monitor(x) == "Purple")
|
|
707
780
|
columns1 = ["identifier", "monitor",
|
|
@@ -819,6 +892,8 @@ class Dataset(DictionaryPlus):
|
|
|
819
892
|
return "Upas"
|
|
820
893
|
case Lascar():
|
|
821
894
|
return "Lascar"
|
|
895
|
+
case Lcm():
|
|
896
|
+
return "Lcm"
|
|
822
897
|
case Purple():
|
|
823
898
|
return "Purple"
|
|
824
899
|
case Apm():
|
|
@@ -1953,6 +2028,37 @@ class PurpleSeries(ApmSeries):
|
|
|
1953
2028
|
def _constructor(self):
|
|
1954
2029
|
return PurpleSeries
|
|
1955
2030
|
|
|
2031
|
+
class Lcm(Apm):
|
|
2032
|
+
monitor = "lcm"
|
|
2033
|
+
|
|
2034
|
+
def __init__(self, *args, **kwargs):
|
|
2035
|
+
Apm.__init__(self, *args, **kwargs)
|
|
2036
|
+
self.m = {}
|
|
2037
|
+
self.variable = "PM2.5"
|
|
2038
|
+
|
|
2039
|
+
@property
|
|
2040
|
+
def _constructor(self):
|
|
2041
|
+
return Lcm
|
|
2042
|
+
|
|
2043
|
+
@property
|
|
2044
|
+
def _constructor_sliced(self):
|
|
2045
|
+
return LcmSeries
|
|
2046
|
+
|
|
2047
|
+
@property
|
|
2048
|
+
def units(self):
|
|
2049
|
+
return lcm_units
|
|
2050
|
+
|
|
2051
|
+
class LcmSeries(ApmSeries):
|
|
2052
|
+
def __init__(self, *args, **kwargs):
|
|
2053
|
+
LcmSeries.__init__(self, *args, **kwargs)
|
|
2054
|
+
_metadata = ['m']
|
|
2055
|
+
|
|
2056
|
+
@property
|
|
2057
|
+
def _constructor(self):
|
|
2058
|
+
return LcmSeries
|
|
2059
|
+
|
|
2060
|
+
|
|
2061
|
+
|
|
1956
2062
|
class PolarH10(dict):
|
|
1957
2063
|
monitor = "polarh10"
|
|
1958
2064
|
def __init__(self, *args, **kwargs):
|
|
@@ -4,7 +4,7 @@ import pandas as pd
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import datetime as dt
|
|
6
6
|
import os as os
|
|
7
|
-
from .classes import Apm, Sum, PolarH10, DictionaryPlus, Grav_Filter, Upas, Lascar, Purple
|
|
7
|
+
from .classes import Apm, Sum, PolarH10, DictionaryPlus, Grav_Filter, Upas, Lascar, Purple, Lcm
|
|
8
8
|
from zipfile import ZipFile
|
|
9
9
|
from copy import deepcopy
|
|
10
10
|
from pandas.errors import EmptyDataError
|
|
@@ -841,6 +841,19 @@ def lascar_processing(directory, file, interpolation=1,interval="30 seconds", in
|
|
|
841
841
|
out = Lascar(df)
|
|
842
842
|
return out
|
|
843
843
|
|
|
844
|
+
|
|
845
|
+
def lcm_processing(directory, file, interpolation=1, interval="300 seconds", interpolate_data=True):
|
|
846
|
+
numeric = ["PM2.5", "PM10", "CO2", "NO2", "Temperature", "Humidity"]
|
|
847
|
+
dtformat = '%Y-%m-%dT%H:%M:%S'
|
|
848
|
+
df = pd.read_csv(directory+file, index_col="timestamp",
|
|
849
|
+
date_format={'Time': dtformat})
|
|
850
|
+
if interpolate_data:
|
|
851
|
+
df = interpolate(df, 300, interpolation, pd.Timedelta(
|
|
852
|
+
'00:06:00'), numeric_columns=numeric, add_binary_counter=False)
|
|
853
|
+
df = keep_interval(df, interval)
|
|
854
|
+
out = Lcm(df)
|
|
855
|
+
return out
|
|
856
|
+
|
|
844
857
|
def sum_interpolation(file, interpolation=1, interval="5 minutes", timing=False):
|
|
845
858
|
if timing:
|
|
846
859
|
start = time.process_time()
|
|
@@ -277,6 +277,10 @@ upas_datatype = {'AccelComplianceCnt': 'integer',
|
|
|
277
277
|
|
|
278
278
|
lascar_units = {"CO(ppm)":"ppm"}
|
|
279
279
|
|
|
280
|
+
|
|
281
|
+
lcm_units = {"sensorName": "-", "deviceId": "-", "resolution": "-", "PM2.5": "µg m-3",
|
|
282
|
+
"PM10": "µg m-3", "CO2": "ppm", "NO2": "ppm", "Temperature": "°C", "Humidity": "%"}
|
|
283
|
+
|
|
280
284
|
lascar_datatype = {"CO(ppm)": "numeric",
|
|
281
285
|
'start': "datetime",
|
|
282
286
|
'end': "datetime",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|