Skip to content

Commit 961f413

Browse files
authored
Merge pull request #73 from kgoebber/sat_sfc_example
add sat-surface declare overlay example
2 parents f07061e + 99ad1fb commit 961f413

File tree

1 file changed

+226
-0
lines changed

1 file changed

+226
-0
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Satellite and Surface Obs\n",
8+
"\n",
9+
"By: Kevin Goebbert\n",
10+
"\n",
11+
"Combining both satellite and surface observations is easy with the simplified declarative syntax available in MetPy. This example uses a bit of Siphon to help get current observations and satellite retrievals.\n",
12+
"\n",
13+
"As demonstrated at AMS 2020 Annual Meeting."
14+
]
15+
},
16+
{
17+
"cell_type": "code",
18+
"execution_count": null,
19+
"metadata": {},
20+
"outputs": [],
21+
"source": [
22+
"from datetime import datetime, timedelta\n",
23+
"\n",
24+
"from metpy.io import metar\n",
25+
"from metpy.plots.declarative import *\n",
26+
"from metpy.units import units\n",
27+
"import numpy as np\n",
28+
"from siphon.catalog import TDSCatalog\n",
29+
"import xarray as xr"
30+
]
31+
},
32+
{
33+
"cell_type": "markdown",
34+
"metadata": {},
35+
"source": [
36+
"A nice definition to help get the most recent satellite observations."
37+
]
38+
},
39+
{
40+
"cell_type": "code",
41+
"execution_count": null,
42+
"metadata": {},
43+
"outputs": [],
44+
"source": [
45+
"def get_goes_image(date=datetime.utcnow(), channel=8, region='CONUS'):\n",
46+
" \"\"\"Return dataset of GOES-16 data.\"\"\"\n",
47+
" cat = TDSCatalog('https://thredds.ucar.edu/thredds/catalog/satellite/goes/east/products/'\n",
48+
" 'CloudAndMoistureImagery/{}/Channel{:02d}/{:%Y%m%d}/'\n",
49+
" 'catalog.xml'.format(region, channel, date))\n",
50+
"\n",
51+
" # Get data from about an hour ago.\n",
52+
" if len(list(cat.datasets)) < 10:\n",
53+
" file_num = len(list(cat.datasets))\n",
54+
" else:\n",
55+
" file_num = 10\n",
56+
" ds = cat.datasets[file_num] # Get most recent dataset\n",
57+
" ds = ds.remote_access(use_xarray=True)\n",
58+
" return ds"
59+
]
60+
},
61+
{
62+
"cell_type": "markdown",
63+
"metadata": {},
64+
"source": [
65+
"## Get Satellite data\n",
66+
"\n",
67+
"Use data available on the UCAR THREDDS Data Server to get a recent GOES East IR satellite imagery from Channel 14."
68+
]
69+
},
70+
{
71+
"cell_type": "code",
72+
"execution_count": null,
73+
"metadata": {},
74+
"outputs": [],
75+
"source": [
76+
"# Get IR Satellite data\n",
77+
"ds = get_goes_image(datetime.utcnow(), channel=14)"
78+
]
79+
},
80+
{
81+
"cell_type": "code",
82+
"execution_count": null,
83+
"metadata": {},
84+
"outputs": [],
85+
"source": [
86+
"# Set map time from Satellite Data\n",
87+
"vtime = ds.time.values.astype('datetime64[ms]').astype('O')"
88+
]
89+
},
90+
{
91+
"cell_type": "markdown",
92+
"metadata": {},
93+
"source": [
94+
"## Get METAR Observations\n",
95+
"\n",
96+
"Use available METAR data, also obtained from the UCAR THREDDS Data Server, download and parse using the MetPy METAR parsing functionality."
97+
]
98+
},
99+
{
100+
"cell_type": "code",
101+
"execution_count": null,
102+
"metadata": {},
103+
"outputs": [],
104+
"source": [
105+
"# Get Surface Data from UCAR\n",
106+
"cat = TDSCatalog('https://thredds-test.unidata.ucar.edu/thredds/catalog/noaaport/text/metar/catalog.xml')\n",
107+
"\n",
108+
"time_idx = list(cat.datasets).index(f'metar_{vtime:%Y%m%d}_{vtime:%H}00.txt')\n",
109+
"\n",
110+
"metar_df = cat.datasets[time_idx]\n",
111+
"metar_df.download()\n",
112+
"\n",
113+
"# Parse METAR data with MetPy\n",
114+
"df = metar.parse_metar_file(metar_df.name)"
115+
]
116+
},
117+
{
118+
"cell_type": "markdown",
119+
"metadata": {},
120+
"source": [
121+
"## Convert Variable\n",
122+
"\n",
123+
"Typically we plot surface temperature in the Fahrenheit scale in the U.S., so we are going to use MetPy unit functionarlity to convert the METAR air temperature (which is in Celsuius) to Fahrenheit and add it to the dataFrame. Subset data to be only over CONUS to help with plotting obs on the satellite projection."
124+
]
125+
},
126+
{
127+
"cell_type": "code",
128+
"execution_count": null,
129+
"metadata": {},
130+
"outputs": [],
131+
"source": [
132+
"# Convert temperature to degF and store in dataframe\n",
133+
"df['tmpf'] = (df.air_temperature.values * units(df.units['air_temperature'])).to('degF')\n",
134+
"\n",
135+
"# Subset for data only over CONUS (for plotting ease)\n",
136+
"df = df[(df.latitude.values > 25) & (df.latitude.values < 60)]\n",
137+
"df = df[(df.longitude.values < -60) & (df.longitude.values > -150)]"
138+
]
139+
},
140+
{
141+
"cell_type": "markdown",
142+
"metadata": {},
143+
"source": [
144+
"## Create Plot\n",
145+
"\n",
146+
"Use the declarative syntax from MetPy to plot both the METAR surface temperatures and the GOES EAST IR Satellite Imagery."
147+
]
148+
},
149+
{
150+
"cell_type": "code",
151+
"execution_count": null,
152+
"metadata": {},
153+
"outputs": [],
154+
"source": [
155+
"# Create Plot\n",
156+
"\n",
157+
"# Plot all obs greater than 32F red\n",
158+
"obs = PlotObs()\n",
159+
"obs.data = df[df.tmpf > 32]\n",
160+
"obs.time = vtime\n",
161+
"obs.time_window = timedelta(minutes=30)\n",
162+
"obs.level = None\n",
163+
"obs.fields = ['tmpf']\n",
164+
"obs.colors = ['red']\n",
165+
"obs.reduce_points = 0.7\n",
166+
"\n",
167+
"# Plot all obs less than 32F blue\n",
168+
"obs2 = PlotObs()\n",
169+
"obs2.data = df[df.tmpf <= 32]\n",
170+
"obs2.time = vtime\n",
171+
"obs2.time_window = timedelta(minutes=30)\n",
172+
"obs2.level = None\n",
173+
"obs2.fields = ['tmpf']\n",
174+
"obs2.colors = ['blue']\n",
175+
"obs2.reduce_points = 0.7\n",
176+
"\n",
177+
"# Add the IR image to the plot\n",
178+
"img = ImagePlot()\n",
179+
"img.data = ds\n",
180+
"img.field = 'Sectorized_CMI'\n",
181+
"img.colormap = 'Greys'\n",
182+
"\n",
183+
"# Bring plots together in a map panel and add a title\n",
184+
"panel = MapPanel()\n",
185+
"panel.area = [-112, -65, 20, 50]\n",
186+
"panel.title = f'IR Satellite Data Channel 14 with Surface Temperature (F) at {vtime}'\n",
187+
"panel.layers = ['coastline', 'borders', 'states']\n",
188+
"panel.plots = [img, obs, obs2]\n",
189+
"\n",
190+
"# Place the panel on a figure\n",
191+
"pc = PanelContainer()\n",
192+
"pc.size = (20, 20)\n",
193+
"pc.panels = [panel]\n",
194+
"pc.show()"
195+
]
196+
},
197+
{
198+
"cell_type": "code",
199+
"execution_count": null,
200+
"metadata": {},
201+
"outputs": [],
202+
"source": []
203+
}
204+
],
205+
"metadata": {
206+
"kernelspec": {
207+
"display_name": "Python 3",
208+
"language": "python",
209+
"name": "python3"
210+
},
211+
"language_info": {
212+
"codemirror_mode": {
213+
"name": "ipython",
214+
"version": 3
215+
},
216+
"file_extension": ".py",
217+
"mimetype": "text/x-python",
218+
"name": "python",
219+
"nbconvert_exporter": "python",
220+
"pygments_lexer": "ipython3",
221+
"version": "3.7.3"
222+
}
223+
},
224+
"nbformat": 4,
225+
"nbformat_minor": 4
226+
}

0 commit comments

Comments
 (0)