Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Objective

In this notebook, we will make a surface map based on current observations from METAR sites across North America.

Set the domain to gather data from and for defining the plot region.

The timestamps of many hourly METAR reports are 5-10 minutes prior to the top of the hour, though there are also intra-hourly reports, often around 15-20 and 35-40 minutes past the hour. When we make our DuckDB query, we will specify a beginning and end time, 15 minutes apart.

2026-10-01 04:12:36.951979 2026-10-01 04:27:36.951979

Open the GeoParquet file for the specific year.

Loading...

Perform the spatial subset. Extend the data bounds slightly.

Loading...

Select the weather variables of interest. Also include the site ID, lat, lon, elevation, and time columns.

Index(['station', 'valid', 'longitude', 'latitude', 'tmpf', 'tmpc', 'dwpf', 'dwpc', 'relh', 'drct', 'sknt', 'gust', 'alti', 'mslp', 'vsby', 'p01i', 'p01m', 'state', 'geometry', 'name', 'elevation', 'country', 'county', 'wfo', 'tzname', 'bbox', 'year'], dtype='str')
Loading...

Read in several of the columns as Pandas Series; extract the value arrays from the Series objects; assign / convert units as necessary

The next step deals with the removal of overlapping stations, using reduce_point_density. This returns a mask we can apply to data to filter the points.

Select a Cartopy map projection, which we will use both to reduce plotted station density and to plot the data on a map.

Visualize Surface Observations

Simple station plotting using plot methods

One way to create station plots with MetPy is to create an instance of StationPlot and call various plot methods, like plot_parameter, to plot arrays of data at locations relative to the center point.

In addition to plotting values, StationPlot has support for plotting text strings, symbols, and plotting values using custom formatting.

Now we just plot with arr[mask] for every arr of data we use in plotting.

/home/runner/micromamba/envs/METAR_archive-cookbook/lib/python3.14/site-packages/cartopy/io/__init__.py:263: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_physical/ne_50m_land.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/home/runner/micromamba/envs/METAR_archive-cookbook/lib/python3.14/site-packages/cartopy/io/__init__.py:263: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_physical/ne_50m_lakes.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/home/runner/micromamba/envs/METAR_archive-cookbook/lib/python3.14/site-packages/cartopy/io/__init__.py:263: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_cultural/ne_50m_admin_1_states_provinces_lakes.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
<Figure size 2500x1500 with 1 Axes>

Summary

  • You now know how to create surface maps from a constantly-updating archive of worldwide METAR observations.

Future work

  • Add support for alternative METAR data sources

  • Plot cloud cover and present weather symbols

What’s Next?

  • We will create an interactive visualization of METAR data, using GeoPandas.