meteostat 1.6.8__tar.gz → 1.7.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.
- {meteostat-1.6.8 → meteostat-1.7.1}/PKG-INFO +3 -3
- {meteostat-1.6.8 → meteostat-1.7.1}/README.md +1 -1
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/__init__.py +12 -1
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/core/cache.py +0 -2
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/core/loader.py +26 -28
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/core/warn.py +1 -1
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/base.py +10 -7
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/daily.py +44 -31
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/hourly.py +44 -43
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/meteodata.py +54 -69
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/monthly.py +24 -19
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/normals.py +59 -19
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/point.py +1 -4
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/stations.py +9 -8
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/timeseries.py +97 -65
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/series/aggregate.py +0 -1
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/series/convert.py +1 -1
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/series/interpolate.py +12 -2
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/series/normalize.py +4 -5
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/utilities/endpoint.py +1 -1
- meteostat-1.7.1/meteostat/utilities/helpers.py +70 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/utilities/mutations.py +10 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat.egg-info/PKG-INFO +3 -3
- meteostat-1.7.1/meteostat.egg-info/requires.txt +3 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/setup.py +3 -3
- meteostat-1.6.8/meteostat/utilities/helpers.py +0 -32
- meteostat-1.6.8/meteostat.egg-info/requires.txt +0 -3
- {meteostat-1.6.8 → meteostat-1.7.1}/LICENSE +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/core/__init__.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/enumerations/__init__.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/enumerations/granularity.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/__init__.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/interface/interpolate.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/series/__init__.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/series/count.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/series/coverage.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/series/fetch.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/series/stations.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/units.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/utilities/__init__.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/utilities/aggregations.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat/utilities/validations.py +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat.egg-info/SOURCES.txt +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat.egg-info/dependency_links.txt +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/meteostat.egg-info/top_level.txt +0 -0
- {meteostat-1.6.8 → meteostat-1.7.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: meteostat
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.1
|
|
4
4
|
Summary: Access and analyze historical weather and climate data with Python.
|
|
5
5
|
Home-page: https://github.com/meteostat/meteostat-python
|
|
6
6
|
Author: Meteostat
|
|
@@ -14,7 +14,7 @@ Classifier: Topic :: Database
|
|
|
14
14
|
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
15
15
|
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
16
16
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
17
|
-
Requires-Python: >=3.
|
|
17
|
+
Requires-Python: >=3.8.0
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ License-File: LICENSE
|
|
|
22
22
|
|
|
23
23
|
The Meteostat Python library provides a simple API for accessing open weather and climate data. The historical observations and statistics are collected by [Meteostat](https://meteostat.net) from different public interfaces, most of which are governmental.
|
|
24
24
|
|
|
25
|
-
Among the data sources are national weather services like the National Oceanic and Atmospheric Administration (NOAA) and Germany's national
|
|
25
|
+
Among the data sources are national weather services like the National Oceanic and Atmospheric Administration (NOAA) and Germany's national weather service (DWD).
|
|
26
26
|
|
|
27
27
|
Are you looking for a **hosted solution**? Try our [JSON API](https://rapidapi.com/meteostat/api/meteostat/).
|
|
28
28
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The Meteostat Python library provides a simple API for accessing open weather and climate data. The historical observations and statistics are collected by [Meteostat](https://meteostat.net) from different public interfaces, most of which are governmental.
|
|
4
4
|
|
|
5
|
-
Among the data sources are national weather services like the National Oceanic and Atmospheric Administration (NOAA) and Germany's national
|
|
5
|
+
Among the data sources are national weather services like the National Oceanic and Atmospheric Administration (NOAA) and Germany's national weather service (DWD).
|
|
6
6
|
|
|
7
7
|
Are you looking for a **hosted solution**? Try our [JSON API](https://rapidapi.com/meteostat/api/meteostat/).
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ The code is licensed under the MIT license.
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
__appname__ = "meteostat"
|
|
15
|
-
__version__ = "1.
|
|
15
|
+
__version__ = "1.7.1"
|
|
16
16
|
|
|
17
17
|
from .interface.base import Base
|
|
18
18
|
from .interface.timeseries import TimeSeries
|
|
@@ -22,3 +22,14 @@ from .interface.hourly import Hourly
|
|
|
22
22
|
from .interface.daily import Daily
|
|
23
23
|
from .interface.monthly import Monthly
|
|
24
24
|
from .interface.normals import Normals
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"Base",
|
|
28
|
+
"TimeSeries",
|
|
29
|
+
"Stations",
|
|
30
|
+
"Point",
|
|
31
|
+
"Hourly",
|
|
32
|
+
"Daily",
|
|
33
|
+
"Monthly",
|
|
34
|
+
"Normals",
|
|
35
|
+
]
|
|
@@ -53,7 +53,6 @@ def clear_cache(cls, max_age: int = None) -> None:
|
|
|
53
53
|
"""
|
|
54
54
|
|
|
55
55
|
if os.path.exists(cls.cache_dir + os.sep + cls.cache_subdir):
|
|
56
|
-
|
|
57
56
|
# Set max_age
|
|
58
57
|
if max_age is None:
|
|
59
58
|
max_age = cls.max_age
|
|
@@ -63,7 +62,6 @@ def clear_cache(cls, max_age: int = None) -> None:
|
|
|
63
62
|
|
|
64
63
|
# Go through all files
|
|
65
64
|
for file in os.listdir(cls.cache_dir + os.sep + cls.cache_subdir):
|
|
66
|
-
|
|
67
65
|
# Get full path
|
|
68
66
|
path = os.path.join(cls.cache_dir + os.sep + cls.cache_subdir, file)
|
|
69
67
|
|
|
@@ -8,16 +8,19 @@ under the terms of the Creative Commons Attribution-NonCommercial
|
|
|
8
8
|
The code is licensed under the MIT license.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
from io import BytesIO
|
|
12
|
+
from gzip import GzipFile
|
|
13
|
+
from urllib.request import Request, ProxyHandler, build_opener
|
|
11
14
|
from urllib.error import HTTPError
|
|
12
15
|
from multiprocessing import Pool
|
|
13
16
|
from multiprocessing.pool import ThreadPool
|
|
14
|
-
from typing import Callable,
|
|
17
|
+
from typing import Callable, List, Optional
|
|
15
18
|
import pandas as pd
|
|
16
19
|
from meteostat.core.warn import warn
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
def processing_handler(
|
|
20
|
-
datasets:
|
|
23
|
+
datasets: List, load: Callable[[dict], None], cores: int, threads: int
|
|
21
24
|
) -> None:
|
|
22
25
|
"""
|
|
23
26
|
Load multiple datasets (simultaneously)
|
|
@@ -28,10 +31,8 @@ def processing_handler(
|
|
|
28
31
|
|
|
29
32
|
# Multi-core processing
|
|
30
33
|
if cores > 1 and len(datasets) > 1:
|
|
31
|
-
|
|
32
34
|
# Create process pool
|
|
33
35
|
with Pool(cores) as pool:
|
|
34
|
-
|
|
35
36
|
# Process datasets in pool
|
|
36
37
|
output = pool.starmap(load, datasets)
|
|
37
38
|
|
|
@@ -41,10 +42,8 @@ def processing_handler(
|
|
|
41
42
|
|
|
42
43
|
# Multi-thread processing
|
|
43
44
|
elif threads > 1 and len(datasets) > 1:
|
|
44
|
-
|
|
45
45
|
# Create process pool
|
|
46
46
|
with ThreadPool(threads) as pool:
|
|
47
|
-
|
|
48
47
|
# Process datasets in pool
|
|
49
48
|
output = pool.starmap(load, datasets)
|
|
50
49
|
|
|
@@ -54,12 +53,11 @@ def processing_handler(
|
|
|
54
53
|
|
|
55
54
|
# Single-thread processing
|
|
56
55
|
else:
|
|
57
|
-
|
|
58
56
|
for dataset in datasets:
|
|
59
57
|
output.append(load(*dataset))
|
|
60
58
|
|
|
61
59
|
# Remove empty DataFrames
|
|
62
|
-
filtered = list(filter(lambda df: df.
|
|
60
|
+
filtered = list(filter(lambda df: not df.empty, output))
|
|
63
61
|
|
|
64
62
|
return pd.concat(filtered) if len(filtered) > 0 else output[0]
|
|
65
63
|
|
|
@@ -67,36 +65,36 @@ def processing_handler(
|
|
|
67
65
|
def load_handler(
|
|
68
66
|
endpoint: str,
|
|
69
67
|
path: str,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
proxy: Optional[str] = None,
|
|
69
|
+
names: Optional[List] = None,
|
|
70
|
+
dtype: Optional[dict] = None,
|
|
71
|
+
parse_dates: Optional[List] = None,
|
|
72
|
+
default_df: Optional[pd.DataFrame] = None,
|
|
74
73
|
) -> pd.DataFrame:
|
|
75
74
|
"""
|
|
76
75
|
Load a single CSV file into a DataFrame
|
|
77
76
|
"""
|
|
78
77
|
|
|
79
78
|
try:
|
|
79
|
+
handlers = []
|
|
80
|
+
|
|
81
|
+
# Set a proxy
|
|
82
|
+
if proxy:
|
|
83
|
+
handlers.append(ProxyHandler({"http": proxy, "https": proxy}))
|
|
80
84
|
|
|
81
85
|
# Read CSV file from Meteostat endpoint
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if coerce_dates:
|
|
92
|
-
df.iloc[:, parse_dates] = df.iloc[:, parse_dates].apply(
|
|
93
|
-
pd.to_datetime, errors="coerce"
|
|
94
|
-
)
|
|
86
|
+
with build_opener(*handlers).open(Request(endpoint + path)) as response:
|
|
87
|
+
# Decompress the content
|
|
88
|
+
with GzipFile(fileobj=BytesIO(response.read()), mode="rb") as file:
|
|
89
|
+
df = pd.read_csv(
|
|
90
|
+
file,
|
|
91
|
+
names=names,
|
|
92
|
+
dtype=dtype,
|
|
93
|
+
parse_dates=parse_dates,
|
|
94
|
+
)
|
|
95
95
|
|
|
96
96
|
except (FileNotFoundError, HTTPError):
|
|
97
|
-
|
|
98
|
-
# Create empty DataFrane
|
|
99
|
-
df = pd.DataFrame(columns=[*types])
|
|
97
|
+
df = default_df if default_df is not None else pd.DataFrame(columns=names)
|
|
100
98
|
|
|
101
99
|
# Display warning
|
|
102
100
|
warn(f"Cannot load {path} from {endpoint}")
|
|
@@ -9,28 +9,31 @@ The code is licensed under the MIT license.
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import os
|
|
12
|
+
from typing import Optional
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class Base:
|
|
15
|
-
|
|
16
16
|
"""
|
|
17
17
|
Base class that provides features which are used across the package
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
# Base URL of the Meteostat bulk data interface
|
|
21
|
-
endpoint
|
|
21
|
+
endpoint = "https://bulk.meteostat.net/v2/"
|
|
22
|
+
|
|
23
|
+
# Proxy URL for the Meteostat (bulk) data interface
|
|
24
|
+
proxy: Optional[str] = None
|
|
22
25
|
|
|
23
26
|
# Location of the cache directory
|
|
24
|
-
cache_dir
|
|
27
|
+
cache_dir = os.path.expanduser("~") + os.sep + ".meteostat" + os.sep + "cache"
|
|
25
28
|
|
|
26
29
|
# Auto clean cache directories?
|
|
27
|
-
autoclean
|
|
30
|
+
autoclean = True
|
|
28
31
|
|
|
29
32
|
# Maximum age of a cached file in seconds
|
|
30
|
-
max_age
|
|
33
|
+
max_age = 24 * 60 * 60
|
|
31
34
|
|
|
32
35
|
# Number of processes used for processing files
|
|
33
|
-
processes
|
|
36
|
+
processes = 1
|
|
34
37
|
|
|
35
38
|
# Number of threads used for processing files
|
|
36
|
-
threads
|
|
39
|
+
threads = 1
|
|
@@ -8,7 +8,7 @@ under the terms of the Creative Commons Attribution-NonCommercial
|
|
|
8
8
|
The code is licensed under the MIT license.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
from datetime import datetime
|
|
11
|
+
from datetime import datetime, timedelta
|
|
12
12
|
from typing import Union
|
|
13
13
|
import pandas as pd
|
|
14
14
|
from meteostat.enumerations.granularity import Granularity
|
|
@@ -18,33 +18,54 @@ from meteostat.interface.point import Point
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class Daily(TimeSeries):
|
|
21
|
-
|
|
22
21
|
"""
|
|
23
22
|
Retrieve daily weather observations for one or multiple weather stations or
|
|
24
23
|
a single geographical point
|
|
25
24
|
"""
|
|
26
25
|
|
|
27
26
|
# The cache subdirectory
|
|
28
|
-
cache_subdir
|
|
27
|
+
cache_subdir = "daily"
|
|
29
28
|
|
|
30
29
|
# Granularity
|
|
31
30
|
granularity = Granularity.DAILY
|
|
32
31
|
|
|
32
|
+
# Download data as annual chunks
|
|
33
|
+
# This cannot be changed and is only kept for backward compatibility
|
|
34
|
+
chunked = True
|
|
35
|
+
|
|
33
36
|
# Default frequency
|
|
34
|
-
_freq
|
|
37
|
+
_freq = "1D"
|
|
38
|
+
|
|
39
|
+
# Source mappings
|
|
40
|
+
_source_mappings = {
|
|
41
|
+
"dwd_daily": "A",
|
|
42
|
+
"eccc_daily": "A",
|
|
43
|
+
"ghcnd": "B",
|
|
44
|
+
"dwd_hourly": "C",
|
|
45
|
+
"eccc_hourly": "C",
|
|
46
|
+
"isd_lite": "D",
|
|
47
|
+
"synop": "E",
|
|
48
|
+
"dwd_poi": "E",
|
|
49
|
+
"metar": "F",
|
|
50
|
+
"model": "G",
|
|
51
|
+
"dwd_mosmix": "G",
|
|
52
|
+
"metno_forecast": "G",
|
|
53
|
+
}
|
|
35
54
|
|
|
36
55
|
# Flag which represents model data
|
|
37
56
|
_model_flag = "G"
|
|
38
57
|
|
|
39
58
|
# Columns
|
|
40
|
-
_columns
|
|
41
|
-
"
|
|
42
|
-
"
|
|
59
|
+
_columns = [
|
|
60
|
+
"year",
|
|
61
|
+
"month",
|
|
62
|
+
"day",
|
|
63
|
+
{"tavg": "temp"},
|
|
43
64
|
"tmin",
|
|
44
65
|
"tmax",
|
|
45
66
|
"prcp",
|
|
46
|
-
"snow",
|
|
47
|
-
"wdir",
|
|
67
|
+
{"snow": "snwd"},
|
|
68
|
+
{"wdir": None},
|
|
48
69
|
"wspd",
|
|
49
70
|
"wpgt",
|
|
50
71
|
"pres",
|
|
@@ -52,27 +73,13 @@ class Daily(TimeSeries):
|
|
|
52
73
|
]
|
|
53
74
|
|
|
54
75
|
# Index of first meteorological column
|
|
55
|
-
_first_met_col =
|
|
56
|
-
|
|
57
|
-
# Data types
|
|
58
|
-
_types: dict = {
|
|
59
|
-
"tavg": "float64",
|
|
60
|
-
"tmin": "float64",
|
|
61
|
-
"tmax": "float64",
|
|
62
|
-
"prcp": "float64",
|
|
63
|
-
"snow": "float64",
|
|
64
|
-
"wdir": "float64",
|
|
65
|
-
"wspd": "float64",
|
|
66
|
-
"wpgt": "float64",
|
|
67
|
-
"pres": "float64",
|
|
68
|
-
"tsun": "float64",
|
|
69
|
-
}
|
|
76
|
+
_first_met_col = 3
|
|
70
77
|
|
|
71
78
|
# Columns for date parsing
|
|
72
|
-
_parse_dates
|
|
79
|
+
_parse_dates = ["year", "month", "day"]
|
|
73
80
|
|
|
74
81
|
# Default aggregation functions
|
|
75
|
-
aggregations
|
|
82
|
+
aggregations = {
|
|
76
83
|
"tavg": "mean",
|
|
77
84
|
"tmin": "min",
|
|
78
85
|
"tmax": "max",
|
|
@@ -88,12 +95,18 @@ class Daily(TimeSeries):
|
|
|
88
95
|
def __init__(
|
|
89
96
|
self,
|
|
90
97
|
loc: Union[pd.DataFrame, Point, list, str], # Station(s) or geo point
|
|
91
|
-
start
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
start=datetime(1781, 1, 1, 0, 0, 0),
|
|
99
|
+
end=datetime.combine(
|
|
100
|
+
datetime.today().date() + timedelta(days=10), datetime.max.time()
|
|
101
|
+
),
|
|
102
|
+
model=True, # Include model data?
|
|
103
|
+
flags=False, # Load source flags?
|
|
95
104
|
) -> None:
|
|
96
|
-
|
|
105
|
+
# Extract relevant years
|
|
106
|
+
if self.chunked:
|
|
107
|
+
self._annual_steps = [
|
|
108
|
+
start.year + i for i in range(end.year - start.year + 1)
|
|
109
|
+
]
|
|
97
110
|
# Initialize time series
|
|
98
111
|
self._init_time_series(loc, start, end, model, flags)
|
|
99
112
|
|
|
@@ -9,50 +9,66 @@ The code is licensed under the MIT license.
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from math import floor
|
|
12
|
-
from datetime import datetime
|
|
13
|
-
from typing import Union
|
|
12
|
+
from datetime import datetime, timedelta
|
|
13
|
+
from typing import Optional, Union
|
|
14
14
|
import pytz
|
|
15
15
|
import pandas as pd
|
|
16
16
|
from meteostat.enumerations.granularity import Granularity
|
|
17
17
|
from meteostat.utilities.aggregations import degree_mean
|
|
18
18
|
from meteostat.interface.timeseries import TimeSeries
|
|
19
19
|
from meteostat.interface.point import Point
|
|
20
|
+
from meteostat.utilities.mutations import calculate_dwpt
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class Hourly(TimeSeries):
|
|
23
|
-
|
|
24
24
|
"""
|
|
25
25
|
Retrieve hourly weather observations for one or multiple weather stations or
|
|
26
26
|
a single geographical point
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
# The cache subdirectory
|
|
30
|
-
cache_subdir
|
|
30
|
+
cache_subdir = "hourly"
|
|
31
31
|
|
|
32
32
|
# Granularity
|
|
33
33
|
granularity = Granularity.HOURLY
|
|
34
34
|
|
|
35
35
|
# Download data as annual chunks
|
|
36
|
-
|
|
36
|
+
# This cannot be changed and is only kept for backward compatibility
|
|
37
|
+
chunked = True
|
|
37
38
|
|
|
38
39
|
# The time zone
|
|
39
|
-
_timezone: str = None
|
|
40
|
+
_timezone: Optional[str] = None
|
|
40
41
|
|
|
41
42
|
# Default frequency
|
|
42
|
-
_freq
|
|
43
|
+
_freq = "1h"
|
|
44
|
+
|
|
45
|
+
# Source mappings
|
|
46
|
+
_source_mappings = {
|
|
47
|
+
"metar": "D",
|
|
48
|
+
"model": "E",
|
|
49
|
+
"isd_lite": "B",
|
|
50
|
+
"synop": "C",
|
|
51
|
+
"dwd_poi": "C",
|
|
52
|
+
"dwd_hourly": "A",
|
|
53
|
+
"dwd_mosmix": "E",
|
|
54
|
+
"metno_forecast": "E",
|
|
55
|
+
"eccc_hourly": "A",
|
|
56
|
+
}
|
|
43
57
|
|
|
44
58
|
# Flag which represents model data
|
|
45
59
|
_model_flag = "E"
|
|
46
60
|
|
|
47
61
|
# Raw data columns
|
|
48
|
-
_columns
|
|
49
|
-
"
|
|
62
|
+
_columns = [
|
|
63
|
+
"year",
|
|
64
|
+
"month",
|
|
65
|
+
"day",
|
|
50
66
|
"hour",
|
|
51
67
|
"temp",
|
|
52
|
-
"dwpt",
|
|
68
|
+
{"dwpt": calculate_dwpt},
|
|
53
69
|
"rhum",
|
|
54
70
|
"prcp",
|
|
55
|
-
"snow",
|
|
71
|
+
{"snow": "snwd"},
|
|
56
72
|
"wdir",
|
|
57
73
|
"wspd",
|
|
58
74
|
"wpgt",
|
|
@@ -62,28 +78,13 @@ class Hourly(TimeSeries):
|
|
|
62
78
|
]
|
|
63
79
|
|
|
64
80
|
# Index of first meteorological column
|
|
65
|
-
_first_met_col =
|
|
66
|
-
|
|
67
|
-
# Data types
|
|
68
|
-
_types: dict = {
|
|
69
|
-
"temp": "float64",
|
|
70
|
-
"dwpt": "float64",
|
|
71
|
-
"rhum": "float64",
|
|
72
|
-
"prcp": "float64",
|
|
73
|
-
"snow": "float64",
|
|
74
|
-
"wdir": "float64",
|
|
75
|
-
"wspd": "float64",
|
|
76
|
-
"wpgt": "float64",
|
|
77
|
-
"pres": "float64",
|
|
78
|
-
"tsun": "float64",
|
|
79
|
-
"coco": "float64",
|
|
80
|
-
}
|
|
81
|
+
_first_met_col = 4
|
|
81
82
|
|
|
82
83
|
# Columns for date parsing
|
|
83
|
-
_parse_dates
|
|
84
|
+
_parse_dates = ["year", "month", "day", "hour"]
|
|
84
85
|
|
|
85
86
|
# Default aggregation functions
|
|
86
|
-
aggregations
|
|
87
|
+
aggregations = {
|
|
87
88
|
"temp": "mean",
|
|
88
89
|
"dwpt": "mean",
|
|
89
90
|
"rhum": "mean",
|
|
@@ -98,22 +99,19 @@ class Hourly(TimeSeries):
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
def _set_time(
|
|
101
|
-
self,
|
|
102
|
+
self,
|
|
103
|
+
start: Optional[datetime] = None,
|
|
104
|
+
end: Optional[datetime] = None,
|
|
105
|
+
timezone: Optional[str] = None,
|
|
102
106
|
) -> None:
|
|
103
107
|
"""
|
|
104
108
|
Set & adapt the period's time zone
|
|
105
109
|
"""
|
|
106
|
-
|
|
107
|
-
# Don't use chunks if full dataset is requested
|
|
108
|
-
if start == None:
|
|
109
|
-
self.chunked = False
|
|
110
|
-
|
|
111
110
|
if timezone:
|
|
112
111
|
# Save timezone
|
|
113
112
|
self._timezone = timezone
|
|
114
113
|
|
|
115
114
|
if start and end:
|
|
116
|
-
|
|
117
115
|
# Initialize time zone
|
|
118
116
|
timezone = pytz.timezone(self._timezone)
|
|
119
117
|
|
|
@@ -124,7 +122,9 @@ class Hourly(TimeSeries):
|
|
|
124
122
|
end = timezone.localize(end, is_dst=None).astimezone(pytz.utc)
|
|
125
123
|
|
|
126
124
|
if self.chunked:
|
|
127
|
-
self._annual_steps = [
|
|
125
|
+
self._annual_steps = [
|
|
126
|
+
start.year + i for i in range(end.year - start.year + 1)
|
|
127
|
+
]
|
|
128
128
|
|
|
129
129
|
self._start = start
|
|
130
130
|
self._end = end
|
|
@@ -132,13 +132,14 @@ class Hourly(TimeSeries):
|
|
|
132
132
|
def __init__(
|
|
133
133
|
self,
|
|
134
134
|
loc: Union[pd.DataFrame, Point, list, str], # Station(s) or geo point
|
|
135
|
-
start
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
start=datetime(1890, 1, 1, 0, 0, 0),
|
|
136
|
+
end=datetime.combine(
|
|
137
|
+
datetime.today().date() + timedelta(days=10), datetime.max.time()
|
|
138
|
+
),
|
|
139
|
+
timezone: Optional[str] = None,
|
|
140
|
+
model=True, # Include model data?
|
|
141
|
+
flags=False, # Load source flags?
|
|
140
142
|
) -> None:
|
|
141
|
-
|
|
142
143
|
# Set time zone and adapt period
|
|
143
144
|
self._set_time(start, end, timezone)
|
|
144
145
|
|