scdata 1.5.0__tar.gz → 1.5.2__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.
- {scdata-1.5.0 → scdata-1.5.2}/MANIFEST.in +3 -2
- {scdata-1.5.0/scdata.egg-info → scdata-1.5.2}/PKG-INFO +3 -6
- scdata-1.5.2/requirements.txt +12 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/__init__.py +1 -1
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/device.py +25 -6
- scdata-1.5.2/scdata/plot/templates/map_legend.html +53 -0
- scdata-1.5.2/scdata/test/export/templates/delivery_template.html +360 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/export/to_file.py +15 -19
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/custom_logger.py +0 -1
- {scdata-1.5.0 → scdata-1.5.2/scdata.egg-info}/PKG-INFO +3 -6
- {scdata-1.5.0 → scdata-1.5.2}/scdata.egg-info/SOURCES.txt +2 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata.egg-info/requires.txt +2 -5
- {scdata-1.5.0 → scdata-1.5.2}/setup.py +1 -1
- scdata-1.5.0/requirements.txt +0 -18
- {scdata-1.5.0 → scdata-1.5.2}/LICENSE +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/README.md +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/_config/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/_config/config.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/check/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/check/flats.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/check/gaps.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/check/implausible.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/check/outliers.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/plot/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/process/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/process/alphasense.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/process/error_codes.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/process/formulae.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/process/geoseries.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/process/params.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/process/regression.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/device/process/timeseries.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/io/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/io/device_api.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/io/device_file.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/io/model.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/models/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/models/models.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/box_plot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/heatmap_iplot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/heatmap_plot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/heatmap_uplot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/maps.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/scatter_dispersion_grid.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/scatter_iplot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/scatter_plot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/target_diagram.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/tools.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/ts_dendrogram.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/ts_dispersion_grid.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/ts_dispersion_plot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/ts_dispersion_uplot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/ts_iplot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/ts_panel.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/ts_plot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/ts_scatter.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/plot/ts_uplot.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/checks/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/checks/checks.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/dispersion/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/dispersion/dispersion.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/export/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/export/templates/sc_template.html +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/test.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/tools/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/tools/combine.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/tools/history.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/test/tools/prepare.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/__init__.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/cleaning.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/date.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/dictmerge.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/find.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/gets.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/interim/example.csv +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/interim/geodata.csv +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/lazy.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/location.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/merging.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/report.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/series.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/stats.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/tree.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/units.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/uploads/example_upload_1.json +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/uploads/example_zenodo_upload.yaml +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/uploads/report.pdf +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/url_check.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/zenodo.py +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/zenodo_templates/README.md +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/zenodo_templates/template_zenodo_dataset.json +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata/tools/zenodo_templates/template_zenodo_publication.json +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata.egg-info/dependency_links.txt +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata.egg-info/not-zip-safe +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/scdata.egg-info/top_level.txt +0 -0
- {scdata-1.5.0 → scdata-1.5.2}/setup.cfg +0 -0
|
@@ -2,8 +2,9 @@ include README.md
|
|
|
2
2
|
include LICENSE
|
|
3
3
|
include setup.py
|
|
4
4
|
include setup.cfg
|
|
5
|
-
include scdata/test/export/templates
|
|
5
|
+
include scdata/test/export/templates/*.html
|
|
6
|
+
include scdata/plot/templates/*.html
|
|
6
7
|
include scdata/tools/interim/*.csv
|
|
7
8
|
include scdata/tools/zenodo_templates/*.*
|
|
8
9
|
include scdata/tools/uploads/*.*
|
|
9
|
-
include requirements.txt
|
|
10
|
+
include requirements.txt
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scdata
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.2
|
|
4
4
|
Summary: Analysis of sensors and time series data
|
|
5
5
|
Home-page: https://github.com/fablabbcn/smartcitizen-data
|
|
6
6
|
Author: oscgonfer
|
|
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
18
18
|
Requires-Python: >=3.9
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: geopy
|
|
21
|
+
Requires-Dist: geopy<3,>=2.4
|
|
22
22
|
Requires-Dist: Jinja2~=3.1.2
|
|
23
23
|
Requires-Dist: matplotlib
|
|
24
24
|
Requires-Dist: pandas~=2.2.2
|
|
@@ -28,11 +28,8 @@ Requires-Dist: requests
|
|
|
28
28
|
Requires-Dist: scipy
|
|
29
29
|
Requires-Dist: scikit-learn
|
|
30
30
|
Requires-Dist: seaborn
|
|
31
|
-
Requires-Dist: smartcitizen-connector>=1.5.
|
|
32
|
-
Requires-Dist: termcolor==1.1.0
|
|
31
|
+
Requires-Dist: smartcitizen-connector>=1.5.1
|
|
33
32
|
Requires-Dist: timezonefinder~=6.1.9
|
|
34
|
-
Requires-Dist: urllib3
|
|
35
|
-
Requires-Dist: Flask~=2.2.2
|
|
36
33
|
Provides-Extra: plotting
|
|
37
34
|
Requires-Dist: bokeh; extra == "plotting"
|
|
38
35
|
Requires-Dist: panel; extra == "plotting"
|
|
@@ -304,22 +304,33 @@ class Device(BaseModel):
|
|
|
304
304
|
def __unavailable_inputs__(self, channel, skipped):
|
|
305
305
|
'''
|
|
306
306
|
Returns the inputs of a channel that the device cannot provide: known sensors
|
|
307
|
-
|
|
307
|
+
without data (not in the device, or without readings), or channels that were skipped
|
|
308
308
|
'''
|
|
309
309
|
channel_names = [channel.name for channel in self.channels]
|
|
310
|
-
|
|
311
|
-
known_sensors = [name.name for name in config.names.get(self.source.handler, [])]
|
|
310
|
+
known_sensors = {name.name for names in config.names.values() for name in names}
|
|
312
311
|
|
|
313
312
|
required, _ = self.__channel_inputs__(channel)
|
|
314
313
|
unavailable = [item for item in channel.depends_on if item in skipped]
|
|
315
314
|
for item in required:
|
|
316
315
|
if item in channel_names:
|
|
317
316
|
if item in skipped: unavailable.append(item)
|
|
318
|
-
elif item in known_sensors and item not in
|
|
317
|
+
elif item in known_sensors and item not in self.data.columns:
|
|
319
318
|
unavailable.append(item)
|
|
320
319
|
|
|
321
320
|
return sorted(set(unavailable))
|
|
322
321
|
|
|
322
|
+
def __failed_inputs__(self, channel):
|
|
323
|
+
'''
|
|
324
|
+
Returns the inputs of a channel whose data request failed in the handler
|
|
325
|
+
'''
|
|
326
|
+
failed = getattr(self.handler, 'failed_sensors', None) or []
|
|
327
|
+
rename = getattr(self, '_rename', {})
|
|
328
|
+
failed = set(failed) | {rename.get(name, name) for name in failed}
|
|
329
|
+
|
|
330
|
+
required, _ = self.__channel_inputs__(channel)
|
|
331
|
+
|
|
332
|
+
return sorted(required & failed)
|
|
333
|
+
|
|
323
334
|
def add_channel(self, calculated_channel = dict()):
|
|
324
335
|
'''
|
|
325
336
|
Add a CalculatedChannel to the device to be processed by a callable function
|
|
@@ -608,10 +619,18 @@ class Device(BaseModel):
|
|
|
608
619
|
if channel.name not in _channels_list: continue
|
|
609
620
|
logger.info(f'Processing {channel.name}')
|
|
610
621
|
|
|
611
|
-
#
|
|
622
|
+
# Data that failed to load cannot be skipped: processing fails
|
|
623
|
+
failed = self.__failed_inputs__(channel)
|
|
624
|
+
if failed:
|
|
625
|
+
logger.error(f'Cannot process {channel.name}. Data request failed for: {failed}')
|
|
626
|
+
process_ok = False
|
|
627
|
+
skipped.add(channel.name)
|
|
628
|
+
continue
|
|
629
|
+
|
|
630
|
+
# Skip channels whose inputs have no data (and their dependants)
|
|
612
631
|
unavailable = self.__unavailable_inputs__(channel, skipped)
|
|
613
632
|
if unavailable:
|
|
614
|
-
logger.warning(f'Skipping {channel.name}.
|
|
633
|
+
logger.warning(f'Skipping {channel.name}. No data for: {unavailable}')
|
|
615
634
|
skipped.add(channel.name)
|
|
616
635
|
continue
|
|
617
636
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<div id='maplegend' class='maplegend'
|
|
2
|
+
style='position: absolute; z-index:9999; background-color:rgba(255, 255, 255, 0.9); border-radius:5px; padding: 10px; font-size:14px; right: 10px; top: 10px;'>
|
|
3
|
+
<div class='legend-title'>Legend</div>
|
|
4
|
+
<div class='legend-scale'>
|
|
5
|
+
<ul class='legend-labels'>
|
|
6
|
+
{% for label, color in legend_labels.items() %}
|
|
7
|
+
<li><span style="background:{{color}};opacity:0.8;"></span>{{label}}</li>
|
|
8
|
+
{% endfor %}
|
|
9
|
+
</ul>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<style type='text/css'>
|
|
14
|
+
.maplegend .legend-title {
|
|
15
|
+
text-align: center;
|
|
16
|
+
margin-bottom: 5px;
|
|
17
|
+
font-weight: bold;
|
|
18
|
+
font-size: 90%;
|
|
19
|
+
}
|
|
20
|
+
.maplegend .legend-scale ul {
|
|
21
|
+
margin: 0;
|
|
22
|
+
margin-bottom: 5px;
|
|
23
|
+
padding: 0;
|
|
24
|
+
float: left;
|
|
25
|
+
list-style: none;
|
|
26
|
+
}
|
|
27
|
+
.maplegend .legend-scale ul li {
|
|
28
|
+
font-size: 80%;
|
|
29
|
+
list-style: none;
|
|
30
|
+
margin-left: 0;
|
|
31
|
+
line-height: 18px;
|
|
32
|
+
margin-bottom: 2px;
|
|
33
|
+
}
|
|
34
|
+
.maplegend ul.legend-labels li span {
|
|
35
|
+
display: block;
|
|
36
|
+
float: left;
|
|
37
|
+
height: 16px;
|
|
38
|
+
width: 16px;
|
|
39
|
+
margin-right: 5px;
|
|
40
|
+
margin-left: 0;
|
|
41
|
+
border: 1px solid #999;
|
|
42
|
+
border-radius:15px;
|
|
43
|
+
}
|
|
44
|
+
.maplegend .legend-source {
|
|
45
|
+
font-size: 80%;
|
|
46
|
+
color: #777;
|
|
47
|
+
clear: both;
|
|
48
|
+
}
|
|
49
|
+
.maplegend a {
|
|
50
|
+
color: #777;
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
53
|
+
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
{% if full %}
|
|
2
|
+
<!doctype html>
|
|
3
|
+
|
|
4
|
+
<html>
|
|
5
|
+
|
|
6
|
+
<head>
|
|
7
|
+
<meta charset="utf-8"/>
|
|
8
|
+
|
|
9
|
+
<title>{{ descriptor['id'] }}</title>
|
|
10
|
+
|
|
11
|
+
<!-- Web Fonts -->
|
|
12
|
+
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i%7CMontserrat:400,700"
|
|
13
|
+
rel="stylesheet">
|
|
14
|
+
|
|
15
|
+
<link rel="shortcut icon" type="image/jpg" href="https://smartcitizen.me/assets/images/smartcitizen_logo.svg"/>
|
|
16
|
+
</head>
|
|
17
|
+
|
|
18
|
+
<body>
|
|
19
|
+
|
|
20
|
+
{% endif %}
|
|
21
|
+
|
|
22
|
+
<div {% if header %} id="report-header" {% else %} id="normal-header" {% endif %}>
|
|
23
|
+
<h1 {% if header %} id="top" {% endif %}>{{ title }}</h1>
|
|
24
|
+
|
|
25
|
+
{% if header %}
|
|
26
|
+
<div style="text-align: right">
|
|
27
|
+
<img src="https://smartcitizen.me/assets/images/smartcitizen_logo.svg" alt="Smart Citizen Logo" width=50px height=50px>
|
|
28
|
+
</div>
|
|
29
|
+
{% endif %}
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div id="container">
|
|
33
|
+
|
|
34
|
+
{% if details %}
|
|
35
|
+
|
|
36
|
+
<div class="header">
|
|
37
|
+
<h2>Delivery</h2>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<ul>
|
|
41
|
+
<li><strong>Delivery:</strong> {{ descriptor.delivery.destination }}</li>
|
|
42
|
+
<li><strong>Batch:</strong> {{ descriptor.delivery.batch }}</li>
|
|
43
|
+
<li><strong>Author:</strong> {{ descriptor.author }}</li>
|
|
44
|
+
</ul>
|
|
45
|
+
|
|
46
|
+
<h3>Devices</h3>
|
|
47
|
+
|
|
48
|
+
{{ descriptor.delivery.devices }}
|
|
49
|
+
|
|
50
|
+
{% endif %}
|
|
51
|
+
|
|
52
|
+
<div class="header">
|
|
53
|
+
<h2>Test description</h2>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<p>The devices are co-located for a period of at least 72h in an <b>indoor</b> environment. Devices that show an abnormal behaviour are analysed and replaced if necessary.
|
|
57
|
+
|
|
58
|
+
<h3> Test conditions </h3>
|
|
59
|
+
|
|
60
|
+
<ul>
|
|
61
|
+
<li>Indoor environment</li>
|
|
62
|
+
<li>No controlled temperature/humidity setup</li>
|
|
63
|
+
</ul>
|
|
64
|
+
|
|
65
|
+
<h3> Additional comments </h3>
|
|
66
|
+
|
|
67
|
+
<ul>
|
|
68
|
+
<li>The test batch average is considered reference for batch dispersion limits</li>
|
|
69
|
+
<li>The confidence intervals used are those of the normal distribution (sample numbers >30) and of the t-student distribution (sample numbers <30).</li>
|
|
70
|
+
<li>The individual sensors components integrated in the Smart Citizen hardware have their own accuracies and dispersions, for which Smart Citizen cannot assume any liability other than trying to work with the most appropiate selection. The tests we perform are aimed to determine and assume any failures in the sensors and their integration within the Smart Citizen hardware. For more information, please check the <a href="https://docs.smartcitizen.me">official documentation</a> and the datasheets of each of the sensors in the <a href="https://docs.smartcitizen.me/Components/boards/Urban%20Board/">sensors part</a>.</li>
|
|
71
|
+
</ul>
|
|
72
|
+
|
|
73
|
+
{% if devices_summary %}
|
|
74
|
+
|
|
75
|
+
<div class="header">
|
|
76
|
+
<h2>Devices summary</h2>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<table>
|
|
80
|
+
<tr class="first">
|
|
81
|
+
<th style="width: 15vh;"> Device </th>
|
|
82
|
+
<th class='table-center' style="width: 35vh;"> Blueprint </th>
|
|
83
|
+
<th class='table-center' style="width: 20vh;"> Documentation </th>
|
|
84
|
+
<th class='table-center' style="width: 20vh;"> Timezone </th>
|
|
85
|
+
<th class='table-center' style="width: 20vh;"> Source </th>
|
|
86
|
+
</tr>
|
|
87
|
+
|
|
88
|
+
{% for key, value in descriptor.devices.items() %}
|
|
89
|
+
<tr>
|
|
90
|
+
<td>{{ key }}</td>
|
|
91
|
+
<td class='table-center'>{{ value.blueprint.upper().replace("_", " ") }}</td>
|
|
92
|
+
<td class='table-center'><a href="{{ value.documentation }}" >Documentation</a></td>
|
|
93
|
+
<td class='table-center'><a>{{ value.timezone }}</a></td>
|
|
94
|
+
<td class='table-center'><em>{{ value.source.upper().replace("_", " ") }}</em></td>
|
|
95
|
+
</tr>
|
|
96
|
+
{% endfor %}
|
|
97
|
+
</table>
|
|
98
|
+
|
|
99
|
+
<div class="header">
|
|
100
|
+
<h2>Device information</h2>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
{% for device, _ in descriptor.devices.items() %}
|
|
104
|
+
<details>
|
|
105
|
+
<summary>Device {{ device }}</summary>
|
|
106
|
+
|
|
107
|
+
{% if descriptor.devices[device]['sensors'].items().__len__() == 0 %}
|
|
108
|
+
<p style="margin-left: 2rem;">Device empty. No data to show</p>
|
|
109
|
+
{% else %}
|
|
110
|
+
<table>
|
|
111
|
+
<tr class="first">
|
|
112
|
+
<th class='table-center' style="width: 20vh;"> Channel </th>
|
|
113
|
+
<th class='table-center' style="width: 10vh;"> Units </th>
|
|
114
|
+
<th class='table-center' style="width: 20vh;"> Type (raw/processed) </th>
|
|
115
|
+
<th class='table-center' style="width: 20vh;"> Algorithm </th>
|
|
116
|
+
<th class='table-center' style="width: 60vh;"> Description </th>
|
|
117
|
+
</tr>
|
|
118
|
+
|
|
119
|
+
{% for metric, value in descriptor.devices[device]['sensors'].items() %}
|
|
120
|
+
<tr>
|
|
121
|
+
<td>{{ metric }}</td>
|
|
122
|
+
<td class='table-center'><em>{{ value.units }}</em></td>
|
|
123
|
+
<td class='table-center'>Raw</td>
|
|
124
|
+
<td class='table-center'>n/a</td>
|
|
125
|
+
{% if 'desc' in value %}
|
|
126
|
+
<td class='table-center'>{{ value.desc }}</td>
|
|
127
|
+
{% else %}
|
|
128
|
+
<td class='table-center'>No description available</td>
|
|
129
|
+
{% endif %}
|
|
130
|
+
</tr>
|
|
131
|
+
{% endfor %}
|
|
132
|
+
|
|
133
|
+
{% if 'metrics' in descriptor.devices[device] %}
|
|
134
|
+
{% for metric, value in descriptor.devices[device]['metrics'].items() %}
|
|
135
|
+
<tr>
|
|
136
|
+
<td>{{ metric }}</td>
|
|
137
|
+
<td class='table-center'>{{ value.units }}</td>
|
|
138
|
+
<td class='table-center'>Processed</td>
|
|
139
|
+
<td class='table-center'>{{ value.process }}</td>
|
|
140
|
+
{% if value %}
|
|
141
|
+
{% if 'desc' in value %}
|
|
142
|
+
<td class='table-center'>{{ value.desc }}</td>
|
|
143
|
+
{% endif %}
|
|
144
|
+
{% else %}
|
|
145
|
+
<td class='table-center'>No description available</td>
|
|
146
|
+
{% endif %}
|
|
147
|
+
</tr>
|
|
148
|
+
{% endfor %}
|
|
149
|
+
{% endif %}
|
|
150
|
+
</table>
|
|
151
|
+
<br>
|
|
152
|
+
</details>
|
|
153
|
+
{% endif %}
|
|
154
|
+
{% endfor %}
|
|
155
|
+
|
|
156
|
+
{% endif %}
|
|
157
|
+
|
|
158
|
+
{% if content %}
|
|
159
|
+
|
|
160
|
+
<h2> Results </h2>
|
|
161
|
+
|
|
162
|
+
{% for item, value in content.items() %}
|
|
163
|
+
<h3>{{ value.title }}</h3>
|
|
164
|
+
|
|
165
|
+
{% if 'text' in value %}
|
|
166
|
+
<p>
|
|
167
|
+
{{ value.text }}
|
|
168
|
+
</p>
|
|
169
|
+
{% endif %}
|
|
170
|
+
|
|
171
|
+
{% if 'image' in value %}
|
|
172
|
+
<div class="img-container">
|
|
173
|
+
<img src="{{ value.image }}" style="width:80%; max-width: 1000px">
|
|
174
|
+
</div>
|
|
175
|
+
{% endif %}
|
|
176
|
+
|
|
177
|
+
{% if 'iframe' in value %}
|
|
178
|
+
<div class="iframe-container">
|
|
179
|
+
{{ value.iframe }}
|
|
180
|
+
</div>
|
|
181
|
+
{% endif %}
|
|
182
|
+
|
|
183
|
+
{% endfor %}
|
|
184
|
+
|
|
185
|
+
{% endif %}
|
|
186
|
+
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
{% if full %}
|
|
190
|
+
|
|
191
|
+
</body>
|
|
192
|
+
|
|
193
|
+
</html>
|
|
194
|
+
|
|
195
|
+
{% endif %}
|
|
196
|
+
|
|
197
|
+
<style type="text/css">
|
|
198
|
+
|
|
199
|
+
body {
|
|
200
|
+
text-align: justify;
|
|
201
|
+
line-height: 1.6;
|
|
202
|
+
font-size: .9rem;
|
|
203
|
+
font-family: Roboto, sans-serif;
|
|
204
|
+
font-weight: lighter;
|
|
205
|
+
margin: 15px;
|
|
206
|
+
overflow: visible;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
div#container{
|
|
210
|
+
padding-left: 40px;
|
|
211
|
+
padding-right: 30px;
|
|
212
|
+
{% if header %}
|
|
213
|
+
padding-top: 40px;
|
|
214
|
+
{% else %}
|
|
215
|
+
padding-top: 20px;
|
|
216
|
+
{% endif %}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
h1#top {
|
|
220
|
+
margin: 0px !important;
|
|
221
|
+
padding: 0px !important;
|
|
222
|
+
font-size: 1.5rem !important;
|
|
223
|
+
font-weight: bold;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
h2{
|
|
227
|
+
font-size: 1.2rem;
|
|
228
|
+
font-weight: normal;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
h3{
|
|
232
|
+
font-size: 1.1rem;
|
|
233
|
+
font-weight: normal;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
ul {
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
table {
|
|
240
|
+
font-size: 0.8rem;
|
|
241
|
+
margin: auto;
|
|
242
|
+
padding: 20px;
|
|
243
|
+
text-align: center;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
summary{
|
|
247
|
+
background: grey;
|
|
248
|
+
color: white;
|
|
249
|
+
text-emphasis: 2em;
|
|
250
|
+
padding: 3px 20px;
|
|
251
|
+
margin-bottom: 5px;
|
|
252
|
+
border-radius: 20px;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
div.img-container {
|
|
256
|
+
text-align: center;
|
|
257
|
+
padding: 20px;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
div.iframe-container {
|
|
261
|
+
text-align: center;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
div#normal-header {
|
|
265
|
+
padding-left: 40px;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
div#report-header {
|
|
269
|
+
display: flex;
|
|
270
|
+
flex-direction: row;
|
|
271
|
+
-ms-flex-align: center;
|
|
272
|
+
-webkit-align-items: center;
|
|
273
|
+
align-items: center;
|
|
274
|
+
-ms-flex-pack: justify;
|
|
275
|
+
-webkit-justify-content: space-between;
|
|
276
|
+
justify-content: space-between;
|
|
277
|
+
color: #FFFFFF;
|
|
278
|
+
height: 120px;
|
|
279
|
+
padding-left: 40px;
|
|
280
|
+
overflow: hidden;
|
|
281
|
+
border-top: none;
|
|
282
|
+
background: #000000;
|
|
283
|
+
box-shadow: 0px 0px 12px 1px rgba(87, 87, 87, 0.2);
|
|
284
|
+
border-radius: 5px 5px 0px 0px;
|
|
285
|
+
padding-right: 60px;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
td.table-center{
|
|
289
|
+
text-align: center;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
th.table-center{
|
|
293
|
+
text-align: center;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
tr.first{
|
|
297
|
+
background: black;
|
|
298
|
+
color: white;
|
|
299
|
+
border-color: black;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
@page
|
|
303
|
+
{
|
|
304
|
+
size: auto; /* auto is the initial value */
|
|
305
|
+
|
|
306
|
+
/* this affects the margin in the printer settings */
|
|
307
|
+
margin: 0mm;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
@media print {
|
|
311
|
+
body{
|
|
312
|
+
padding: 0mm !important;
|
|
313
|
+
margin: 0mm !important;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
div#report-header{
|
|
317
|
+
background: #000000 !important;
|
|
318
|
+
font-size: 90% !important;
|
|
319
|
+
page-break-inside: avoid;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
div.device {
|
|
323
|
+
display: block;
|
|
324
|
+
page-break-inside: avoid;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
table {
|
|
328
|
+
page-break-inside: avoid;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
table.dataframe {
|
|
333
|
+
border: 0px none;
|
|
334
|
+
border-collapse: collapse;
|
|
335
|
+
border-spacing: 0;
|
|
336
|
+
text-align: right;
|
|
337
|
+
}
|
|
338
|
+
table.dataframe tr {
|
|
339
|
+
border: 0px none;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
table.dataframe td, table.dataframe th {
|
|
343
|
+
border: 0px none;
|
|
344
|
+
padding-left: 0.5em;
|
|
345
|
+
padding-right: 0.5em;
|
|
346
|
+
font-weight: lighter;
|
|
347
|
+
white-space: normal;
|
|
348
|
+
max-width: none;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
table.dataframe th:not(:empty) {
|
|
352
|
+
text-align: left;
|
|
353
|
+
font-weight: bold;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
table.dataframe tr:nth-child(even) td{
|
|
357
|
+
background-color: #f5f5f5;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
</style>
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
from os.path import join, dirname, exists
|
|
4
4
|
from os import makedirs
|
|
5
5
|
from scdata.tools.custom_logger import logger
|
|
6
|
-
import
|
|
7
|
-
from re import sub
|
|
6
|
+
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
8
7
|
|
|
9
8
|
def to_csv(self, path = None, forced_overwrite = False):
|
|
10
9
|
"""
|
|
@@ -68,10 +67,11 @@ def to_html(self, title = 'Your title here', template = 'sc_template.html', path
|
|
|
68
67
|
Returns
|
|
69
68
|
----------
|
|
70
69
|
rendered:
|
|
71
|
-
|
|
70
|
+
rendered template
|
|
72
71
|
'''
|
|
73
|
-
# TODO - Update or remove
|
|
74
|
-
raise NotImplementedError
|
|
72
|
+
# TODO - Update or remove: the templates use the old test descriptor format
|
|
73
|
+
raise NotImplementedError('to_html is disabled: its templates use the old test descriptor, '
|
|
74
|
+
'which Test no longer has (descriptor, content)')
|
|
75
75
|
|
|
76
76
|
# Find the path to the html templates directory
|
|
77
77
|
template_folder = join(dirname(__file__), 'templates')
|
|
@@ -84,20 +84,16 @@ def to_html(self, title = 'Your title here', template = 'sc_template.html', path
|
|
|
84
84
|
|
|
85
85
|
filename = join(path, f'{self.name}.html')
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
devices_summary = devices_summary,
|
|
98
|
-
full = full,
|
|
99
|
-
header = header
|
|
100
|
-
)
|
|
87
|
+
environment = Environment(loader=FileSystemLoader(template_folder), autoescape=select_autoescape())
|
|
88
|
+
rendered = environment.get_template(template).render(
|
|
89
|
+
title = title,
|
|
90
|
+
descriptor = self.descriptor,
|
|
91
|
+
content = self.content,
|
|
92
|
+
details = details,
|
|
93
|
+
devices_summary = devices_summary,
|
|
94
|
+
full = full,
|
|
95
|
+
header = header
|
|
96
|
+
)
|
|
101
97
|
|
|
102
98
|
with open(filename, 'w') as handle:
|
|
103
99
|
handle.write(rendered)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scdata
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.2
|
|
4
4
|
Summary: Analysis of sensors and time series data
|
|
5
5
|
Home-page: https://github.com/fablabbcn/smartcitizen-data
|
|
6
6
|
Author: oscgonfer
|
|
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
18
18
|
Requires-Python: >=3.9
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: geopy
|
|
21
|
+
Requires-Dist: geopy<3,>=2.4
|
|
22
22
|
Requires-Dist: Jinja2~=3.1.2
|
|
23
23
|
Requires-Dist: matplotlib
|
|
24
24
|
Requires-Dist: pandas~=2.2.2
|
|
@@ -28,11 +28,8 @@ Requires-Dist: requests
|
|
|
28
28
|
Requires-Dist: scipy
|
|
29
29
|
Requires-Dist: scikit-learn
|
|
30
30
|
Requires-Dist: seaborn
|
|
31
|
-
Requires-Dist: smartcitizen-connector>=1.5.
|
|
32
|
-
Requires-Dist: termcolor==1.1.0
|
|
31
|
+
Requires-Dist: smartcitizen-connector>=1.5.1
|
|
33
32
|
Requires-Dist: timezonefinder~=6.1.9
|
|
34
|
-
Requires-Dist: urllib3
|
|
35
|
-
Requires-Dist: Flask~=2.2.2
|
|
36
33
|
Provides-Extra: plotting
|
|
37
34
|
Requires-Dist: bokeh; extra == "plotting"
|
|
38
35
|
Requires-Dist: panel; extra == "plotting"
|
|
@@ -55,6 +55,7 @@ scdata/plot/ts_panel.py
|
|
|
55
55
|
scdata/plot/ts_plot.py
|
|
56
56
|
scdata/plot/ts_scatter.py
|
|
57
57
|
scdata/plot/ts_uplot.py
|
|
58
|
+
scdata/plot/templates/map_legend.html
|
|
58
59
|
scdata/test/__init__.py
|
|
59
60
|
scdata/test/test.py
|
|
60
61
|
scdata/test/checks/__init__.py
|
|
@@ -63,6 +64,7 @@ scdata/test/dispersion/__init__.py
|
|
|
63
64
|
scdata/test/dispersion/dispersion.py
|
|
64
65
|
scdata/test/export/__init__.py
|
|
65
66
|
scdata/test/export/to_file.py
|
|
67
|
+
scdata/test/export/templates/delivery_template.html
|
|
66
68
|
scdata/test/export/templates/sc_template.html
|
|
67
69
|
scdata/test/tools/__init__.py
|
|
68
70
|
scdata/test/tools/combine.py
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
geopy
|
|
1
|
+
geopy<3,>=2.4
|
|
2
2
|
Jinja2~=3.1.2
|
|
3
3
|
matplotlib
|
|
4
4
|
pandas~=2.2.2
|
|
@@ -8,11 +8,8 @@ requests
|
|
|
8
8
|
scipy
|
|
9
9
|
scikit-learn
|
|
10
10
|
seaborn
|
|
11
|
-
smartcitizen-connector>=1.5.
|
|
12
|
-
termcolor==1.1.0
|
|
11
|
+
smartcitizen-connector>=1.5.1
|
|
13
12
|
timezonefinder~=6.1.9
|
|
14
|
-
urllib3
|
|
15
|
-
Flask~=2.2.2
|
|
16
13
|
|
|
17
14
|
[dev]
|
|
18
15
|
pytest
|
scdata-1.5.0/requirements.txt
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# TODO To be updated?
|
|
2
|
-
geopy~=1.21.0
|
|
3
|
-
# TODO To be updated?
|
|
4
|
-
Jinja2~=3.1.2
|
|
5
|
-
matplotlib
|
|
6
|
-
pandas~=2.2.2
|
|
7
|
-
pydantic~=2.8
|
|
8
|
-
# TODO To be updated?
|
|
9
|
-
PyYAML~=6.0.1
|
|
10
|
-
requests
|
|
11
|
-
scipy
|
|
12
|
-
scikit-learn
|
|
13
|
-
seaborn
|
|
14
|
-
smartcitizen-connector>=1.5.0
|
|
15
|
-
termcolor==1.1.0
|
|
16
|
-
timezonefinder~=6.1.9
|
|
17
|
-
urllib3
|
|
18
|
-
Flask~=2.2.2
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{scdata-1.5.0 → scdata-1.5.2}/scdata/tools/zenodo_templates/template_zenodo_publication.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|