Accessing Arpege Data#
using meteofrance_publicapi
Get your application ID#
See the readme for details.
The following example uses a dotfile to store the secret.
[1]:
import dotenv
import os
dotenv.load_dotenv()
application_id = os.getenv("APPLICATION_ID")
Optional : activate the logs inside the notebook#
[2]:
import logging
logging.basicConfig(level=logging.INFO)
Initialize the client#
[4]:
from meteofrance_publicapi import ArpegeForecast
client = ArpegeForecast(application_id=application_id,
cache_dir="./.cache")
INFO:numexpr.utils:NumExpr defaulting to 8 threads.
Fetch the capabilities#
It is best the first get the capabilities from the API to know what is available.
[6]:
client.get_capabilities()
client.all_coverageid_prefix
[6]:
['U_COMPONENT_OF_WIND__POTENTIAL_VORTICITY_SURFACE_1500',
'MEDIUM_CLOUD_COVER__GROUND_OR_WATER_SURFACE',
'TOTAL_CLOUD_COVER__GROUND_OR_WATER_SURFACE',
'PRESSURE__MEAN_SEA_LEVEL',
'SPECIFIC_CLOUD_ICE_WATER_CONTENT__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'BRIGHTNESS_TEMPERATURE__GROUND_OR_WATER_SURFACE',
'V_COMPONENT_OF_WIND__POTENTIAL_VORTICITY_SURFACE_1500',
'GEOMETRIC_HEIGHT__GROUND_OR_WATER_SURFACE',
'POTENTIAL_VORTICITY__ISOBARIC_SURFACE',
'TOTAL_SNOW_PRECIPITATION__GROUND_OR_WATER_SURFACE',
'WIND_SPEED__ISOBARIC_SURFACE',
'SPECIFIC_CLOUD_ICE_WATER_CONTENT__ISOBARIC_SURFACE',
'DEW_POINT_TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'PRESSURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'U_COMPONENT_OF_WIND_GUST__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'TEMPERATURE__GROUND_OR_WATER_SURFACE',
'SHORT_WAVE_RADIATION_FLUX__GROUND_OR_WATER_SURFACE',
'DOWNWARD_SHORT_WAVE_RADIATION_FLUX__GROUND_OR_WATER_SURFACE',
'MINIMUM_TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'PLANETARY_BOUNDARY_LAYER_HEIGHT__GROUND_OR_WATER_SURFACE',
'WIND_SPEED__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'U_COMPONENT_OF_WIND__POTENTIAL_VORTICITY_SURFACE_2000',
'V_COMPONENT_OF_WIND_GUST__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'V_COMPONENT_OF_WIND__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'MAXIMUM_TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'CONVECTIVE_AVAILABLE_POTENTIAL_ENERGY__GROUND_OR_WATER_SURFACE',
'TOTAL_WATER_PRECIPITATION__GROUND_OR_WATER_SURFACE',
'VERTICAL_VELOCITY_PRESSURE__ISOBARIC_SURFACE',
'U_COMPONENT_OF_WIND__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'V_COMPONENT_OF_WIND__POTENTIAL_VORTICITY_SURFACE_2000',
'LOW_CLOUD_COVER__GROUND_OR_WATER_SURFACE',
'RELATIVE_HUMIDITY__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'RELATIVE_HUMIDITY__ISOBARIC_SURFACE',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'V_COMPONENT_OF_WIND__ISOBARIC_SURFACE',
'TURBULENT_KINETIC_ENERGY__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND',
'PRESSURE__GROUND_OR_WATER_SURFACE',
'TURBULENT_KINETIC_ENERGY__ISOBARIC_SURFACE',
'PSEUDO_ADIABATIC_POTENTIAL_TEMPERATURE__ISOBARIC_SURFACE',
'TEMPERATURE__ISOBARIC_SURFACE',
'TOTAL_PRECIPITATION__GROUND_OR_WATER_SURFACE',
'ABSOLUTE_VORTICITY__ISOBARIC_SURFACE',
'U_COMPONENT_OF_WIND__ISOBARIC_SURFACE',
'GEOPOTENTIAL__ISOBARIC_SURFACE',
'DEW_POINT_TEMPERATURE__ISOBARIC_SURFACE',
'HIGH_CLOUD_COVER__GROUND_OR_WATER_SURFACE',
'WIND_SPEED_GUST__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND']
As you can see from the coverage ID prefixes, quite a lot are available ! Lets use the temperature for this example.
[7]:
coverage_name = "TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND"
coverageids = client.all_coverageid_of_name(coverage_name)
coverageids
[7]:
['TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-21T00.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-21T06.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-21T12.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-21T18.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-22T00.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-22T06.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-22T12.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-22T18.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-23T00.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-23T06.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-23T12.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-23T18.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-24T00.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-24T06.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-24T12.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-24T18.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-25T00.00.00Z',
'TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-25T06.00.00Z']
The coverageids
corresponds to all the forecast computation available for this Temperature field. This example was run on 2024-05-04 at 18:00 UTC.
The computations available goes back in the past up to 2024-04-01 up to the latests run available, today at 12:00 UTC. Let’s use the latests.
[8]:
coverageid = coverageids[-1]
description = client.get_description(coverageid)
Here, description is a dict with a lot of information. For instance, you can get the limits of the domain with the following:
[9]:
description["wcs:CoverageDescriptions"]["wcs:CoverageDescription"]["gml:boundedBy"]
[9]:
{'gml:EnvelopeWithTimePeriod': {'@srsName': 'http://meteofrance.fr/def/crs/3DLongLatHeight',
'@axisLabels': 'long lat height time',
'@uomLabels': 'deg deg m ISO8601',
'@srsDimension': '3',
'gml:lowerCorner': '-32.0 20.0 2',
'gml:upperCorner': '42.0 72.0 3000',
'gml:beginPosition': {'@frame': '#ISO-8601',
'#text': '2024-04-25T06:00:00Z'},
'gml:endPosition': {'@frame': '#ISO-8601', '#text': '2024-04-29T12:00:00Z'}}}
You can see that
longitude spans from -32° et 43°
latitude spans from 20° to 42°
height spans from 2m to 3000m
time goes from 2024-04-25T06:00:00Z to 2024-04-29T12:00:00Z which means 4 days in the future !
This 4D domain can only be accessed by 2D slices.
According to the few tests I did, I seems that only the 2D lat-long can be accessed, which mean one time at a time.
[10]:
temperature_filename = client.get_coverage(
coverageid=coverageid,
height=2,
time=3600, # the value for the time is a bit strange. It is the number of seconds since the start of the forecast.
lat=(20, 72),
long=(-32, 42)
)
temperature_filename
[10]:
WindowsPath('.cache/TEMPERATURE__SPECIFIC_HEIGHT_LEVEL_ABOVE_GROUND___2024-04-25T06.00.00Z/2m_3600Z_20-72_-32-42.tiff')
[11]:
from meteofrance_publicapi.raster import plot_tiff_file
ax = plot_tiff_file(temperature_filename)
ax.set_title(ax.get_title() + "\n 1hour in the future")
[11]:
Text(0.5, 1.0, 'Temperature at 2m above ground \n computed at 2024-04-25T06.00 \n 1hour in the future')
c:\Users\antoi\.conda\envs\dev\Lib\site-packages\cartopy\mpl\style.py:76: UserWarning: facecolor will have no effect as it has been defined as "never".
warnings.warn('facecolor will have no effect as it has been '
[ ]: