CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-meteostat

Access and analyze historical weather and climate data with Python.

Pending
Overview
Eval results
Files

climate-normals.mddocs/

Climate Normals

The Normals class provides access to climate normals (30-year averages) that represent typical weather conditions for specific locations and time periods. Climate normals are essential for establishing baseline conditions, detecting climate change, and providing context for current weather events.

Capabilities

Climate Normals Initialization

Create a climate normals dataset for weather stations or geographic points with standard 30-year reference periods.

class Normals:
    def __init__(self, loc: Union[pd.DataFrame, Point, list, str], start: int = None, end: int = None) -> None:
        """
        Initialize climate normals 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: int, optional start year of 30-year period
        - end: int, optional end year of 30-year period (must be start + 29)
        
        Note: If start/end not specified, returns all available normal periods.
        Valid periods must be exactly 30 years and end in year divisible by 10.
        """

Data Normalization

Ensure complete monthly coverage for all stations and reference periods.

def normalize(self):
    """
    Normalize the DataFrame to include all 12 months.
    Fills missing months with NaN values for complete time series.
    
    Returns:
    Normals object with normalized monthly data
    """

Data Retrieval

Fetch climate normals data with computed average temperature.

def fetch(self) -> pd.DataFrame:
    """
    Fetch climate normals DataFrame.
    Automatically computes tavg from tmin and tmax.
    
    Returns:  
    pandas.DataFrame with monthly climate normals
    """

Data Columns

Climate normals include the following monthly average parameters:

# Temperature measurements (°C)
tavg: float       # Average temperature (computed from tmin/tmax)
tmin: float       # Average minimum temperature
tmax: float       # Average maximum temperature

# Precipitation
prcp: float       # Average 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       # Average sunshine duration (hours)

# Index levels (multi-index DataFrame)
month: int        # Month number (1-12)
start: int        # Start year of normal period  
end: int          # End year of normal period
station: str      # Station ID (for multi-station queries)

Usage Examples

Basic Climate Normals

from meteostat import Point, Normals

# Get climate normals for Paris
paris = Point(48.8566, 2.3522, 35)

# Get 1991-2020 climate normals
normals = Normals(paris, 1991, 2020)
climate_data = normals.fetch()

print("Paris climate normals (1991-2020):")
print(climate_data[['tavg', 'tmin', 'tmax', 'prcp']])

Compare Different Normal Periods

from meteostat import Point, Normals
import pandas as pd

# Compare old vs new climate normals for New York
nyc = Point(40.7128, -74.0060, 10)

# Get different 30-year periods
old_normals = Normals(nyc, 1981, 2010).fetch()
new_normals = Normals(nyc, 1991, 2020).fetch()

# Compare temperature changes
temp_comparison = pd.DataFrame({
    '1981-2010': old_normals['tavg'],
    '1991-2020': new_normals['tavg']
})
temp_comparison['Change'] = temp_comparison['1991-2020'] - temp_comparison['1981-2010']

print("Temperature change between normal periods (°C):")
print(temp_comparison)

Regional Climate Normals

from meteostat import Stations, Normals

# Get climate normals for multiple stations in Japan  
japan_stations = Stations().region('JP').inventory('monthly', True).fetch(5)

# Get current climate normals
normals = Normals(japan_stations, 1991, 2020)
japan_climate = normals.fetch()

# Analyze regional temperature patterns
regional_temps = japan_climate.groupby('month')[['tavg', 'tmin', 'tmax']].mean()
print("Regional climate normals for Japan:")
print(regional_temps)

Seasonal Climate Analysis

from meteostat import Point, Normals

# Analyze seasonal climate for Denver, Colorado
denver = Point(39.7392, -104.9903, 1609)

# Get climate normals  
normals = Normals(denver, 1991, 2020)
climate = normals.fetch()

# Define seasons and calculate seasonal averages
climate['season'] = climate.index.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_normals = climate.groupby('season').agg({
    'tavg': 'mean',
    'prcp': 'sum',  # Total seasonal precipitation
    'tsun': 'sum'   # Total seasonal sunshine
})

print("Seasonal climate normals for Denver:")
print(seasonal_normals)

Climate Normal Anomalies

from datetime import datetime
from meteostat import Point, Monthly, Normals

# Calculate current year anomalies vs climate normals
stockholm = Point(59.3293, 18.0686, 28)

# Get climate normals and current year data
normals = Normals(stockholm, 1991, 2020).fetch()
current_year = Monthly(stockholm, datetime(2020, 1, 1), datetime(2020, 12, 31)).fetch()

# Calculate temperature anomalies
monthly_normals = normals.set_index(normals.index.droplevel(['start', 'end']))['tavg']
current_temps = current_year['tavg']

# Align indices for comparison
anomalies = current_temps - monthly_normals

print("2020 Temperature anomalies vs 1991-2020 normals (°C):")  
print(anomalies)

All Available Normal Periods

from meteostat import Point, Normals

# Get all available climate normal periods
location = Point(51.5074, -0.1278)  # London

# Don't specify start/end to get all periods
all_normals = Normals(location)
all_climate = all_normals.fetch()

# See available periods
periods = all_climate.index.get_level_values('end').unique()
print(f"Available normal periods ending in: {sorted(periods)}")

# Compare trends across periods
period_comparison = all_climate.groupby(['end', 'month'])['tavg'].mean().unstack('month')
print("\nTemperature trends across normal periods:")
print(period_comparison)

Standard Reference Periods

Climate normals are calculated for standard 30-year periods:

# Standard WMO reference periods  
current_period = (1991, 2020)    # Current WMO standard
previous_period = (1981, 2010)   # Previous WMO standard  
older_period = (1971, 2000)      # Historical reference

# Period validation rules
valid_period_length = 30          # Must be exactly 30 years
end_year_divisible_by = 10        # End year should end in 0

Data Processing Methods

Climate normals objects inherit standard processing methods:

# Data retrieval
def fetch(self) -> pd.DataFrame: ...
def count(self) -> int: ...

# Data processing  
def convert(self, units: dict): ...

# Utility methods
def clear_cache(self): ...

Multi-Index Structure

Climate normals DataFrames use a multi-level index:

# Index levels for multi-station queries
index_levels = ['station', 'start', 'end', 'month']

# Index levels for single station  
single_station_levels = ['start', 'end', 'month']  

# Index levels when period is specified
period_specified_levels = ['month']

Applications in Climate Science

Climate Change Detection

# Compare different 30-year periods to detect long-term changes
temp_change = new_normals['tavg'] - old_normals['tavg']
significant_change = temp_change[abs(temp_change) > 0.5]  # >0.5°C change

Weather Extremes Assessment

# Determine if current conditions are unusual vs climate normal
current_temp = 25.5  # Current July temperature
july_normal = normals.loc[7, 'tavg']  # July climate normal
anomaly = current_temp - july_normal  # Temperature anomaly

Agricultural Planning

# Use normals for growing season analysis
growing_season = normals[normals['tavg'] > 5]  # Months above 5°C
frost_free_days = len(growing_season)

Energy Demand Modeling

# Calculate heating/cooling degree days from normals
heating_degree_days = (18.3 - normals['tavg']).clip(lower=0).sum()
cooling_degree_days = (normals['tavg'] - 18.3).clip(lower=0).sum()

Install with Tessl CLI

npx tessl i tessl/pypi-meteostat

docs

climate-normals.md

daily-data.md

data-processing.md

geographic-points.md

hourly-data.md

index.md

monthly-data.md

unit-conversions.md

weather-stations.md

tile.json