Access and analyze historical weather and climate data with Python.
—
The Monthly class provides access to monthly aggregated weather statistics, offering long-term climate patterns and trends. Monthly data is ideal for climate analysis, seasonal comparisons, and understanding regional weather patterns over extended periods.
Create a monthly time series for weather stations or geographic points with flexible time range options.
class Monthly:
def __init__(self, loc: Union[pd.DataFrame, Point, list, str], start: datetime = None, end: datetime = None, model: bool = True, flags: bool = False) -> None:
"""
Initialize monthly weather data retrieval.
Parameters:
- loc: Union[pd.DataFrame, Point, list, str]
- pd.DataFrame: Station data from Stations.fetch()
- Point: Geographic point for automatic station selection
- list: List of station IDs
- str: Single station ID
- start: datetime, optional start of time period (day will be set to 1st)
- end: datetime, optional end of time period
- model: bool, whether to include model/reanalysis data (default: True)
- flags: bool, whether to include data source flags (default: False)
"""Calculate expected number of monthly observations for the defined time period.
def expected_rows(self) -> int:
"""
Return expected number of monthly rows for the date range.
Returns:
int, expected number of monthly observations
"""Monthly data includes the following aggregated meteorological parameters:
# Temperature measurements (°C)
tavg: float # Average temperature for the month
tmin: float # Average minimum temperature
tmax: float # Average maximum temperature
# Precipitation
prcp: float # Total precipitation amount (mm)
# Wind measurements
wspd: float # Average wind speed (km/h)
# Atmospheric pressure
pres: float # Average sea level pressure (hPa)
# Solar radiation
tsun: float # Total sunshine duration (hours)
# Data quality flags (when flags=True)
tavg_flag: str # Average temperature data source flag
tmin_flag: str # Minimum temperature data source flag
tmax_flag: str # Maximum temperature data source flag
# ... (additional _flag columns for each parameter)from datetime import datetime
from meteostat import Point, Monthly
# Set time period for recent years
start = datetime(2015, 1, 1)
end = datetime(2020, 12, 31)
# Create point for Rome, Italy
rome = Point(41.9028, 12.4964, 20)
# Get monthly data
data = Monthly(rome, start, end)
monthly_data = data.fetch()
print(f"Retrieved {len(monthly_data)} monthly observations")
print(monthly_data[['tavg', 'tmin', 'tmax', 'prcp']].head())from datetime import datetime
from meteostat import Point, Monthly
import matplotlib.pyplot as plt
# Analyze temperature trends for central England
central_england = Point(52.0, -2.0)
# Get 50 years of monthly data
start = datetime(1970, 1, 1)
end = datetime(2020, 12, 31)
data = Monthly(central_england, start, end)
monthly_data = data.fetch()
# Calculate annual temperature anomalies
baseline_period = monthly_data['1981':'2010']
baseline_temp = baseline_period['tavg'].mean()
annual_temps = monthly_data.groupby(monthly_data.index.year)['tavg'].mean()
temperature_anomalies = annual_temps - baseline_temp
print("Temperature anomalies relative to 1981-2010 baseline:")
print(temperature_anomalies.tail(10))from datetime import datetime
from meteostat import Point, Monthly
import pandas as pd
# Analyze seasonal patterns for Moscow
moscow = Point(55.7558, 37.6173, 156)
# Get 30 years of data
start = datetime(1990, 1, 1)
end = datetime(2020, 12, 31)
data = Monthly(moscow, start, end)
monthly_data = data.fetch()
# Calculate seasonal averages
monthly_data['season'] = monthly_data.index.month.map({
12: 'Winter', 1: 'Winter', 2: 'Winter',
3: 'Spring', 4: 'Spring', 5: 'Spring',
6: 'Summer', 7: 'Summer', 8: 'Summer',
9: 'Fall', 10: 'Fall', 11: 'Fall'
})
seasonal_climate = monthly_data.groupby('season').agg({
'tavg': ['mean', 'std'],
'prcp': ['mean', 'std'],
'tsun': 'mean'
})
print("30-year seasonal climate summary for Moscow:")
print(seasonal_climate)from datetime import datetime
from meteostat import Stations, Monthly
# Compare climate between different regions
northern_stations = Stations().region('NO').fetch(3) # Norway
southern_stations = Stations().region('ES').fetch(3) # Spain
# Get climate data for comparison period
start = datetime(2000, 1, 1)
end = datetime(2020, 12, 31)
# Northern Europe climate
north_data = Monthly(northern_stations, start, end).fetch()
north_climate = north_data.groupby(north_data.index.month).agg({
'tavg': 'mean', 'prcp': 'mean'
})
# Southern Europe climate
south_data = Monthly(southern_stations, start, end).fetch()
south_climate = south_data.groupby(south_data.index.month).agg({
'tavg': 'mean', 'prcp': 'mean'
})
print("Climate comparison - Average monthly temperature (°C):")
comparison = pd.DataFrame({
'Northern Europe': north_climate['tavg'],
'Southern Europe': south_climate['tavg']
})
print(comparison)from datetime import datetime
from meteostat import Point, Monthly
# Analyze drought conditions for California
california = Point(36.7783, -119.4179)
# Get monthly precipitation data
start = datetime(1950, 1, 1)
end = datetime(2020, 12, 31)
data = Monthly(california, start, end)
monthly_data = data.fetch()
# Calculate standardized precipitation index (simple version)
monthly_precip = monthly_data['prcp']
# Calculate long-term monthly averages
monthly_normals = monthly_precip.groupby(monthly_precip.index.month).mean()
# Identify drought years (annual precipitation < 75% of normal)
annual_precip = monthly_precip.groupby(monthly_precip.index.year).sum()
normal_annual = monthly_normals.sum()
drought_threshold = normal_annual * 0.75
drought_years = annual_precip[annual_precip < drought_threshold]
print(f"Drought years (< 75% of normal precipitation):")
print(drought_years.sort_values())When flags=True, each meteorological parameter includes a corresponding source flag indicating data quality and origin:
# Source flag meanings for monthly data
"A": str # High-quality monthly climate observations
"C": str # Aggregated from high-quality daily observations
"D": str # GHCN-M global historical climatology network monthly data
"E": str # Aggregated from hourly observations
"F": str # ISD aggregated observations
"G": str # SYNOP aggregated observations
"H": str # METAR aggregated aviation reports
"I": str # Model/reanalysis data (ERA5, NCEP, etc.)Monthly values are calculated using appropriate aggregation methods:
# Default aggregation functions
aggregations = {
"tavg": "mean", # Average of daily mean temperatures
"tmin": "mean", # Average of daily minimum temperatures
"tmax": "mean", # Average of daily maximum temperatures
"prcp": "sum", # Total monthly precipitation
"wspd": "mean", # Average wind speed
"pres": "mean", # Average pressure
"tsun": "sum" # Total monthly sunshine hours
}Monthly data is particularly useful for:
# Calculate 30-year climate normals
baseline_data = monthly_data['1981':'2010']
climate_normals = baseline_data.groupby(baseline_data.index.month).mean()# Analyze the annual temperature cycle
monthly_cycle = monthly_data.groupby(monthly_data.index.month)['tavg'].mean()
temperature_range = monthly_cycle.max() - monthly_cycle.min()# Detect long-term trends using linear regression
from scipy import stats
annual_temps = monthly_data.groupby(monthly_data.index.year)['tavg'].mean()
years = annual_temps.index.values
temps = annual_temps.values
slope, intercept, r_value, p_value, std_err = stats.linregress(years, temps)
print(f"Temperature trend: {slope:.3f}°C per year (p={p_value:.4f})")Monthly data objects inherit all time series processing methods:
# Data retrieval and analysis
def fetch(self) -> pd.DataFrame: ...
def count(self) -> int: ...
def coverage(self): ...
# Data processing
def normalize(self): ...
def interpolate(self, limit: int = 3): ...
def aggregate(self, freq: str, spatial: bool = False): ...
def convert(self, units: dict): ...
# Utility methods
def stations(self) -> pd.Index: ...
def clear_cache(self): ...Monthly data quality depends on:
Install with Tessl CLI
npx tessl i tessl/pypi-meteostat