├── .dask └── config.yaml ├── .gitignore ├── 1-Introduction ├── 1_pyart_reading_and_plotting_data.ipynb ├── 2_Introduction_to_gridding.ipynb └── section_1_answer.py ├── 2-Cloud_Examples ├── 1-NEXRAD_on_Amazon.ipynb └── 2 - Extracting a NEXRAD Column.ipynb ├── Courses ├── AMSPythonVirtual2021.md ├── MidwestStudent2021.md └── mwsc.png ├── LICENSE ├── README.md ├── binder ├── environment.yml └── postBuild ├── scripts ├── provision.sh └── provision_curl.sh └── simple.yml /.dask/config.yaml: -------------------------------------------------------------------------------- 1 | fuse_subgraphs: False 2 | fuse_ave_width: 0 3 | 4 | distributed: 5 | logging: 6 | bokeh: critical 7 | 8 | dashboard: 9 | link: /user/{JUPYTERHUB_USER}/proxy/{port}/status 10 | 11 | admin: 12 | tick: 13 | limit: 5s 14 | 15 | kubernetes: 16 | count: 17 | max: 50 18 | worker-template: 19 | metadata: 20 | spec: 21 | nodeSelector: 22 | dask-worker: True 23 | restartPolicy: Never 24 | containers: 25 | - args: 26 | - dask-worker 27 | - --nthreads 28 | - '2' 29 | - --no-bokeh 30 | - --memory-limit 31 | - 7GB 32 | - --death-timeout 33 | - '60' 34 | image: ${JUPYTER_IMAGE_SPEC} 35 | name: dask-worker 36 | resources: 37 | limits: 38 | cpu: "1.75" 39 | memory: 7G 40 | requests: 41 | cpu: 1 42 | memory: 7G -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /1-Introduction/1_pyart_reading_and_plotting_data.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Pyart 1.0: Reading and Plotting a Radar File" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Let us start we an introductory on what is Py-ART, then after we will begin to code away." 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "The Python ARM Radar Toolkit or Py-ART:\n", 22 | "\n", 23 | " * Py-ART is a Python module for plotting, correcting and analyzing weather radar data.\n", 24 | " * Development began to address the needs of ARM with the acquisition of a number of\n", 25 | " new scanning cloud and precipitation radar as part of the American Recovery Act.\n", 26 | " * The project has since expanded to work with a variety of weather radars and a wider user\n", 27 | " base including radar researchers and climate modelers.\n", 28 | " * The software has been released on GitHub as open source software under a BSD license.\n", 29 | " Runs on Linux, OS X. It also runs on Windows with more limited functionality.\n", 30 | " \n", 31 | "Contributions from others are always welcome." 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "What can Py-ART do?\n", 39 | "Py-ART can be used for a variety of tasks from basic plotting to more complex\n", 40 | "processing pipelines. Specific uses for Py-ART include:\n", 41 | "\n", 42 | " * Reading radar data in a variety of file formats.\n", 43 | " * Creating plots and visualization of radar data.\n", 44 | " * Correcting radar moments while in antenna coordinates, such as:\n", 45 | " * Doppler unfolding/de-aliasing.\n", 46 | " * Attenuation correction.\n", 47 | " * Phase processing using a Linear Programming method.\n", 48 | " * Mapping data from one or multiple radars onto a Cartesian grid.\n", 49 | " * Performing retrievals.\n", 50 | " * Writing radial and Cartesian data to NetCDF files." 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "Py-ART essentials links:\n", 58 | " * Landing page, [arm-doe.github.io/pyart/](http://arm-doe.github.io/pyart/)\n", 59 | " * Documentation, [arm-doe.github.io/pyart-docs-travis/](http://arm-doe.github.io/pyart-docs-travis/)\n", 60 | " * Examples, [arm-doe.github.io/pyart/dev/auto_examples/index.html](http://arm-doe.github.io/pyart/dev/auto_examples/index.html)\n", 61 | " * Source Code, [github.com/ARM-DOE/pyart](https://github.com/ARM-DOE/pyart)\n", 62 | " * Mailing list, [groups.google.com/group/pyart-users/](http://groups.google.com/group/pyart-users/)\n", 63 | " * Issue Tracker, [github.com/ARM-DOE/pyart/issues](https://github.com/ARM-DOE/pyart/issues)" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "Now that we know what Py-ART is, let us began coding." 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "First we want to import any modules that will be needed." 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "import cartopy.crs as ccrs\n", 87 | "import matplotlib.pyplot as plt\n", 88 | "import numpy as np\n", 89 | "import pyart\n", 90 | "import os" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "#WARNING: Ignoring warningings makes a pretty notebook but can lead to trouble\n", 100 | "import warnings\n", 101 | "warnings.filterwarnings('ignore')" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "When reading in a radar file, we use the pyart.io.read module.\n", 109 | "pyart.io.read can read a variety of different radar formats, such as Cf/Radial, LASSEN, and more. \n", 110 | "The documentation on what formats can be read by Py-ART can be found here:\n", 111 | "\n", 112 | "http://arm-doe.github.io/pyart-docs-travis/user_reference/io.html\n", 113 | "\n", 114 | "For most file formats listed on the page, using pyart.io.read should suffice since Py-ART has the ability to automatically detect the file format." 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "To read a radar file, first we need to download a file from ARM. We will use the Atmospheric Community Toolkit to interface with the ARM Live interface.\n", 122 | "First lets define the username and token, we will use a group one for this course, please visit https://adc.arm.gov/armlive/ to get your very own!: " 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "\n", 132 | "radar = pyart.io.read(os.path.expanduser('~/data/arm/csapr_test_case.nc'), \n", 133 | " delay_field_loading = True)\n" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": null, 139 | "metadata": {}, 140 | "outputs": [], 141 | "source": [ 142 | "pyart.io.read?" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "When reading a radar file, there are a few options to add, such as excluding radar fields. Excluding fields becomes useful when you are loading many radar files at a time and want to conserve memory and save time." 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "To see the full list of parameters, in a Jupyter Notebook, simply add a question mark after the function." 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "In the radar object are fields. This is where data such as reflectivity and velocity are stored.\n", 164 | "To see what fields are present we can add the fields and keys additions to the variable where the\n", 165 | "radar object is stored." 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": null, 171 | "metadata": {}, 172 | "outputs": [], 173 | "source": [ 174 | "radar.fields.keys()" 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "metadata": {}, 180 | "source": [ 181 | "The fields are stored in a dictionary, each containing coordinates, units and more.\n", 182 | "All can be accessed by just adding the fields addition to the radar object variable.\n", 183 | "For an individual field, we add a string in brackets after the fields addition to see\n", 184 | "the contents of that field." 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": null, 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "print(radar.fields)" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "print(radar.fields['reflectivity'])" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "We can go even further in the dictionary and a see within the reflectivity field by accessing the units or data itself.\n", 210 | "For example add the string data in brackets after the reflectivity string bracket." 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": null, 216 | "metadata": {}, 217 | "outputs": [], 218 | "source": [ 219 | "print(radar.fields['reflectivity']['data'])" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": null, 225 | "metadata": {}, 226 | "outputs": [], 227 | "source": [ 228 | "print(radar.fields['reflectivity']['data'][300, 2])" 229 | ] 230 | }, 231 | { 232 | "cell_type": "markdown", 233 | "metadata": {}, 234 | "source": [ 235 | "Finally, for a more condensed view of the radar object, just use radar.info()." 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": null, 241 | "metadata": {}, 242 | "outputs": [], 243 | "source": [ 244 | "# This will read the whole radar object so lets leave it for at home\n", 245 | "# radar.info()" 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "metadata": {}, 251 | "source": [ 252 | "Now that we have loaded the data and inspected it, the next logical thing to do is to visualize the data! Py-ART's visualiation functionality is done through the objects in the pyart.graph module: \n", 253 | "\n", 254 | "http://arm-doe.github.io/pyart-docs-travis/user_reference/graph.html\n", 255 | "\n", 256 | "In Py-ART there are 5 visualization classes in pyart.graph:\n", 257 | "\n", 258 | "* RadarDisplay\t \n", 259 | "* RadarMapDisplay\t \n", 260 | "* AirborneRadarDisplay\t \n", 261 | "\n", 262 | "Plotting grid data\n", 263 | "* GridMapDisplay\n", 264 | "\n", 265 | "For the examples in this tutorial, we will be using RadarMapDisplay. For this example, we are going to use Cartopy to plot our data. " 266 | ] 267 | }, 268 | { 269 | "cell_type": "markdown", 270 | "metadata": {}, 271 | "source": [ 272 | "To display a radar image using Cartopy, we create a figure first and then create a RadarMapDisplayCartopy object from the radar. The following example displays the reflectivity from the radar." 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": null, 278 | "metadata": {}, 279 | "outputs": [], 280 | "source": [ 281 | "fig = plt.figure(figsize=[12, 12])\n", 282 | "display = pyart.graph.RadarMapDisplay(radar)\n", 283 | "display.plot_ppi_map('reflectivity', sweep=3, resolution='50m',\n", 284 | " vmin=-8, vmax=60,\n", 285 | " projection=ccrs.PlateCarree())\n", 286 | "plt.show()" 287 | ] 288 | }, 289 | { 290 | "cell_type": "markdown", 291 | "metadata": {}, 292 | "source": [ 293 | "You can change many parameters in the graph by changing the arguments to plot_ppi_map. As you can recall from earlier. simply view these arguments in a Jupyter notebook by typing:" 294 | ] 295 | }, 296 | { 297 | "cell_type": "code", 298 | "execution_count": null, 299 | "metadata": {}, 300 | "outputs": [], 301 | "source": [ 302 | "display.plot_ppi_map?" 303 | ] 304 | }, 305 | { 306 | "cell_type": "markdown", 307 | "metadata": {}, 308 | "source": [ 309 | "For example, let's change the colormap to something different" 310 | ] 311 | }, 312 | { 313 | "cell_type": "code", 314 | "execution_count": null, 315 | "metadata": {}, 316 | "outputs": [], 317 | "source": [ 318 | "fig = plt.figure(figsize=[12, 12])\n", 319 | "display = pyart.graph.RadarMapDisplay(radar)\n", 320 | "display.plot_ppi_map('reflectivity', sweep=2, resolution='50m',\n", 321 | " vmin=-8, vmax=64,\n", 322 | " projection=ccrs.PlateCarree(), cmap='pyart_Gray9')\n", 323 | "plt.show()" 324 | ] 325 | }, 326 | { 327 | "cell_type": "markdown", 328 | "metadata": {}, 329 | "source": [ 330 | "Or, let's view a different elevation scan! To do this, change the sweep parameter in the plot_ppi_map function." 331 | ] 332 | }, 333 | { 334 | "cell_type": "code", 335 | "execution_count": null, 336 | "metadata": {}, 337 | "outputs": [], 338 | "source": [ 339 | "fig = plt.figure(figsize=[12, 8])\n", 340 | "display = pyart.graph.RadarMapDisplay(radar)\n", 341 | "display.plot_ppi_map('differential_reflectivity', sweep=2, resolution='50m',\n", 342 | " vmin=-1, vmax=6,\n", 343 | " projection=ccrs.PlateCarree())\n", 344 | "plt.show()" 345 | ] 346 | }, 347 | { 348 | "cell_type": "markdown", 349 | "metadata": {}, 350 | "source": [ 351 | "Or, display radial velocity instead of reflectivity." 352 | ] 353 | }, 354 | { 355 | "cell_type": "code", 356 | "execution_count": null, 357 | "metadata": {}, 358 | "outputs": [], 359 | "source": [ 360 | "nyq = radar.instrument_parameters['nyquist_velocity']['data'][0]\n", 361 | "\n", 362 | "fig = plt.figure(figsize=[12, 8])\n", 363 | "display = pyart.graph.RadarMapDisplay(radar)\n", 364 | "display.plot_ppi_map('velocity', sweep=2, resolution='50m',\n", 365 | " vmin=-nyq, vmax=nyq,\n", 366 | " projection=ccrs.PlateCarree(), cmap='coolwarm')\n", 367 | "plt.show()" 368 | ] 369 | }, 370 | { 371 | "cell_type": "markdown", 372 | "metadata": {}, 373 | "source": [ 374 | "## Lets make it pretty!" 375 | ] 376 | }, 377 | { 378 | "cell_type": "code", 379 | "execution_count": null, 380 | "metadata": {}, 381 | "outputs": [], 382 | "source": [] 383 | }, 384 | { 385 | "cell_type": "markdown", 386 | "metadata": {}, 387 | "source": [ 388 | "## Exercise\n", 389 | "\n", 390 | "Now that the basics of loading and processing Cf/Radial files has been introduced, let's go ahead use what we have learned to load and plot the file nsaxsaprppiC1.a1.20140201.184802.nc located in the data directory. Recommend using radar.fields.keys() to check the name of the fields for plotting. Play around with changing factors such as the field plotted, color scale, color maps, axes limits to get a feel for how to visualize radar data with Py-ART." 391 | ] 392 | }, 393 | { 394 | "cell_type": "code", 395 | "execution_count": null, 396 | "metadata": {}, 397 | "outputs": [], 398 | "source": [] 399 | }, 400 | { 401 | "cell_type": "markdown", 402 | "metadata": {}, 403 | "source": [ 404 | "Press shift-Enter in the below cell for a possible answer. There are many ways to visualize data using Py-ART, so the answer here is not necessarily the only one!" 405 | ] 406 | }, 407 | { 408 | "cell_type": "code", 409 | "execution_count": null, 410 | "metadata": { 411 | "scrolled": true 412 | }, 413 | "outputs": [], 414 | "source": [ 415 | "# %load section_1_answer.py\n", 416 | "radar = pyart.io.read('./data/nsaxsaprppiC1.a1.20140201.184802.nc')\n", 417 | "display = pyart.graph.RadarMapDisplay(radar)\n", 418 | "display.plot_ppi_map('reflectivity_horizontal', sweep=0, vmin=-10, vmax=60,\n", 419 | " resolution='10m')\n" 420 | ] 421 | }, 422 | { 423 | "cell_type": "code", 424 | "execution_count": null, 425 | "metadata": {}, 426 | "outputs": [], 427 | "source": [] 428 | } 429 | ], 430 | "metadata": { 431 | "kernelspec": { 432 | "display_name": "Python 3", 433 | "language": "python", 434 | "name": "python3" 435 | }, 436 | "language_info": { 437 | "codemirror_mode": { 438 | "name": "ipython", 439 | "version": 3 440 | }, 441 | "file_extension": ".py", 442 | "mimetype": "text/x-python", 443 | "name": "python", 444 | "nbconvert_exporter": "python", 445 | "pygments_lexer": "ipython3", 446 | "version": "3.7.10" 447 | } 448 | }, 449 | "nbformat": 4, 450 | "nbformat_minor": 2 451 | } 452 | -------------------------------------------------------------------------------- /1-Introduction/2_Introduction_to_gridding.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "large-filter", 6 | "metadata": {}, 7 | "source": [ 8 | "# Introduction to gridding and working with grids\n", 9 | "A common activity for working with scanning radar data is the estimation of the radar measuremets (and retrievals) on a regularly spaced grid. This could be for GIS purposes, the compraring to other data sources or for comparisons to model outputs. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "id": "color-timber", 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "import cartopy.crs as ccrs\n", 20 | "import matplotlib.pyplot as plt\n", 21 | "import numpy as np\n", 22 | "import pyart\n", 23 | "import os\n", 24 | "import cartopy.crs as ccrs\n", 25 | "import cartopy.feature as cfeature\n", 26 | "\n", 27 | "\n", 28 | "import matplotlib.ticker as mticker\n", 29 | "\n" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "id": "varying-principal", 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "#Lets read in our data set\n", 40 | "radar = pyart.io.read(os.path.expanduser('~/data/arm/csapr_test_case.nc'), \n", 41 | " delay_field_loading = True)\n" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "id": "treated-salon", 47 | "metadata": {}, 48 | "source": [ 49 | "## Lets get some basic geometry about our radar data" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "id": "lined-closing", 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "max_lat = radar.gate_latitude['data'].max()\n", 60 | "min_lat = radar.gate_latitude['data'].min()\n", 61 | "max_lon = radar.gate_longitude['data'].max()\n", 62 | "min_lon = radar.gate_longitude['data'].min()\n", 63 | "print(max_lat, min_lat, max_lon, min_lon)\n", 64 | "\n", 65 | "height = radar.gate_altitude\n", 66 | "lats = radar.gate_latitude\n", 67 | "lons = radar.gate_longitude\n", 68 | "lat_lines = np.arange(min_lat, max_lat, .5)\n", 69 | "lon_lines = np.arange(min_lon, max_lon, .5)\n" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "id": "fitting-lease", 75 | "metadata": {}, 76 | "source": [ 77 | "## Lets take a look at all the bells and whistles on Py-ART's Gridder" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "id": "hazardous-panama", 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [ 87 | "pyart.map.map_gates_to_grid?" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": null, 93 | "id": "arctic-relief", 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "id": "crude-catalog", 101 | "metadata": {}, 102 | "source": [ 103 | "## Lets make a regular grid \n", 104 | "31 vertical levels, 301 by 301 horizontal points. 0 to 15km in height, and -120 to 120km in x and y. " 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "id": "current-cowboy", 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "grids = pyart.map.grid_from_radars(radar,(31,301,301),\n", 115 | " ((0.,15000.),(-120000.,120000.),(-120000.,120000.)),\n", 116 | " refl_field='reflectivity', weighting_function='Barnes2')" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "id": "formed-project", 122 | "metadata": {}, 123 | "source": [ 124 | "# So what did we get???" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "id": "injured-pharmacology", 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "grids?" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "id": "listed-poker", 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "grids.fields.keys()" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "id": "consecutive-hundred", 150 | "metadata": {}, 151 | "source": [ 152 | "## Why your own grid object? What about xarray?\n", 153 | "When Py-ART was being developed xarray was very new.. but fear not! We have a simple method for converting" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": null, 159 | "id": "elementary-michigan", 160 | "metadata": {}, 161 | "outputs": [], 162 | "source": [ 163 | "grids.to_xarray?" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": null, 169 | "id": "intelligent-retail", 170 | "metadata": {}, 171 | "outputs": [], 172 | "source": [ 173 | "xgrids = grids.to_xarray()\n" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": null, 179 | "id": "discrete-business", 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "xgrids" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "id": "objective-gallery", 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "xgrids.reflectivity.mean()" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "id": "parliamentary-plumbing", 200 | "metadata": {}, 201 | "outputs": [], 202 | "source": [ 203 | "xgrids.reflectivity.sel(z=500, time=xgrids.time[0])" 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": null, 209 | "id": "smoking-victorian", 210 | "metadata": {}, 211 | "outputs": [], 212 | "source": [ 213 | "xgrids.reflectivity.sel(z=500, time=xgrids.time[0]).plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow, vmin=-6, vmax=64)" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": null, 219 | "id": "sensitive-cheese", 220 | "metadata": { 221 | "scrolled": true 222 | }, 223 | "outputs": [], 224 | "source": [ 225 | "fig = plt.figure(figsize=[15, 7])\n", 226 | "ax = plt.axes(projection=ccrs.LambertConformal())\n", 227 | "pc = xgrids.reflectivity.sel(z=3000, \n", 228 | " time=xgrids.time[0]).plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow, \n", 229 | " vmin=-6, vmax=64)\n", 230 | "gl = ax.gridlines(draw_labels=True,\n", 231 | " linewidth=2, color='gray', alpha=0.5, linestyle='--')" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": null, 237 | "id": "olive-lancaster", 238 | "metadata": {}, 239 | "outputs": [], 240 | "source": [ 241 | "fig = plt.figure(figsize=[15, 7])\n", 242 | "pc = xgrids.reflectivity.sel(x=0, time=xgrids.time[0]).plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow,\n", 243 | " vmin=-6, vmax=64)\n", 244 | "\n" 245 | ] 246 | }, 247 | { 248 | "cell_type": "code", 249 | "execution_count": null, 250 | "id": "casual-creek", 251 | "metadata": {}, 252 | "outputs": [], 253 | "source": [ 254 | "# A little trick with much thanks to Ryan Abernathy\n", 255 | "\n", 256 | "lalogrids = xgrids.swap_dims({\"x\": \"lon\"})\n", 257 | "lalogrids = lalogrids.swap_dims({\"y\": \"lat\"})\n" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": null, 263 | "id": "sealed-american", 264 | "metadata": {}, 265 | "outputs": [], 266 | "source": [ 267 | "#lets make sure we get our projection right!\n", 268 | "\n", 269 | "print(grids.projection)\n", 270 | "lon_0 = grids.get_projparams()['lon_0']\n", 271 | "lat_0 = grids.get_projparams()['lat_0']\n", 272 | "proj = ccrs.AzimuthalEquidistant(central_latitude=lat_0, central_longitude=lon_0)\n", 273 | "\n", 274 | "\n", 275 | "fig = plt.figure(figsize=[15, 7])\n", 276 | "display = pyart.graph.GridMapDisplay(grids)\n", 277 | "\n", 278 | "# panel sizes\n", 279 | "map_panel_axes = [0.05, 0.05, .4, .80]\n", 280 | "x_cut_panel_axes = [0.55, 0.10, .4, .25]\n", 281 | "y_cut_panel_axes = [0.55, 0.50, .4, .25]\n", 282 | "\n", 283 | "# panel 1\n", 284 | "ax1 = fig.add_axes(map_panel_axes, projection=proj)\n", 285 | "\n", 286 | "\n", 287 | "pc = xgrids.reflectivity.sel(z=3000, \n", 288 | " time=xgrids.time[0]).plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow, \n", 289 | " vmin=-6, vmax=64, ax = ax1)\n", 290 | "gl = ax1.gridlines(draw_labels=True,\n", 291 | " linewidth=2, color='gray', alpha=0.5, linestyle='--')\n", 292 | "\n", 293 | "ax1.add_feature(cfeature.RIVERS)\n", 294 | "ax1.add_feature(cfeature.STATES)\n", 295 | "\n", 296 | "\n", 297 | "#ax.add_feature(cartopy.feature.NaturalEarthFeature('cultural', 'roads', '10m'))\n", 298 | "roads = cfeature.NaturalEarthFeature(\n", 299 | " category='cultural',\n", 300 | " name='roads',\n", 301 | " scale='10m',\n", 302 | " facecolor='none',\n", 303 | " edgecolor='black',\n", 304 | " alpha=0.5)\n", 305 | "\n", 306 | "ax1.add_feature(roads)\n", 307 | "\n", 308 | "ax1.add_feature(cfeature.LAKES, zorder=0)\n", 309 | "\n", 310 | "\n", 311 | "# panel 2, along longitude slice.\n", 312 | "ax2 = fig.add_axes(x_cut_panel_axes)\n", 313 | "\n", 314 | "pc = lalogrids.reflectivity.sel(lat=36.9, time=xgrids.time[0],method=\"nearest\").plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow,\n", 315 | " vmin=-6, vmax=64, ax=ax2)\n", 316 | "\n", 317 | "ax2.set_ylim([0,15000])\n", 318 | "#ax2.set_xlim([-120000,120000])\n", 319 | "ax2.set_xlabel('Distance from SGP CF (km)')\n", 320 | "\n", 321 | "# panel 3, along latitude slice\n", 322 | "ax3 = fig.add_axes(y_cut_panel_axes)\n", 323 | "\n", 324 | "pc = lalogrids.reflectivity.sel(lon=-97.45, time=xgrids.time[0],method=\"nearest\").plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow,\n", 325 | " vmin=-6, vmax=64, ax=ax3)\n", 326 | "\n", 327 | "ax3.set_ylim([0,15000])\n", 328 | "#ax3.set_xlim([-120000,120000])\n", 329 | "ax3.set_xlabel('Distance from SGP CF (km)')\n" 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": null, 335 | "id": "historical-plasma", 336 | "metadata": {}, 337 | "outputs": [], 338 | "source": [] 339 | } 340 | ], 341 | "metadata": { 342 | "kernelspec": { 343 | "display_name": "Python 3", 344 | "language": "python", 345 | "name": "python3" 346 | }, 347 | "language_info": { 348 | "codemirror_mode": { 349 | "name": "ipython", 350 | "version": 3 351 | }, 352 | "file_extension": ".py", 353 | "mimetype": "text/x-python", 354 | "name": "python", 355 | "nbconvert_exporter": "python", 356 | "pygments_lexer": "ipython3", 357 | "version": "3.7.10" 358 | } 359 | }, 360 | "nbformat": 4, 361 | "nbformat_minor": 5 362 | } 363 | -------------------------------------------------------------------------------- /1-Introduction/section_1_answer.py: -------------------------------------------------------------------------------- 1 | radar = pyart.io.read('./data/nsaxsaprppiC1.a1.20140201.184802.nc') 2 | display = pyart.graph.RadarMapDisplay(radar) 3 | display.plot_ppi_map('reflectivity_horizontal', sweep=0, vmin=-10, vmax=60, 4 | resolution='10m') 5 | -------------------------------------------------------------------------------- /2-Cloud_Examples/1-NEXRAD_on_Amazon.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Remotely fetching NEXRAD data, gridding and intergration with MetPy and Siphon\n", 8 | "\n", 9 | "This notebook highlights the power of having NEXRAD on Amazon Web Services Simple Storage Service (S3). We use a tool, which is pip installable, called nexradaws. We show how it works to download and use tempfile for easy access. How to build a simple (with issues) function. We also showcase Py-ART's multi-radar gridding capabilities. Finally we show how Py-ART and MetPy + Siphon can be used to make nice mosiacs with metars. **Note: the MetPy portion only works for cases less than a month old. Will need to be updated when this component is taught**.\n" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "import nexradaws\n", 19 | "import tempfile\n", 20 | "import os\n", 21 | "import shutil\n", 22 | "import pyart\n", 23 | "from datetime import datetime, timedelta\n", 24 | "from matplotlib import pyplot as plt\n", 25 | "\n", 26 | "import cartopy.crs as ccrs\n", 27 | "import cartopy.feature as cfeature\n", 28 | "\n", 29 | "import metpy.calc as mpcalc\n", 30 | "import metpy.plots as mpplots\n", 31 | "\n", 32 | "import numpy as np\n", 33 | "\n", 34 | "from matplotlib.patheffects import withStroke\n", 35 | "from metpy.io import parse_metar_file\n", 36 | "from metpy.units import pandas_dataframe_to_unit_arrays\n", 37 | "\n", 38 | "# Here is where we import the TDSCatalog class from siphon for obtaining our data \n", 39 | "from siphon.catalog import TDSCatalog\n", 40 | "\n", 41 | "import pytz" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "# Create a tempory file, connect nexrad aws and request a list of files from the \n", 51 | "#Chicago NEXRAD for the 10th of August last year\n", 52 | "\n", 53 | "templocation = tempfile.mkdtemp()\n", 54 | "conn = nexradaws.NexradAwsInterface()\n", 55 | "scans = conn.get_avail_scans(2020, 8, 10,'KLOT')" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "#Download 5 files\n", 65 | "\n", 66 | "lcn = templocation\n", 67 | "localfiles = conn.download(scans[350:355],lcn)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "#Load one of the files\n", 77 | "\n", 78 | "radar = pyart.io.read(localfiles.success[1].filepath)\n" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": null, 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [ 87 | "#Visualize. Set the projection first this time so we have some\n", 88 | "#hand axes. Add the lakes at the bottom of the plot\n", 89 | "\n", 90 | "myf = plt.figure(figsize=[10,10])\n", 91 | "ax = plt.axes(projection=ccrs.PlateCarree())\n", 92 | "myd = pyart.graph.RadarMapDisplay(radar)\n", 93 | "ax.add_feature(cfeature.LAKES, zorder=0)\n", 94 | "\n", 95 | "myd.plot_ppi_map('reflectivity', 0, vmin=-8, vmax=64)\n" 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "## So this is cool.. How do we roll a custom function?" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "#Lets start by interrogating the scan object\n", 112 | "\n", 113 | "a=scans[-1]\n", 114 | "a.scan_time" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "## An Aside, when it comes to coding...\n", 122 | "And you want to do something, like, say, finding the cloest time to a given date.. **GOOGLE IT AND CLICK THE FIRST STACK OVERFLOW LINK**. Coding from scratch is very rare.. Most coding is by addition of subtraction to existing code (like this cookbook!)." 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "#https://stackoverflow.com/questions/32237862/find-the-closest-date-to-a-given-date/32237949\n", 132 | "def nearest(items, pivot):\n", 133 | " return min(items, key=lambda x: abs(x - pivot))" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": null, 139 | "metadata": {}, 140 | "outputs": [], 141 | "source": [ 142 | "# Now, by trail and error I found that some scan[i].times are none.. so lets control for that\n", 143 | "\n", 144 | "times = [scan.scan_time for scan in scans] # <--- Python generator... these can get you in trouble\n", 145 | "\n", 146 | "#Need to clean\n", 147 | "good_scans = []\n", 148 | "good_times = []\n", 149 | "for i in range(len(scans)):\n", 150 | " if times[i] is not None:\n", 151 | " good_times.append(times[i])\n", 152 | " good_scans.append(scans[i])\n", 153 | " \n", 154 | "nearest_time = nearest(good_times, datetime(2020,8,10,20,6,55,0, pytz.UTC)) # <---- nexradaws times are TZ aware \n", 155 | "\n", 156 | "\n", 157 | "index = times.index(nearest_time)" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "#Lets see if this worked\n", 167 | "print(index)" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": {}, 173 | "source": [ 174 | "## Woot! It works! Now lets wrap it into a function" 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "# This is a VERY LAZY function. \n", 184 | "#No testing and if it gets a file Py-ART can not read it will fail, ungracefully\n", 185 | "\n", 186 | "def get_my_radar(connex, site, this_datetime):\n", 187 | " tlocation = tempfile.mkdtemp()\n", 188 | " these_scans = connex.get_avail_scans(this_datetime.year,this_datetime.month, this_datetime.day, site)\n", 189 | " these_times = [scan.scan_time for scan in these_scans]\n", 190 | " targ = this_datetime\n", 191 | " \n", 192 | " #Need to clean\n", 193 | " these_good_scans = []\n", 194 | " these_good_times = []\n", 195 | " for i in range(len(these_scans)):\n", 196 | " if these_times[i] is not None:\n", 197 | " these_good_times.append(these_times[i])\n", 198 | " these_good_scans.append(these_scans[i])\n", 199 | " \n", 200 | " print(len(these_good_scans), len(these_good_times))\n", 201 | "\n", 202 | " this_nearest_time = nearest(these_good_times, targ)\n", 203 | " this_index = these_good_times.index(this_nearest_time)\n", 204 | " lcn = templocation\n", 205 | " localfiles = conn.download(these_good_scans[this_index],lcn)\n", 206 | " return pyart.io.read(localfiles.success[0].filepath)" 207 | ] 208 | }, 209 | { 210 | "cell_type": "markdown", 211 | "metadata": {}, 212 | "source": [ 213 | "## Lets take this baby for a spin! \n", 214 | "Here are some dates (both timezone aware and naive) and radars when \"stuff\" happened." 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": null, 220 | "metadata": {}, 221 | "outputs": [], 222 | "source": [ 223 | "\n", 224 | "#Recent Chicago Snowstorm\n", 225 | "snow_time_n = datetime(2021, 2, 15, 20, 6, 55, 0) # <-- We first make Naive. The need for this will become apparent\n", 226 | "snow_time = snow_time_n.replace(tzinfo=pytz.UTC)\n", 227 | "snow_radar = \"KLOT\"\n", 228 | "\n", 229 | "#May 20th ARM MC3E case \n", 230 | "boom_time_n = datetime(2011, 5, 20, 11, 6, 55, 0)\n", 231 | "boom_time = boom_time_n.replace(tzinfo=pytz.UTC)\n", 232 | "snow_radar = \"KVNX\"\n", 233 | "\n", 234 | "#Irma\n", 235 | "hurricane_time_n = datetime(2017, 9, 6, 21, 48, 0)\n", 236 | "hurricane_time = hurricane_time_n.replace(tzinfo=pytz.UTC)\n", 237 | "hurricane_radar = \"TJUA\"\n", 238 | "\n", 239 | "#Midwest Derecho\n", 240 | "der_time_n = datetime(2020, 8, 10, 20, 48, 0)\n", 241 | "der_time = der_time_n.replace(tzinfo=pytz.UTC)\n", 242 | "der_radar = 'KLOT'\n", 243 | "\n", 244 | "#Specific example used for later, must be t-30 days\n", 245 | "#Change before giving live course\n", 246 | "recent_time_n = datetime(2021, 9, 7, 20, 8, 0)\n", 247 | "recent_time = recent_time_n.replace(tzinfo=pytz.UTC)\n", 248 | "recent_radar = 'KLOT'\n", 249 | "\n", 250 | "\n", 251 | "\n", 252 | "\n", 253 | "radar = get_my_radar(conn, recent_radar, recent_time)\n" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": null, 259 | "metadata": {}, 260 | "outputs": [], 261 | "source": [ 262 | "myf = plt.figure(figsize=[10,10])\n", 263 | "\n", 264 | "map_panel_axes = [0.05, 0.05, .8, .8]\n", 265 | "ax = myf.add_axes(map_panel_axes, projection=ccrs.PlateCarree())\n", 266 | "\n", 267 | "myd = pyart.graph.RadarMapDisplay(radar)\n", 268 | "myd.plot_ppi_map('reflectivity', 0, vmin=-8, vmax=64, ax=ax, embelish=False, colorbar_flag=False)\n", 269 | "\n", 270 | "cbar = plt.colorbar(mappable=myd.plots[0], fraction=.1, shrink=.8, label='NEXRAD Z$_e$ (dBZ)')\n", 271 | "\n", 272 | "gl = ax.gridlines(draw_labels=True,\n", 273 | " linewidth=2, color='gray', alpha=0.5, linestyle='--')\n", 274 | "\n", 275 | "gl.ylabels_right = False\n", 276 | "ax.add_feature(cfeature.COASTLINE)\n", 277 | "ax.add_feature(cfeature.STATES)\n", 278 | "ax.add_feature(cfeature.LAKES, zorder=0)\n" 279 | ] 280 | }, 281 | { 282 | "cell_type": "markdown", 283 | "metadata": {}, 284 | "source": [ 285 | "## Exercise: Fetch a high impact weather event\n", 286 | "Can you think of an interesting case near a NEXRAD?\n", 287 | "[![Foo](https://www.roc.noaa.gov/WSR88D/Images/CONUSLayoutNspgsW_TJUA.png)](https://www.roc.noaa.gov/WSR88D/Maps.aspx)\n" 288 | ] 289 | }, 290 | { 291 | "cell_type": "code", 292 | "execution_count": null, 293 | "metadata": {}, 294 | "outputs": [], 295 | "source": [ 296 | "#Enter your code here" 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "metadata": {}, 302 | "source": [ 303 | "## So back to gridding\n", 304 | "This code has been tweaked to run with 8GB memory. **This will only work on the Pangeo binder**." 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": null, 310 | "metadata": {}, 311 | "outputs": [], 312 | "source": [ 313 | "#Lets conserve some memory\n", 314 | "del(radar) #<--- The del command is handy!\n", 315 | "\n", 316 | "metpy_time = recent_time\n", 317 | "metpy_time_n = recent_time_n\n", 318 | "\n", 319 | "# https://www.spc.noaa.gov/climo/reports/210215_rpts.html\n", 320 | "\n", 321 | "KLOT = get_my_radar(conn, 'KLOT', metpy_time)\n", 322 | "KIWX = get_my_radar(conn, 'KIWX', metpy_time)\n", 323 | "KILX = get_my_radar(conn, 'KILX', metpy_time)" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": null, 329 | "metadata": {}, 330 | "outputs": [], 331 | "source": [ 332 | "KLOT.fields.keys()" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": null, 338 | "metadata": {}, 339 | "outputs": [], 340 | "source": [ 341 | "#more memory conserving, lets remove a bunch of radar moments. \n", 342 | "\n", 343 | "for key in ['clutter_filter_power_removed','velocity', 'differential_phase','spectrum_width' ]:\n", 344 | " KILX.fields.pop(key)\n", 345 | " KLOT.fields.pop(key)\n", 346 | " KIWX.fields.pop(key)" 347 | ] 348 | }, 349 | { 350 | "cell_type": "markdown", 351 | "metadata": {}, 352 | "source": [ 353 | "## Introducing Gatefilters!\n", 354 | "These will be covered in more detail in another notebook. Py-ART Gatefilters are a way of making highly configurable masks. Many (and soon all) Py-ART functions accept gatefilters. \n", 355 | "\n", 356 | "Here, we very simply make a gatefilter that excludes invalid (inf, nan et al) and masked values. **This can speed up gridding**." 357 | ] 358 | }, 359 | { 360 | "cell_type": "code", 361 | "execution_count": null, 362 | "metadata": {}, 363 | "outputs": [], 364 | "source": [ 365 | "KILX_f = pyart.filters.GateFilter(KILX)\n", 366 | "KILX_f.exclude_masked('reflectivity')\n", 367 | "KILX_f.exclude_invalid('reflectivity')\n", 368 | "\n", 369 | "KLOT_f = pyart.filters.GateFilter(KLOT)\n", 370 | "KLOT_f.exclude_masked('reflectivity')\n", 371 | "KLOT_f.exclude_invalid('reflectivity')\n", 372 | "\n", 373 | "KIWX_f = pyart.filters.GateFilter(KIWX)\n", 374 | "KIWX_f.exclude_masked('reflectivity')\n", 375 | "KIWX_f.exclude_invalid('reflectivity')\n", 376 | "\n" 377 | ] 378 | }, 379 | { 380 | "cell_type": "code", 381 | "execution_count": null, 382 | "metadata": {}, 383 | "outputs": [], 384 | "source": [ 385 | "#Lets construct a grid. NOTE: Origin is at the first radar in the tuple\n", 386 | "#This takes ~1 minute\n", 387 | "\n", 388 | "grids = pyart.map.grid_from_radars((KILX, KIWX, KLOT),(16,401,401),\n", 389 | " ((0.,15000.),(-400000.,400000.),(-400000.,400000.)), \n", 390 | " weighting_function='Barnes2',\n", 391 | " fields=['reflectivity','cross_correlation_ratio'],\n", 392 | " gatefilters=(KILX_f, KIWX_f, KLOT_f))" 393 | ] 394 | }, 395 | { 396 | "cell_type": "code", 397 | "execution_count": null, 398 | "metadata": {}, 399 | "outputs": [], 400 | "source": [ 401 | "# lets do some clean up\n", 402 | "del(KILX, KIWX, KLOT )" 403 | ] 404 | }, 405 | { 406 | "cell_type": "code", 407 | "execution_count": null, 408 | "metadata": {}, 409 | "outputs": [], 410 | "source": [ 411 | "# Lets convert to xarray\n", 412 | "xgrids = grids.to_xarray()\n", 413 | "\n", 414 | "box = (xgrids.lon.values.min(),xgrids.lon.values.max(), \n", 415 | " xgrids.lat.values.min(), xgrids.lat.values.max())" 416 | ] 417 | }, 418 | { 419 | "cell_type": "code", 420 | "execution_count": null, 421 | "metadata": {}, 422 | "outputs": [], 423 | "source": [ 424 | "box" 425 | ] 426 | }, 427 | { 428 | "cell_type": "code", 429 | "execution_count": null, 430 | "metadata": {}, 431 | "outputs": [], 432 | "source": [ 433 | "#lets make sure we get our projection right!\n", 434 | "\n", 435 | "print(grids.projection)\n", 436 | "lon_0 = grids.get_projparams()['lon_0']\n", 437 | "lat_0 = grids.get_projparams()['lat_0']\n", 438 | "proj = ccrs.AzimuthalEquidistant(central_latitude=lat_0, central_longitude=lon_0)" 439 | ] 440 | }, 441 | { 442 | "cell_type": "code", 443 | "execution_count": null, 444 | "metadata": {}, 445 | "outputs": [], 446 | "source": [ 447 | "lalogrids = xgrids.swap_dims({\"x\": \"lon\"})\n", 448 | "lalogrids = lalogrids.swap_dims({\"y\": \"lat\"})\n", 449 | "\n", 450 | "\n", 451 | "fig = plt.figure(figsize=[15, 7])\n", 452 | "\n", 453 | "# panel sizes\n", 454 | "map_panel_axes = [0.05, 0.05, .4, .80]\n", 455 | "x_cut_panel_axes = [0.55, 0.10, .4, .25]\n", 456 | "y_cut_panel_axes = [0.55, 0.50, .4, .25]\n", 457 | "\n", 458 | "# panel 1\n", 459 | "ax1 = fig.add_axes(map_panel_axes, projection=proj)\n", 460 | "\n", 461 | "\n", 462 | "pc = xgrids.reflectivity.sel(z=3000, \n", 463 | " time=xgrids.time[0]).plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow, \n", 464 | " vmin=-6, vmax=64, ax = ax1)\n", 465 | "\n", 466 | "ax1.add_feature(cfeature.COASTLINE)\n", 467 | "ax1.add_feature(cfeature.LAKES, zorder=0)\n", 468 | "\n", 469 | "gl = ax1.gridlines(draw_labels=True,\n", 470 | " linewidth=2, color='gray', alpha=0.5, linestyle='--')\n", 471 | "\n", 472 | "\n", 473 | "\n", 474 | "\n", 475 | "# panel 2, along longitude slice.\n", 476 | "ax2 = fig.add_axes(x_cut_panel_axes)\n", 477 | "\n", 478 | "pc = lalogrids.reflectivity.sel(lat=41.5, time=xgrids.time[0],method=\"nearest\").plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow,\n", 479 | " vmin=-6, vmax=64, ax=ax2)\n", 480 | "\n", 481 | "ax2.set_ylim([0,17000])\n", 482 | "ax2.set_xlim([-93,-87])\n", 483 | "ax2.set_xlabel('Distance from radar (km)')\n", 484 | "\n", 485 | "# panel 3, along latitude slice\n", 486 | "ax3 = fig.add_axes(y_cut_panel_axes)\n", 487 | "\n", 488 | "pc = lalogrids.reflectivity.sel(lon=-88.5, time=xgrids.time[0],method=\"nearest\").plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow,\n", 489 | " vmin=-6, vmax=64, ax=ax3)\n", 490 | "\n", 491 | "ax3.set_ylim([0,17000])\n", 492 | "\n", 493 | "ax3.set_xlabel('Distance from radar (km)')\n" 494 | ] 495 | }, 496 | { 497 | "cell_type": "markdown", 498 | "metadata": {}, 499 | "source": [ 500 | "## Now lets use MetPy!" 501 | ] 502 | }, 503 | { 504 | "cell_type": "code", 505 | "execution_count": null, 506 | "metadata": {}, 507 | "outputs": [], 508 | "source": [ 509 | "\n", 510 | "lon_0 = grids.get_projparams()['lon_0']\n", 511 | "lat_0 = grids.get_projparams()['lat_0']\n", 512 | "proj = ccrs.AzimuthalEquidistant(central_latitude=lat_0, central_longitude=lon_0)\n", 513 | "box = (xgrids.lon.values.min(),xgrids.lon.values.max(), \n", 514 | " xgrids.lat.values.min(), xgrids.lat.values.max())" 515 | ] 516 | }, 517 | { 518 | "cell_type": "code", 519 | "execution_count": null, 520 | "metadata": {}, 521 | "outputs": [], 522 | "source": [ 523 | "# METAR information is stored in a different \n", 524 | "# location from the previous THREDDS catalog, \n", 525 | "# notice the change in URL.\n", 526 | "metar_cat = TDSCatalog('https://thredds-test.unidata.ucar.edu/thredds/catalog/noaaport/text/metar/catalog.xml')\n", 527 | "\n", 528 | "# Open the metar file that contains data\n", 529 | "# closest to the satellite image time, dt\n", 530 | "#metar_text = metar_cat.datasets.filter_time_nearest(metpy_time_n).remote_open(mode='t')\n", 531 | "metar_text = metar_cat.datasets.filter_time_range(metpy_time_n, metpy_time_n + timedelta(hours=1))[0].remote_open(mode='t')" 532 | ] 533 | }, 534 | { 535 | "cell_type": "code", 536 | "execution_count": null, 537 | "metadata": {}, 538 | "outputs": [], 539 | "source": [ 540 | "metar_text" 541 | ] 542 | }, 543 | { 544 | "cell_type": "code", 545 | "execution_count": null, 546 | "metadata": {}, 547 | "outputs": [], 548 | "source": [ 549 | "# parse_metar_file() outputs a pandas DataFrame\n", 550 | "sfc_data = parse_metar_file(metar_text, year=metpy_time_n.year, month=metpy_time_n.month)\n", 551 | "\n", 552 | "# Save the units for all columns to a new variable\n", 553 | "sfc_units = sfc_data.units\n", 554 | "\n", 555 | "# Filter out missing lat/lon data\n", 556 | "sfc_data = sfc_data[sfc_data.latitude.notna() & sfc_data.longitude.notna()]\n", 557 | "\n", 558 | "# Set missing weather condition data to an empty string, ''\n", 559 | "sfc_data['current_wx1'][sfc_data['current_wx1'].isna()] = ''" 560 | ] 561 | }, 562 | { 563 | "cell_type": "code", 564 | "execution_count": null, 565 | "metadata": {}, 566 | "outputs": [], 567 | "source": [ 568 | "#Thanks Ryan May for this fix. There are more than one ob in a one hour Siphon sample\n", 569 | "\n", 570 | "def closest(df, dt):\n", 571 | " diff = df.date_time - dt\n", 572 | " ind = np.argmin(diff)\n", 573 | " return df.iloc[ind]\n" 574 | ] 575 | }, 576 | { 577 | "cell_type": "code", 578 | "execution_count": null, 579 | "metadata": {}, 580 | "outputs": [], 581 | "source": [ 582 | "sfc_data.pop('station_id')\n", 583 | "sfc_data = sfc_data.groupby('station_id').apply(closest, metpy_time_n)\n", 584 | "sfc_data = pandas_dataframe_to_unit_arrays(sfc_data, sfc_units)\n" 585 | ] 586 | }, 587 | { 588 | "cell_type": "code", 589 | "execution_count": null, 590 | "metadata": {}, 591 | "outputs": [], 592 | "source": [ 593 | "sfc_data['wx_code'] = mpplots.wx_code_to_numeric(sfc_data['current_wx1'])\n", 594 | "sfc_data['u'], sfc_data['v'] = mpcalc.wind_components(sfc_data['wind_speed'], sfc_data['wind_direction'])\n", 595 | "\n", 596 | "# Start by creating the matplotlib axes\n", 597 | "fig = plt.figure(figsize=[15, 15])\n", 598 | "ax = plt.axes(projection=proj)\n", 599 | "pc = xgrids.reflectivity.sel(z=1000, method=\"nearest\",\n", 600 | " time=xgrids.time[0]).plot.pcolormesh(cmap=pyart.graph.cm_colorblind.HomeyerRainbow, \n", 601 | " vmin=-6, vmax=64)\n", 602 | "gl = ax.gridlines(draw_labels=True,\n", 603 | " linewidth=2, color='gray', alpha=0.5, linestyle='--')\n", 604 | "# Create the station plot object, stn,\n", 605 | "# from the StationPlot class, using the\n", 606 | "# PlateCarree projection\n", 607 | "stn = mpplots.StationPlot(ax, sfc_data['longitude'].m, sfc_data['latitude'].m, transform=ccrs.PlateCarree(),\n", 608 | " clip_on=True)\n", 609 | "\n", 610 | "# Populate the temperature and dewpoint\n", 611 | "stn.plot_parameter('NW', sfc_data['air_temperature'], color='red')\n", 612 | "stn.plot_parameter('SW', sfc_data['dew_point_temperature'], color='blue')\n", 613 | "\n", 614 | "# Populate the center circle cloud coverage and weather code\n", 615 | "stn.plot_symbol('C', sfc_data['cloud_coverage'], mpplots.sky_cover)\n", 616 | "stn.plot_symbol('E', sfc_data['wx_code'], mpplots.current_weather, color='blue')\n", 617 | "\n", 618 | "# Populate the wind bard\n", 619 | "stn.plot_barb(sfc_data['u'], sfc_data['v'])\n", 620 | "\n", 621 | "\n", 622 | "ax.add_feature(cfeature.COASTLINE)\n", 623 | "ax.add_feature(cfeature.LAKES, zorder=0)\n", 624 | "ax.set_extent(box)" 625 | ] 626 | }, 627 | { 628 | "cell_type": "code", 629 | "execution_count": null, 630 | "metadata": {}, 631 | "outputs": [], 632 | "source": [] 633 | } 634 | ], 635 | "metadata": { 636 | "kernelspec": { 637 | "display_name": "Python 3", 638 | "language": "python", 639 | "name": "python3" 640 | }, 641 | "language_info": { 642 | "codemirror_mode": { 643 | "name": "ipython", 644 | "version": 3 645 | }, 646 | "file_extension": ".py", 647 | "mimetype": "text/x-python", 648 | "name": "python", 649 | "nbconvert_exporter": "python", 650 | "pygments_lexer": "ipython3", 651 | "version": "3.7.8" 652 | } 653 | }, 654 | "nbformat": 4, 655 | "nbformat_minor": 5 656 | } 657 | -------------------------------------------------------------------------------- /Courses/AMSPythonVirtual2021.md: -------------------------------------------------------------------------------- 1 | # the 2021 AMS Python Course Py-ART Component 2 | Huge shout out to Damien Irving and co for organizing. 3 | 4 | The Python ARM Radar Toolkit is a open source community platform for interacting with radar (and even LIDAR) data based 5 | around a common data model. Py-ART is supported by the United States Department of Energy, Office of Science, 6 | [ARM program](www.arm.gov) and we are grateful for their support. 7 | 8 | Py-ART is a [community codebase with 38 contributors](https://github.com/ARM-DOE/pyart)! 9 | 10 | The Py-ART component will cover three notebooks from our training repository. This will be mainly done in a 11 | demonstration mode with some time for exploring. 12 | 13 | The three notebooks are: 14 | 1) [Reading data using Py-ART and a basic explore of the data model and plotting.](../1-Introduction/1_pyart_reading_and_plotting_data.ipynb) 15 | 2) [Mapping polar radar data onto a cartesian grid and a bit more Cartopy fun](../1-Introduction/2_Introduction_to_gridding.ipynb) 16 | 3) [An Application of Py-ART to NEXRAD in the Cloud and linking to MetPy](../2-Cloud_Examples/1-NEXRAD_on_Amazon.ipynb) 17 | 18 | To get started in the cloud click to launch this Pangeo (we LOVE Pangeo) hosted Binder: 19 | [![Binder](https://mybinder.org/badge_logo.svg)](https://binder.pangeo.io/v2/gh/ARM-Development/PyART-Training/HEAD?urlpath=lab) 20 | 21 | If you want to install locally [Check out the readme](../README.md) 22 | 23 | -------------------------------------------------------------------------------- /Courses/MidwestStudent2021.md: -------------------------------------------------------------------------------- 1 | # The 2021 Midwest Student Conference on Atmospheric Research 2 | ![alt](./mwsc.png) 3 | 4 | **Welcome students!** 5 | 6 | The Python ARM Radar Toolkit is a open source community platform for interacting with radar (and even LIDAR) data based 7 | around a common data model. Py-ART is supported by the United States Department of Energy, Office of Science, 8 | [ARM program](https://www.arm.gov) and we are grateful for their support. 9 | 10 | Py-ART is a [community codebase with 38 contributors](https://github.com/ARM-DOE/pyart)! 11 | 12 | This *very* short course will give you an introduction to Py-ART. This will be mainly done in a 13 | demonstration mode with some time for exploring. This should be considered an on-ramp for your learning. 14 | 15 | Stay in touch by [joining the email list]( https://groups.google.com/group/pyart-users/) 16 | 17 | Follow [Scott](https://twitter.com/Cyclogenesis_au), [Bobby](https://twitter.com/rcjackson_wx), 18 | [Zach](https://twitter.com/zssherman) or [Py-ART](https://twitter.com/Py_ART) on Twitter. 19 | 20 | The three notebooks are: 21 | 1) [Reading data using Py-ART and a basic explore of the data model and plotting.](../1-Introduction/1_pyart_reading_and_plotting_data.ipynb) 22 | 2) [Mapping polar radar data onto a cartesian grid and a bit more Cartopy fun](../1-Introduction/2_Introduction_to_gridding.ipynb) 23 | 3) [An Application of Py-ART to NEXRAD in the Cloud and linking to MetPy](../2-Cloud_Examples/1-NEXRAD_on_Amazon.ipynb) 24 | 25 | Basic schedule (Central time): 26 | * 9am - 9:20 am Introduction and getting tech working 27 | * 9:20 am - 9:50 am Intro notebook 28 | * 9:50 am - 10 am Break 29 | * 10 am - 10:20 am Mapping and griding 30 | * 10:20 am - 11 am Cloud example 31 | 32 | There are two ways to run the code for this course. Thanks to Pangeo, you can run it in the cloud. 33 | If you are running the course this way please be patient when the instance is spinning up. The less risky but harder 34 | way is installing locally. **With 35 people signed up for the course and just Scott as an instructor 35 | we will not be able to provide assistance in real time.** If you run into an 36 | issue follow along with the livestream. The Pangeo binder will stay live so you can try running 37 | interactively at a later date. 38 | 39 | ### Lets Go! 40 | 41 | To get started in the cloud click to launch this Pangeo (we LOVE Pangeo) hosted Binder: 42 | [![Binder](https://mybinder.org/badge_logo.svg)](https://binder.pangeo.io/v2/gh/ARM-Development/PyART-Training/HEAD?urlpath=lab) 43 | 44 | If you want to install locally [Check out the readme](../README.md) 45 | 46 | -------------------------------------------------------------------------------- /Courses/mwsc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARM-Development/PyART-Training/2ed38216fdd19c8b5a38f7e83c376da05d6b2336/Courses/mwsc.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Atmospheric Radiation Measurement user facility 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyART-Training 2 | A repository containing consolidated training materials for Py-ART 3 | 4 | ## Running in the Cloud 5 | 6 | Launch Binder: 7 | [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/ARM-Development/PyART-Training/HEAD) 8 | 9 | Launch JupyterLab Binder (Beta but much cooler): 10 | [![Binder](https://mybinder.org/badge_logo.svg)](https://beta.mybinder.org/v2/gh/ARM-Development/PyART-Training/HEAD?urlpath=lab) 11 | 12 | Launch JupyterLab Pangeo (Not LTS but needed for gridding examples): 13 | [![Binder](https://mybinder.org/badge_logo.svg)](https://binder.pangeo.io/v2/gh/ARM-Development/PyART-Training/HEAD?urlpath=lab) 14 | 15 | Huge thanks to the Binder and Pangeo teams their institutions and sponsors. 16 | 17 | ## Local Installation 18 | 19 | **Please note this requires compilers on your system. Google how to do this using things like xcode (macos) and 20 | build-essential (ubuntu)** 21 | 22 | Clone this repository to a local directory 23 | 24 | eg: 25 | ```shell 26 | wget https://github.com/ARM-Development/PyART-Training/archive/main.zip 27 | unzip main.zip 28 | ``` 29 | or: 30 | ```shell script 31 | git clone https://github.com/ARM-Development/PyART-Training 32 | ``` 33 | 34 | Create the environment using Conda: 35 | ```shell script 36 | cd pyart-training 37 | conda env create -f environment.yml 38 | conda activate pyart-training 39 | ``` 40 | 41 | **If you are having issues with compilers (pip) use the simple env (not all examples will work):** 42 | ```shell script 43 | cd pyart-training 44 | conda env create -f simple.yml 45 | conda activate pyart-training 46 | ``` 47 | 48 | Provisioning. 49 | If you have not got a system wide wget install it using conda: 50 | ```shell script 51 | conda install -c conda-forge wget 52 | ``` 53 | 54 | Run the provision script (note, could be zsh et al instead of bash): 55 | ```shell script 56 | bash scripts/provision.sh 57 | ``` 58 | Note, some users report SSL issues with the wget command.. if this hits you use: 59 | 60 | ```shell script 61 | bash scripts/provision_curl.sh 62 | ``` 63 | 64 | Rock on! 65 | ```shell script 66 | jupyter notebook 67 | ``` 68 | 69 | 70 | 71 | ## Courses 72 | 73 | [The 2021 AMS Python Virtual course](./Courses/AMSPythonVirtual2021.md) 74 | 75 | [The 2021 Midwest Student Conference on Atmospheric Research](./Courses/MidwestStudent2021.md) 76 | -------------------------------------------------------------------------------- /binder/environment.yml: -------------------------------------------------------------------------------- 1 | name: pyart-training 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - pip 7 | - python=3.7 8 | - ipython=7.10 9 | - boto 10 | - boto3 11 | - cython 12 | - numpy 13 | - scipy 14 | - matplotlib 15 | - jupyter 16 | - xarray 17 | - netcdf4 18 | - metpy 19 | - siphon 20 | - cartopy 21 | - geographiclib 22 | - act-atmos 23 | - pip: 24 | - nexradaws 25 | - git+https://github.com/ARM-DOE/pyart 26 | - git+https://github.com/CSU-Radarmet/CSU_RadarTools.git -------------------------------------------------------------------------------- /binder/postBuild: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | jupyter contrib nbextension install --user 4 | jupyter nbextension enable --py widgetsnbextension 5 | jupyter labextension install @jupyter-widgets/jupyterlab-manager@0.38 --minimize=False 6 | 7 | 8 | #export COIN_INSTALL_DIR=/srv/conda/envs/notebook 9 | #/srv/conda/envs/notebook/bin/pip install git+https://github.com/coin-or/CyLP 10 | 11 | bash /home/jovyan/scripts/provision.sh -------------------------------------------------------------------------------- /scripts/provision.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | cd ~ 5 | mkdir data 6 | cd data 7 | 8 | #cp2 removed for this example 9 | 10 | #mkdir cp2 11 | #cd cp2 12 | #wget http://mcs.anl.gov/~scollis/cp2.tgz 13 | #tar -xvzf cp2.tgz 14 | #rm cp2.tgz 15 | #cd .. 16 | 17 | #wget http://www.mcs.anl.gov/~scollis/era5_data_aus.nc 18 | 19 | 20 | #NOTE: This is temporary.. This will be replaced using ARMLive 21 | 22 | mkdir arm 23 | cd arm 24 | wget http://www.mcs.anl.gov/~scollis/pyart/csapr_test_case.nc 25 | wget http://www.mcs.anl.gov/~scollis/pyart/nsaxsaprppiC1.a1.20140201.184802.nc 26 | wget http://www.mcs.anl.gov/~scollis/pyart/sgpxsaprcmacsurI5.c1.20170801.044013.nc 27 | cd .. 28 | #wget http://www.mcs.anl.gov/~scollis/metdata.tgz 29 | #tar -xvzf metdata.tgz 30 | #rm metdata.tgz 31 | 32 | wget http://www.mcs.anl.gov/~scollis/ausdata.tgz 33 | tar -xvzf ausdata.tgz 34 | rm ausdata.tgz 35 | 36 | cd ~ 37 | if [ -d tmp ]; then 38 | rm -rf tmp 39 | fi 40 | -------------------------------------------------------------------------------- /scripts/provision_curl.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #Thanks Dave Wolff 4 | 5 | cd ~ 6 | mkdir data 7 | cd data 8 | mkdir arm 9 | cd arm 10 | 11 | #wget http://www.mcs.anl.gov/~scollis/pyart/csapr_test_case.nc 12 | #wget http://www.mcs.anl.gov/~scollis/pyart/nsaxsaprppiC1.a1.20140201.184802.nc 13 | #wget http://www.mcs.anl.gov/~scollis/pyart/sgpxsaprcmacsurI5.c1.20170801.044013.nc 14 | 15 | echo "Getting ARM data..." 16 | curl -o csapr_test_case.nc https://www.mcs.anl.gov/~scollis/pyart/csapr_test_case.nc 17 | curl -o nsaxsaprppiC1.a1.20140201.184802.nc https://www.mcs.anl.gov/~scollis/pyart/nsaxsaprppiC1.a1.20140201.184802.nc 18 | curl -o sgpxsaprcmacsurI5.c1.20170801.044013.nc https://www.mcs.anl.gov/~scollis/pyart/sgpxsaprcmacsurI5.c1.20170801.044013.nc 19 | 20 | echo "Getting AUS data..." 21 | cd ~/data 22 | curl -o ausdata.tgz https://www.mcs.anl.gov/~scollis/ausdata.tgz 23 | tar -xvzf ausdata.tgz 24 | rm ausdata.tgz 25 | 26 | cd ~ 27 | if [ -d tmp ]; then 28 | rm -rf tmp 29 | fi 30 | 31 | echo "Done." -------------------------------------------------------------------------------- /simple.yml: -------------------------------------------------------------------------------- 1 | name: pyart-training 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - pip 7 | - python=3.7 8 | - ipython=7.10 9 | - boto 10 | - boto3 11 | - cython 12 | - numpy 13 | - scipy 14 | - matplotlib 15 | - jupyter 16 | - xarray 17 | - netcdf4 18 | - metpy 19 | - siphon 20 | - cartopy 21 | - arm_pyart 22 | - pip: 23 | - nexradaws --------------------------------------------------------------------------------