Pneumonia Front (May 16, 2023)#

What is a Pneumonia Front?#

This is a term, originally coined by meteorologists in Milwaukee, Wisconsin, that refers to a strong cold front around the Great Lakes that leads to temperatures cooling very quickly, at a rate of 16 degrees Fahrenheit in 1 hour. These fronts can be quite common in the spring around Milwaukee and Chicagoland. We observed one of these fronts on May 16, 2023, observing this steep temperature decrease at one of our sensors at Northeastern Illinois University on the north side of Chicago, Illinois!

The Code to Create the Plots#

Hide code cell source
import sage_data_client
from bokeh.models.formatters import DatetimeTickFormatter
import hvplot.pandas
import hvplot.xarray
import pytz
import holoviews as hv
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import xarray as xr
import matplotlib.pyplot as plt
from metpy.plots import USCOUNTIES
import metpy.calc as mpcalc
import act
import numpy as np
import pandas as pd
import warnings
from bokeh.models import DatetimeTickFormatter
import panel as pn

start="2023-05-16T22:00:00Z"
end="2023-05-17T00:00:00Z"

def apply_formatter(plot, element):
    plot.handles['xaxis'].formatter = DatetimeTickFormatter(hours='%m/%d/%Y \n %H:%M',
                                                            minutes='%m/%d/%Y \n %H:%M',
                                                            hourmin='%m/%d/%Y \n %H:%M',
                                                            days='%m/%d/%Y \n %H:%M',
                                                            months='%m/%d/%Y \n %H:%M')
xr.set_options(keep_attrs=True)
warnings.filterwarnings("ignore")
hv.extension("bokeh")



# Dictionary for renaming to standard names
variable_rename_dict = {'wxt.env.humidity':'relative_humidity',
                        'wxt.env.pressure':'air_pressure',
                        'wxt.env.temp':'air_temperature',
                        'wxt.heater.temp':'heater_temperature',
                        'wxt.heater.volt':'heater_voltage',
                        'wxt.rain.accumulation':'rain_accumulation',
                        'wxt.wind.direction':'wind_direction',
                        'wxt.wind.speed':'wind_speed',
                        'sys.gps.lat':'latitude',
                        'sys.gps.lon':'longitude',
                    }

# Dictionary for units that are missing
units_dict = {'wxt.env.temp': 'degC',
              'wxt.env.pressure':'hPa',
              'wxt.env.humidity':'percent',
              'wxt.wind.speed':'m/s',
              'wxt.wind.direction':'degrees'}

def generate_data_array(df, variable, rename_variable_dict=variable_rename_dict):
    new_variable_name = rename_variable_dict[variable]
    df_variable= df.loc[df.name == variable]
    ds = df_variable.to_xarray().rename({'value':new_variable_name,
                                         'timestamp':'time',
                                         'meta.vsn':'node'})
    ds[new_variable_name].attrs['units'] = df_variable['meta.units'].values[0]
    ds['time'] = pd.to_datetime(ds.time)
    ds.attrs['datastream'] = ds.node.values[0]
    return ds[[new_variable_name]]

def generate_dataset(df, variables, rename_variable_dict=variable_rename_dict):
    try:
        reindexed = df.set_index(['meta.vsn', 'timestamp'])
    except:
        reindexed = df.set_index(['timestamp'])
    return xr.merge([generate_data_array(reindexed, variable) for variable in variables])


# Query and load for n numbder of days
wxt_df = sage_data_client.query(
    start=start,
    end=end,
    filter={
        "sensor": "vaisala-wxt536",
        "name": "wxt.env.*"
    }
)

wxt_df1 = sage_data_client.query(
    start=start,
    end=end,
    filter={
        "sensor": "vaisala-wxt536",
        "name": "wxt.wind.*"
    }
)

# Use local Chicago times
wxt_df = pd.concat([wxt_df, wxt_df1])
#time = pd.to_datetime(wxt_df.timestamp.values, utc=True)
#wxt_df['timestamp'] = time.tz_convert(pytz.timezone("America/Chicago"))

try:

    # Discover what variables we have and what to load into xarray
    wxt_variables = wxt_df.name.unique()
    wxt_df['meta.units'] = wxt_df.name.map(units_dict)
    
    wxt_ds = generate_dataset(wxt_df, wxt_variables).squeeze().metpy.parse_cf()
    wxt_ds['node'] = ['W08D at Northeastern Illinois University']
    # Convert to Local Chicago Time - THIS IS ONLY FOR DAYLIGHT TIME
    wxt_ds['time'] = wxt_ds.time - pd.Timedelta(hours=5)
    wxt_ds['air_dewpoint_temperature'] = mpcalc.dewpoint_from_relative_humidity(wxt_ds.air_temperature, wxt_ds.relative_humidity)
    
    # Convert to degrees Fahrenheit
    wxt_ds['air_temperature'] = wxt_ds['air_temperature'].metpy.quantify().metpy.convert_units('degF').metpy.dequantify()
    wxt_ds['air_dewpoint_temperature'] = wxt_ds['air_dewpoint_temperature'].metpy.quantify().metpy.convert_units('degF').metpy.dequantify()
    wxt_ds['wind_speed'] = wxt_ds['wind_speed'].metpy.quantify().metpy.convert_units('mph').metpy.dequantify()
    
    # Resample to 1 minute freqency
    minute_ds = wxt_ds.resample(time='1T').mean()

    plots = []
    temp_plot = wxt_ds.air_temperature.hvplot(color='red',
                                              xlabel='Local Time (Chicago)',
                                              label='Air Temperature (degF)')
    dewp_plot = wxt_ds.air_dewpoint_temperature.hvplot(color='green',
                                                       xlabel='Local Time (Chicago)',
                                                       label='Dewpoint Temperature (degF)')
    plots.append((temp_plot * dewp_plot).opts(hooks=[apply_formatter]))
    
    meteogram_variables = ['wind_speed', 'wind_direction']
    for variable in meteogram_variables:
        plots.append((wxt_ds[variable].hvplot.line(label='10 Hz Data') * 
                     minute_ds[variable].hvplot.line(label='1 Minute Data')).opts(hooks=[apply_formatter]))
    
    
except:
    plots = pn.Row(title='No Data Available')

View the Data!#

Here, we are looking at the Temperature (red), Dewpoint (green), and Wind Speed and Direction (blue). Notice the temperature drop at around 5:30 PM local time, and the increase in wind speed!

Hide code cell source
display(hv.Layout(plots).opts(title='CROCUS Observations at Northeastern Illinois').cols(1))