{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Meteogram\n", "## Here we draw a surface meteogram, from data that we retrieve from our METAR archive." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Imports" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "\n", "import matplotlib.pyplot as plt\n", "from matplotlib.dates import DateFormatter, AutoDateLocator,YearLocator, HourLocator,DayLocator,MonthLocator\n", "\n", "from metpy.units import units\n", "from datetime import datetime, timedelta\n", "import seaborn as sns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Set the desired start and end time (UTC), and create strings for the figure title." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "startTime = datetime(2024,4,20,0)\n", "endTime = datetime(2024,4,23,0)\n", "sTimeStr = startTime.strftime(format=\"%x %H UTC\")\n", "eTimeStr = endTime.strftime(format=\"%x %H UTC\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create an empty `Dateframe` to which we will concatenate the hourly CSV files in the desired time range." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df = pd.DataFrame()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Loop over each hour. Concatenate each hour's METARs into the full `Dataframe`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "curTime = startTime\n", "while (curTime <= endTime):\n", " print (curTime)\n", " timeStr = curTime.strftime(\"%y%m%d%H\")\n", " metarCSV = f'/ktyle_rit/scripts/sflist2/complete/{timeStr}.csv'\n", " dfTemp = pd.read_csv(metarCSV, sep='\\s+')\n", " df = pd.concat([df, dfTemp], ignore_index=True)\n", " curTime = curTime + timedelta(hours=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Examine the `Dataframe`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Select the station from which to subset the `Dataframe`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "site = 'ALB'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create a new `Dataframe` that contains only the rows for the desired site." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dfSub = df.query('STN == @site')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create a new column that represents the date and time as a `datetime64` object." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Next line suppresses a warning message. See https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy. \n", "# This won't be necessary with Pandas version 3 and beyond.\n", "\n", "pd.options.mode.copy_on_write = True \n", "\n", "dattim = pd.to_datetime(dfSub['YYMMDD/HHMM'],format=\"%y%m%d/%H%M\", utc=True)\n", "dfSub['DATETIME'] = dattim" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Examine the subsetted `Dataframe`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dfSub" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Select a couple of variables we wish to plot on the meteogram. In this case, 2m temperature and dewpoint." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "var1 = dfSub['TMPC']\n", "var2 = dfSub['DWPC']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Examine one of the variables ... of course, it's a Pandas `Series`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "var1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pandas `Series` objects don't support units. We can, however, create **Numpy** arrays from the `Series` *values* attribute and then attach units to them." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "tmpc = var1.values * units('degC')\n", "dwpc = var2.values * units('degC')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Examine one of the units-aware arrays." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tmpc" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now convert into degrees F." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "tmpf = tmpc.to('degF')\n", "dwpf = dwpc.to('degF')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Create the meteogram and save the figure to disk." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "sns.set()\n", "\n", "fig, ax = plt.subplots(figsize=(15, 10))\n", "\n", "# Improve on the default ticking\n", "\n", "ax.xaxis.set_major_locator(HourLocator(interval=3))\n", "hoursFmt = DateFormatter('%d/%H')\n", "ax.xaxis.set_major_formatter(hoursFmt)\n", "\n", "ax.plot(dfSub['DATETIME'], tmpf, color='tab:red', label='Temp')\n", "ax.plot(dfSub['DATETIME'], dwpf, color='tab:green', label='Dwpt')\n", "\n", "ax.set_title(f'Site: {site} Date Range: {sTimeStr} - {eTimeStr}')\n", "\n", "ax.set_xlabel('Hour (UTC)')\n", "ax.set_ylabel('Temperature °F')\n", "ax.set_xlim(startTime, endTime)\n", "ax.legend(loc='best')\n", "\n", "fig.savefig (f'{site}_mgram.png')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "

Things to try:

\n", "
  1. Basic Select a site and time range relevant for your case
  2. \n", "
  3. Basic Create a multi-panel figure, each displaying a variable of interest
  4. \n", "
  5. Advanced Plot two variables that have different units; create corresponding y-axis labels on the left and right sides of the plot
\n", "
" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 Jan. 2024 Environment", "language": "python", "name": "jan24" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.7" } }, "nbformat": 4, "nbformat_minor": 4 }