Python module for reading/writing GRIB files using ECMWF ECCODES library
—
Limited capabilities for modifying existing GRIB messages and writing them to new files. Supports changing metadata keys and data values, but cannot create GRIB files from scratch.
Change GRIB key values in existing messages.
class gribmessage:
def __setitem__(self, key: str, value):
"""
Set GRIB key values.
Parameters:
- key: str, GRIB key name
- value: appropriate type for the key
Common types: int, float, str, numpy.ndarray (for 'values')
"""
def __setattr__(self, name: str, value):
"""Set GRIB keys as attributes (equivalent to __setitem__)"""Usage example:
grbs = pygrib.open('weather.grb')
grb = grbs.readline()
# Modify forecast time
grb['forecastTime'] = 120
# Or using attribute syntax
grb.forecastTime = 120
# Change parameter (e.g., to pressure tendency)
grb['parameterNumber'] = 2
grb['shortName'] = 'prate' # May change automatically
# Modify level information
grb['level'] = 850
grb['typeOfLevel'] = 'isobaricInhPa'
print(f"Modified message: {grb}")Change the actual meteorological data array in GRIB messages.
class gribmessage:
def __setitem__(self, key: str, value):
"""
For 'values' key, accepts numpy arrays to replace data.
Parameters:
- key: str, must be 'values' for data modification
- value: numpy.ndarray, new data array
Must be compatible with grid dimensions
"""Usage example:
grbs = pygrib.open('weather.grb')
grb = grbs.select(shortName='t', level=500)[0]
# Get original data
original_data = grb['values']
print(f"Original range: {original_data.min():.1f} to {original_data.max():.1f}")
# Apply transformations
# Convert from Kelvin to Celsius
celsius_data = original_data - 273.15
# Apply smoothing filter
from scipy import ndimage
smoothed_data = ndimage.gaussian_filter(original_data, sigma=1.0)
# Scale values
scaled_data = original_data * 1.1
# Set modified data back to message
grb['values'] = celsius_data
print(f"Modified range: {grb['values'].min():.1f} to {grb['values'].max():.1f}")
# Update metadata to reflect change
grb['units'] = 'C'
grb['name'] = 'Temperature (Celsius)'Convert modified messages to binary format and write to files.
class gribmessage:
def tostring(self) -> bytes:
"""
Encode message as binary GRIB string.
Returns:
bytes, binary GRIB message data ready for writing
"""Usage example:
grbs = pygrib.open('input.grb')
grb = grbs.readline()
# Modify the message
grb['forecastTime'] = 168
grb['parameterNumber'] = 11 # Change to different parameter
data = grb['values']
grb['values'] = data * 0.95 # Scale data by 5%
# Convert to binary format
binary_msg = grb.tostring()
# Write to new file
with open('modified.grb', 'wb') as f:
f.write(binary_msg)
# Verify the written file
new_grbs = pygrib.open('modified.grb')
new_grb = new_grbs.readline()
print(f"Written message: {new_grb}")
print(f"Forecast time: {new_grb['forecastTime']}")
new_grbs.close()Modify and write multiple messages to create new GRIB files.
input_grbs = pygrib.open('input.grb')
# Open output file for writing
with open('processed.grb', 'wb') as output_file:
# Process each message
for grb in input_grbs:
# Apply modifications based on parameter type
if grb['shortName'] == 't': # Temperature
# Convert K to C
data = grb['values'] - 273.15
grb['values'] = data
grb['units'] = 'C'
elif grb['shortName'] in ['u', 'v']: # Wind components
# Scale wind speeds
data = grb['values'] * 1.05
grb['values'] = data
# Extend forecast time by 6 hours
grb['forecastTime'] = grb['forecastTime'] + 6
# Write modified message
binary_msg = grb.tostring()
output_file.write(binary_msg)
input_grbs.close()
# Verify processed file
processed_grbs = pygrib.open('processed.grb')
print(f"Processed file contains {len(processed_grbs)} messages")
processed_grbs.close()Reload original message data from file after modifications.
def reload(grb):
"""
Reload gribmessage from file to refresh data.
Creates new message object with original file data.
Parameters:
- grb: gribmessage, message to reload
Returns:
New gribmessage object with original data from file
"""Usage example:
grbs = pygrib.open('weather.grb')
grb = grbs.readline()
# Store original values for comparison
original_forecast_time = grb['forecastTime']
original_data = grb['values'].copy()
# Make modifications
grb['forecastTime'] = 240
grb['values'] = grb['values'] * 2.0
print(f"Modified forecast time: {grb['forecastTime']}")
print(f"Modified data range: {grb['values'].min():.1f} to {grb['values'].max():.1f}")
# Reload original data
original_grb = pygrib.reload(grb)
print(f"Reloaded forecast time: {original_grb['forecastTime']}")
print(f"Reloaded data range: {original_grb['values'].min():.1f} to {original_grb['values'].max():.1f}")pygrib cannot create GRIB files from scratch - it can only modify existing messages.
# NOT SUPPORTED: Creating new GRIB files from scratch
# This will not work:
# new_grb = pygrib.gribmessage() # Cannot instantiate directly
# pygrib.create_grib_file() # No such function
# SUPPORTED: Modify existing messages
grbs = pygrib.open('existing.grb')
grb = grbs.readline()
# ... modify grb ...
binary_data = grb.tostring() # Convert to binary for writingNot all GRIB keys can be modified safely:
grb = grbs.readline()
# Safe modifications (common use cases)
grb['forecastTime'] = 120 # Change forecast hour
grb['level'] = 850 # Change level
grb['values'] = new_data # Replace data array
grb['units'] = 'new_unit' # Change units
# Potentially problematic modifications
# grb['Ni'] = 360 # Don't change grid dimensions
# grb['Nj'] = 181 # without corresponding data changes
# grb['gridType'] = 'lambert' # Don't change grid type
# Always verify modifications work by testing the output
try:
binary_data = grb.tostring()
print("Modification successful")
except Exception as e:
print(f"Modification failed: {e}")When modifying data arrays, ensure compatibility with grid structure:
grb = grbs.select(shortName='t', level=500)[0]
original_data = grb['values']
print(f"Original data shape: {original_data.shape}")
print(f"Grid info: Ni={grb['Ni']}, Nj={grb['Nj']}")
# New data must match grid dimensions
if grb.expand_reduced:
# For expanded grids, data shape should match (Nj, Ni)
expected_shape = (grb['Nj'], grb['Ni'])
else:
# For reduced grids, data is 1D
expected_shape = (grb['numberOfValues'],)
# Create compatible new data
new_data = original_data * 1.1 # Simple scaling preserves shape
grb['values'] = new_data
# Verify compatibility
assert grb['values'].shape == original_data.shapeInstall with Tessl CLI
npx tessl i tessl/pypi-pygrib