While MetPy's docs have an example that uses the declarative interface to plot a canned SPC outlook, here's one that pulls remote data for a given date/time:
from datetime import datetime
import geopandas
from metpy.cbook import get_test_data
from metpy.plots import add_metpy_logo, MapPanel, PanelContainer, PlotGeometry
import numpy as np
import pandas as pd
from shapely.geometry import MultiPoint
# Full date and time; time only affects which convective outlook is pulled
dt = datetime(2022, 12, 14, 20)
# Fetch and parse the outlook geojson
outlook_url = f'https://www.spc.noaa.gov/products/outlook/archive/2022/day1otlk_{dt:%Y%m%d_%H00}_cat.lyr.geojson'
day1_outlook = geopandas.read_file(outlook_url)
# Loop and fetch all the storm reports for that date
url = f'https://www.spc.noaa.gov/climo/reports/{dt:%y%m%d}_rpts_raw_{{kind}}.csv'
reports = [MultiPoint(np.array(pd.read_csv(url.format(kind=kind), skiprows=1)[['LON', 'LAT']]))
for kind in ('torn', 'hail', 'wind')]
# Set up plot using all of the presentation information in the geojson
outlook_plot = PlotGeometry()
outlook_plot.geometry = day1_outlook['geometry']
outlook_plot.fill = day1_outlook['fill']
outlook_plot.stroke = day1_outlook['stroke']
outlook_plot.labels = day1_outlook['LABEL']
outlook_plot.label_fontsize = 'medium'
# Hard-coded visual style to "match" SPC
report_plot = PlotGeometry()
report_plot.geometry = reports
report_plot.fill = ['red', 'green', 'blue']
report_plot.marker = '.'
# Add elements to plot
panel = MapPanel()
panel.title = f'SPC Day 1 Convective Outlook (Valid {dt:%Hz %b %d %Y})'
panel.plots = [outlook_plot, report_plot]
panel.area = [-120, -75, 25, 50]
panel.projection = 'lcc'
panel.layers = ['lakes', 'land', 'ocean', 'states', 'coastline', 'borders']
pc = PanelContainer()
pc.size = (12, 8)
pc.panels = [panel]
add_metpy_logo(pc.figure, 15, 15, size='small')
pc.show()
While MetPy's docs have an example that uses the declarative interface to plot a canned SPC outlook, here's one that pulls remote data for a given date/time: