tonik 0.0.8__py3-none-any.whl → 0.0.9__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.
- tonik/api.py +17 -15
- tonik/utils.py +23 -17
- tonik/xarray2zarr.py +24 -10
- {tonik-0.0.8.dist-info → tonik-0.0.9.dist-info}/METADATA +2 -2
- tonik-0.0.9.dist-info/RECORD +12 -0
- {tonik-0.0.8.dist-info → tonik-0.0.9.dist-info}/WHEEL +1 -1
- tonik-0.0.8.dist-info/RECORD +0 -12
- {tonik-0.0.8.dist-info → tonik-0.0.9.dist-info}/entry_points.txt +0 -0
- {tonik-0.0.8.dist-info → tonik-0.0.9.dist-info}/licenses/LICENSE +0 -0
tonik/api.py
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
from argparse import ArgumentParser
|
|
2
|
-
from datetime import timedelta, datetime, timezone
|
|
3
1
|
import logging
|
|
4
2
|
import os
|
|
3
|
+
from argparse import ArgumentParser
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Annotated
|
|
5
6
|
from urllib.parse import unquote
|
|
6
7
|
|
|
7
|
-
from cftime import num2date, date2num
|
|
8
8
|
import datashader as dsh
|
|
9
9
|
import numpy as np
|
|
10
10
|
import pandas as pd
|
|
11
11
|
import uvicorn
|
|
12
|
+
from cftime import date2num, num2date
|
|
12
13
|
from fastapi import FastAPI, HTTPException, Query
|
|
13
14
|
from fastapi.middleware.cors import CORSMiddleware
|
|
14
15
|
from fastapi.responses import HTMLResponse, StreamingResponse
|
|
15
|
-
from pydantic import BaseModel
|
|
16
|
-
from typing import Annotated
|
|
17
16
|
|
|
18
|
-
from .storage import Storage
|
|
19
17
|
from . import get_data
|
|
18
|
+
from .storage import Storage
|
|
20
19
|
|
|
21
20
|
logger = logging.getLogger(__name__)
|
|
22
21
|
|
|
@@ -67,7 +66,8 @@ class TonikAPI:
|
|
|
67
66
|
_st = self.preprocess_datetime(starttime)
|
|
68
67
|
_et = self.preprocess_datetime(endtime)
|
|
69
68
|
g = Storage(group, rootdir=self.rootdir,
|
|
70
|
-
starttime=_st, endtime=_et
|
|
69
|
+
starttime=_st, endtime=_et,
|
|
70
|
+
create=False)
|
|
71
71
|
if subdir is None:
|
|
72
72
|
c = g
|
|
73
73
|
else:
|
|
@@ -103,13 +103,15 @@ class TonikAPI:
|
|
|
103
103
|
else:
|
|
104
104
|
df = pd.DataFrame(data=feat.to_pandas(), columns=[feat.name])
|
|
105
105
|
df['dates'] = df.index
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
if resolution != 'full':
|
|
107
|
+
try:
|
|
108
|
+
current_resolution = pd.Timedelta(
|
|
109
|
+
df['dates'].diff().mean())
|
|
110
|
+
if current_resolution < pd.Timedelta(resolution):
|
|
111
|
+
df = df.resample(pd.Timedelta(resolution)).mean()
|
|
112
|
+
except ValueError:
|
|
113
|
+
logger.warning(
|
|
114
|
+
f"Cannot resample {feat.name} to {resolution}: e")
|
|
113
115
|
df.rename(columns={feat.name: 'feature'}, inplace=True)
|
|
114
116
|
output = df.to_csv(index=False, columns=['dates', 'feature'])
|
|
115
117
|
return StreamingResponse(iter([output]),
|
|
@@ -143,7 +145,7 @@ class TonikAPI:
|
|
|
143
145
|
c = sg.get_substore(*subdir)
|
|
144
146
|
except TypeError:
|
|
145
147
|
c = sg
|
|
146
|
-
except FileNotFoundError
|
|
148
|
+
except FileNotFoundError:
|
|
147
149
|
msg = "Directory {} not found.".format(
|
|
148
150
|
'/'.join([sg.path] + subdir))
|
|
149
151
|
raise HTTPException(status_code=404, detail=msg)
|
tonik/utils.py
CHANGED
|
@@ -8,8 +8,8 @@ import xarray as xr
|
|
|
8
8
|
def generate_test_data(dim=1, ndays=30, nfreqs=10,
|
|
9
9
|
tstart=datetime.now(),
|
|
10
10
|
freq='10min', intervals=None,
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
feature_names=None, seed=42,
|
|
12
|
+
freq_names=None, add_nans=True):
|
|
13
13
|
"""
|
|
14
14
|
Generate a 1D or 2D feature for testing.
|
|
15
15
|
"""
|
|
@@ -28,25 +28,31 @@ def generate_test_data(dim=1, ndays=30, nfreqs=10,
|
|
|
28
28
|
data = np.tile(data, (nfreqs, 1))
|
|
29
29
|
# Add 10% NaNs
|
|
30
30
|
idx_nan = rs.integers(0, nints-1, int(0.1*nints))
|
|
31
|
+
|
|
32
|
+
xds_dict = {}
|
|
31
33
|
if dim == 1:
|
|
32
34
|
if add_nans:
|
|
33
35
|
data[idx_nan] = np.nan
|
|
34
|
-
if
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
if feature_names is None:
|
|
37
|
+
feature_names = ['rsam', 'dsar']
|
|
38
|
+
for feature in feature_names:
|
|
39
|
+
xds_dict[feature] = xr.DataArray(
|
|
40
|
+
data, coords=[dates], dims=['datetime'])
|
|
38
41
|
if dim == 2:
|
|
39
42
|
if add_nans:
|
|
40
43
|
data[:, idx_nan] = np.nan
|
|
41
44
|
freqs = np.arange(nfreqs)
|
|
42
|
-
if
|
|
43
|
-
|
|
44
|
-
if
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
if feature_names is None:
|
|
46
|
+
feature_names = ['ssam', 'filterbank']
|
|
47
|
+
if freq_names is None:
|
|
48
|
+
freq_names = ['frequency', 'fbfrequency']
|
|
49
|
+
|
|
50
|
+
for feature_name, freq_name in zip(feature_names, freq_names):
|
|
51
|
+
xds_dict[feature_name] = xr.DataArray(
|
|
52
|
+
data, coords=[freqs, dates], dims=[freq_name, 'datetime'])
|
|
53
|
+
xds = xr.Dataset(xds_dict)
|
|
54
|
+
xds.attrs['starttime'] = dates[0].isoformat()
|
|
55
|
+
xds.attrs['endtime'] = dates[-1].isoformat()
|
|
56
|
+
xds.attrs['station'] = 'MDR'
|
|
57
|
+
xds.attrs['interval'] = '10min'
|
|
58
|
+
return xds
|
tonik/xarray2zarr.py
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import os
|
|
2
3
|
|
|
3
4
|
import xarray as xr
|
|
4
5
|
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
def xarray2zarr(xds, path, mode='a'):
|
|
7
10
|
for feature in xds.data_vars.keys():
|
|
@@ -11,13 +14,24 @@ def xarray2zarr(xds, path, mode='a'):
|
|
|
11
14
|
fout, group='original', mode='w')
|
|
12
15
|
else:
|
|
13
16
|
xds_existing = xr.open_zarr(fout, group='original')
|
|
14
|
-
|
|
15
|
-
xds_existing.datetime
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
try:
|
|
18
|
+
overlap = xds_existing.datetime.where(
|
|
19
|
+
xds_existing.datetime == xds.datetime)
|
|
20
|
+
if overlap.size > 0:
|
|
21
|
+
xds[feature].loc[dict(datetime=overlap)].to_zarr(
|
|
22
|
+
fout, group='original', mode='r+', region='auto')
|
|
23
|
+
xds[feature].drop_sel(datetime=overlap).to_zarr(
|
|
24
|
+
fout, group='original', mode='a', append_dim="datetime")
|
|
25
|
+
else:
|
|
26
|
+
xds[feature].to_zarr(
|
|
27
|
+
fout, group='original', append_dim='datetime')
|
|
28
|
+
except Exception as e:
|
|
29
|
+
msg = f"Appending {feature} to {fout} failed: {e}\n"
|
|
30
|
+
msg += "Attempting to merge the two datasets."
|
|
31
|
+
logger.error(msg)
|
|
32
|
+
# remove duplicate datetime entries
|
|
33
|
+
xda_existing = xds_existing[feature].drop_duplicates(
|
|
34
|
+
'datetime', keep='last')
|
|
35
|
+
xda_new = xds[feature].drop_duplicates('datetime', keep='last')
|
|
36
|
+
xda_new.combine_first(xda_existing).to_zarr(
|
|
37
|
+
fout, group='original', mode='w')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: tonik
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
4
4
|
Summary: Store time series data as HDF5 files and access them through an API.
|
|
5
5
|
Project-URL: Homepage, https://tsc-tools.github.io/tonik
|
|
6
6
|
Project-URL: Issues, https://github.com/tsc-tools/tonik/issues
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
tonik/__init__.py,sha256=ZBVGh4dm_l9xwiBGb33O5QV9MfZeNiEd3DBDAm6DiHk,511
|
|
2
|
+
tonik/api.py,sha256=8YS0WCMlm5xs2N6V8n9BiP87ywJC_BUzYsPvWR9KWJk,6499
|
|
3
|
+
tonik/storage.py,sha256=sScIFA4KXURNPwTnV-rvDh6cWCy9sRrErr9BshZpw2I,11303
|
|
4
|
+
tonik/utils.py,sha256=_TxXf9o9fOvtuOvGO6-ww9F5m0QelHyfQzQw8RGjTV4,1868
|
|
5
|
+
tonik/xarray2hdf5.py,sha256=cekO9vo9ZRlr0VndswJjPC27CEVD3TpRVKLAJ-aAO0g,4465
|
|
6
|
+
tonik/xarray2zarr.py,sha256=DM91jW63ySIuhjlJBIdrw61dZGG8QU5qKlBJYYIhRos,1592
|
|
7
|
+
tonik/package_data/index.html,sha256=GKDClUhIam_fAYbNfzAolORhSCG3ae1wW3VjWCg4PMk,2732
|
|
8
|
+
tonik-0.0.9.dist-info/METADATA,sha256=CWU0A4o08nA0X6L53Rzo6cRgG7NblX3EJRQkNSnoE-w,1938
|
|
9
|
+
tonik-0.0.9.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
10
|
+
tonik-0.0.9.dist-info/entry_points.txt,sha256=VnGfC5qAzpntEHAb5pooUEpYABSgOfQoNhCEtLDJyf8,45
|
|
11
|
+
tonik-0.0.9.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
12
|
+
tonik-0.0.9.dist-info/RECORD,,
|
tonik-0.0.8.dist-info/RECORD
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
tonik/__init__.py,sha256=ZBVGh4dm_l9xwiBGb33O5QV9MfZeNiEd3DBDAm6DiHk,511
|
|
2
|
-
tonik/api.py,sha256=vdsWHNGGWo4sbqlDyZQj2tX5oe6hAWCzyL6ffsfpCB4,6437
|
|
3
|
-
tonik/storage.py,sha256=sScIFA4KXURNPwTnV-rvDh6cWCy9sRrErr9BshZpw2I,11303
|
|
4
|
-
tonik/utils.py,sha256=YD2zZx5nKGfTJKTYTsEZVV78uNRCSakvU_6X6Mgwx-s,1664
|
|
5
|
-
tonik/xarray2hdf5.py,sha256=cekO9vo9ZRlr0VndswJjPC27CEVD3TpRVKLAJ-aAO0g,4465
|
|
6
|
-
tonik/xarray2zarr.py,sha256=d7FAOe7DESbKC9CZS41r62DjlNy0S8ik01lMGXBvJKw,901
|
|
7
|
-
tonik/package_data/index.html,sha256=GKDClUhIam_fAYbNfzAolORhSCG3ae1wW3VjWCg4PMk,2732
|
|
8
|
-
tonik-0.0.8.dist-info/METADATA,sha256=uqrHvBl01n05hqWN8lnNETuoYIGZ8vNq9QWnRmajcEY,1938
|
|
9
|
-
tonik-0.0.8.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
|
|
10
|
-
tonik-0.0.8.dist-info/entry_points.txt,sha256=VnGfC5qAzpntEHAb5pooUEpYABSgOfQoNhCEtLDJyf8,45
|
|
11
|
-
tonik-0.0.8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
12
|
-
tonik-0.0.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|