Skip to content

Commit 7cc4459

Browse files
authored
Meteostat 1.5.1 (#54)
* Meteostat 1.5.1 * Update README * Update README
1 parent 382bf27 commit 7cc4459

File tree

9 files changed

+126
-44
lines changed

9 files changed

+126
-44
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ The Meteostat Python library provides a simple API for accessing open weather an
44

55
Among the data sources are national weather services like the National Oceanic and Atmospheric Administration (NOAA) and Germany's national meteorological service (DWD).
66

7+
Are you looking for a **hosted solution**? Try our [JSON API](https://rapidapi.com/meteostat/api/meteostat/).
8+
79
## Installation
810

911
The Meteostat Python package is available through [PyPI](https://pypi.org/project/meteostat/):

examples/daily/compare.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,19 @@
1010

1111
from datetime import datetime
1212
import matplotlib.pyplot as plt
13-
from meteostat import Stations, Daily
14-
15-
# Get weather stations by WMO ID
16-
stations = Stations()
17-
stations = stations.id('wmo', ('71624', '72295', '68816', '94767'))
18-
stations = stations.fetch()
19-
20-
# Get names of weather stations
21-
names = stations['name'].to_list()
13+
from meteostat import Daily
2214

2315
# Time period
2416
start = datetime(2019, 1, 1)
2517
end = datetime(2019, 12, 31)
2618

2719
# Get daily data
28-
data = Daily(stations, start, end)
20+
data = Daily(['71624', '72295', '68816', '94767'], start, end)
2921
data = data.fetch()
3022

3123
# Plot chart
3224
data.unstack('station')['tavg'].plot(
3325
legend=True,
3426
ylabel='Avg. Daily Temperature °C',
3527
title='Average Temperature Report for 2019')
36-
plt.legend(names)
3728
plt.show()

meteostat/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"""
1313

1414
__appname__ = 'meteostat'
15-
__version__ = '1.5.0'
15+
__version__ = '1.5.1'
1616

1717
from .interface.base import Base
1818
from .interface.timeseries import Timeseries

meteostat/interface/daily.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,39 @@ def _resolve_point(
170170
if self._stations.size == 0 or self._data.size == 0:
171171
return None
172172

173+
def adjust_temp(data: pd.DataFrame):
174+
"""
175+
Adjust temperature-like data based on altitude
176+
"""
177+
178+
data.loc[data['tavg'] != np.NaN, 'tavg'] = data['tavg'] + \
179+
((2 / 3) * ((data['elevation'] - alt) / 100))
180+
data.loc[data['tmin'] != np.NaN, 'tmin'] = data['tmin'] + \
181+
((2 / 3) * ((data['elevation'] - alt) / 100))
182+
data.loc[data['tmax'] != np.NaN, 'tmax'] = data['tmax'] + \
183+
((2 / 3) * ((data['elevation'] - alt) / 100))
184+
185+
return data
186+
173187
if method == 'nearest':
174188

175-
self._data = self._data.groupby(
189+
if adapt_temp:
190+
191+
# Join elevation of involved weather stations
192+
data = self._data.join(
193+
stations['elevation'], on='station')
194+
195+
# Adapt temperature-like data based on altitude
196+
data = adjust_temp(data)
197+
198+
# Drop elevation & round
199+
data = data.drop('elevation', axis=1).round(1)
200+
201+
else:
202+
203+
data = self._data
204+
205+
self._data = data.groupby(
176206
pd.Grouper(level='time', freq=self._freq)).agg('first')
177207

178208
else:
@@ -183,12 +213,7 @@ def _resolve_point(
183213

184214
# Adapt temperature-like data based on altitude
185215
if adapt_temp:
186-
data.loc[data['tavg'] != np.NaN, 'tavg'] = data['tavg'] + \
187-
((2 / 3) * ((data['elevation'] - alt) / 100))
188-
data.loc[data['tmin'] != np.NaN, 'tmin'] = data['tmin'] + \
189-
((2 / 3) * ((data['elevation'] - alt) / 100))
190-
data.loc[data['tmax'] != np.NaN, 'tmax'] = data['tmax'] + \
191-
((2 / 3) * ((data['elevation'] - alt) / 100))
216+
data = adjust_temp(data)
192217

193218
# Exclude non-mean data & perform aggregation
194219
excluded = data['wdir']

meteostat/interface/hourly.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,37 @@ def _resolve_point(
238238
if self._stations.size == 0 or self._data.size == 0:
239239
return None
240240

241+
def adjust_temp(data: pd.DataFrame):
242+
"""
243+
Adjust temperature-like data based on altitude
244+
"""
245+
246+
data.loc[data['temp'] != np.NaN, 'temp'] = data['temp'] + \
247+
((2 / 3) * ((data['elevation'] - alt) / 100))
248+
data.loc[data['dwpt'] != np.NaN, 'dwpt'] = data['dwpt'] + \
249+
((2 / 3) * ((data['elevation'] - alt) / 100))
250+
251+
return data
252+
241253
if method == 'nearest':
242254

243-
self._data = self._data.groupby(pd.Grouper(
255+
if adapt_temp:
256+
257+
# Join elevation of involved weather stations
258+
data = self._data.join(
259+
stations['elevation'], on='station')
260+
261+
# Adapt temperature-like data based on altitude
262+
data = adjust_temp(data)
263+
264+
# Drop elevation & round
265+
data = data.drop('elevation', axis=1).round(1)
266+
267+
else:
268+
269+
data = self._data
270+
271+
self._data = data.groupby(pd.Grouper(
244272
level='time', freq=self._freq)).agg('first')
245273

246274
else:
@@ -251,10 +279,7 @@ def _resolve_point(
251279

252280
# Adapt temperature-like data based on altitude
253281
if adapt_temp:
254-
data.loc[data['temp'] != np.NaN, 'temp'] = data['temp'] + \
255-
((2 / 3) * ((data['elevation'] - alt) / 100))
256-
data.loc[data['dwpt'] != np.NaN, 'dwpt'] = data['dwpt'] + \
257-
((2 / 3) * ((data['elevation'] - alt) / 100))
282+
data = adjust_temp(data)
258283

259284
# Exclude non-mean data & perform aggregation
260285
excluded = data[['wdir', 'coco']]

meteostat/interface/monthly.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,38 @@ def _resolve_point(
170170
if self._stations.size == 0 or self._data.size == 0:
171171
return None
172172

173+
def adjust_temp(data: pd.DataFrame):
174+
"""
175+
Adjust temperature-like data based on altitude
176+
"""
177+
178+
data.loc[data['tavg'] != np.NaN, 'tavg'] = data['tavg'] + \
179+
((2 / 3) * ((data['elevation'] - alt) / 100))
180+
data.loc[data['tmin'] != np.NaN, 'tmin'] = data['tmin'] + \
181+
((2 / 3) * ((data['elevation'] - alt) / 100))
182+
data.loc[data['tmax'] != np.NaN, 'tmax'] = data['tmax'] + \
183+
((2 / 3) * ((data['elevation'] - alt) / 100))
184+
185+
return data
186+
173187
if method == 'nearest':
174188

189+
if adapt_temp:
190+
191+
# Join elevation of involved weather stations
192+
data = self._data.join(
193+
stations['elevation'], on='station')
194+
195+
# Adapt temperature-like data based on altitude
196+
data = adjust_temp(data)
197+
198+
# Drop elevation & round
199+
data = data.drop('elevation', axis=1).round(1)
200+
201+
else:
202+
203+
data = self._data
204+
175205
self._data = self._data.groupby(
176206
pd.Grouper(level='time', freq=self._freq)).agg('first')
177207

@@ -183,12 +213,7 @@ def _resolve_point(
183213

184214
# Adapt temperature-like data based on altitude
185215
if adapt_temp:
186-
data.loc[data['tavg'] != np.NaN, 'tavg'] = data['tavg'] + \
187-
((2 / 3) * ((data['elevation'] - alt) / 100))
188-
data.loc[data['tmin'] != np.NaN, 'tmin'] = data['tmin'] + \
189-
((2 / 3) * ((data['elevation'] - alt) / 100))
190-
data.loc[data['tmax'] != np.NaN, 'tmax'] = data['tmax'] + \
191-
((2 / 3) * ((data['elevation'] - alt) / 100))
216+
data = adjust_temp(data)
192217

193218
# Exclude non-mean data & perform aggregation
194219
excluded = data['wdir']

meteostat/interface/point.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class Point:
2020
"""
2121

2222
# The interpolation method (weighted or nearest)
23-
method: str = 'weighted'
23+
method: str = 'nearest'
2424

2525
# Maximum radius for nearby stations
2626
radius: int = 35000
@@ -41,7 +41,7 @@ class Point:
4141
weight_alt: float = 0.4
4242

4343
# The list of weather stations
44-
stations: pd.Index = None
44+
_stations: pd.Index = None
4545

4646
# The latitude
4747
_lat: float = None
@@ -83,17 +83,19 @@ def get_stations(self, freq: str = None, start: datetime = None,
8383

8484
# Captue unfiltered weather stations
8585
unfiltered = stations.fetch()
86-
unfiltered = unfiltered[abs(self._alt -
87-
unfiltered['elevation']) <= self.alt_range]
86+
if self.alt_range:
87+
unfiltered = unfiltered[abs(self._alt -
88+
unfiltered['elevation']) <= self.alt_range]
8889

8990
# Apply inventory filter
9091
if freq and start and end:
9192
stations = stations.inventory(freq, (start, end))
9293

9394
# Apply altitude filter
9495
stations = stations.fetch()
95-
stations = stations[abs(self._alt -
96-
stations['elevation']) <= self.alt_range]
96+
if self.alt_range:
97+
stations = stations[abs(self._alt -
98+
stations['elevation']) <= self.alt_range]
9799

98100
# Fill up stations
99101
selected: int = len(stations.index)
@@ -102,15 +104,18 @@ def get_stations(self, freq: str = None, start: datetime = None,
102104
unfiltered.head(
103105
self.max_count - selected))
104106

105-
# Calculate score values
106-
stations['score'] = ((1 - (stations['distance'] / self.radius)) * self.weight_dist) + (
107-
(1 - (abs(self._alt - stations['elevation']) / self.alt_range)) * self.weight_alt)
107+
# Score values
108+
if self.radius:
108109

109-
# Sort by score (descending)
110-
stations = stations.sort_values('score', ascending=False)
110+
# Calculate score values
111+
stations['score'] = ((1 - (stations['distance'] / self.radius)) * self.weight_dist) + (
112+
(1 - (abs(self._alt - stations['elevation']) / self.alt_range)) * self.weight_alt)
113+
114+
# Sort by score (descending)
115+
stations = stations.sort_values('score', ascending=False)
111116

112117
# Capture result
113-
self.stations = stations.index[:self.max_count]
118+
self._stations = stations.index[:self.max_count]
114119

115120
return stations.head(self.max_count)
116121

@@ -122,3 +127,12 @@ def alt(self) -> int:
122127

123128
# Return altitude
124129
return self._alt
130+
131+
@property
132+
def stations(self) -> pd.Index:
133+
"""
134+
Returns the point's weather stations
135+
"""
136+
137+
# Return weather stations
138+
return self._stations

meteostat/interface/stations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def distance(lat1, lon1, lat2, lon2):
151151
lat, lon, temp._data['latitude'], temp._data['longitude'])
152152

153153
# Filter by radius
154-
if radius is not None:
154+
if radius:
155155
temp._data = temp._data[temp._data['distance'] <= radius]
156156

157157
# Sort stations by distance

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# Setup
1616
setup(
1717
name='meteostat',
18-
version='1.5.0',
18+
version='1.5.1',
1919
author='Meteostat',
2020
author_email='[email protected]',
2121
description='Access and analyze historical weather and climate data with Python.',

0 commit comments

Comments
 (0)