示例#1
0
def test_station_plot_locations():
    """Test that locations are properly replaced."""
    fig = plt.figure(figsize=(3, 3))

    locations = ['C', 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N2', 'NNE', 'ENE', 'E2',
                 'ESE', 'SSE', 'S2', 'SSW', 'WSW', 'W2', 'WNW', 'NNW']
    x_pos = np.array([0])
    y_pos = np.array([0])

    # Make the plot
    sp = StationPlot(fig.add_subplot(1, 1, 1), x_pos, y_pos, fontsize=8, spacing=24)
    for loc in locations:
        sp.plot_text(loc, [loc])

    sp.ax.set_xlim(-2, 2)
    sp.ax.set_ylim(-2, 2)

    return fig
示例#2
0
def test_plot_text_fontsize():
    """Test changing fontsize in plot_text."""
    fig = plt.figure(figsize=(3, 3))
    ax = plt.subplot(1, 1, 1)

    # testing data
    x = np.array([1])
    y = np.array([2])

    # Make the plot
    sp = StationPlot(ax, x, y, fontsize=36)
    sp.plot_text('NW', ['72'], fontsize=24)
    sp.plot_text('SW', ['60'], fontsize=4)

    sp.ax.set_xlim(0, 3)
    sp.ax.set_ylim(0, 3)

    return fig
示例#3
0
def test_station_plot_replace():
    """Test that locations are properly replaced."""
    fig = plt.figure(figsize=(3, 3))

    # testing data
    x = np.array([1])
    y = np.array([1])

    # Make the plot
    sp = StationPlot(fig.add_subplot(1, 1, 1), x, y, fontsize=16)
    sp.plot_barb([20], [0])
    sp.plot_barb([5], [0])
    sp.plot_parameter('NW', [10.5], color='red')
    sp.plot_parameter('NW', [20], color='blue')

    sp.ax.set_xlim(-3, 3)
    sp.ax.set_ylim(-3, 3)

    return fig
示例#4
0
def test_stationplot_clipping():
    """Test the that clipping can be enabled as a default parameter."""
    fig = plt.figure(figsize=(9, 9))

    # testing data
    x = np.array([1, 5])
    y = np.array([2, 4])

    # Make the plot
    sp = StationPlot(fig.add_subplot(1, 1, 1), x, y, fontsize=16, clip_on=True)
    sp.plot_barb([20, 0], [0, -50])
    sp.plot_text('E', ['KOKC', 'ICT'], color='blue')
    sp.plot_parameter('NW', [10.5, 15] * units.degC, color='red')
    sp.plot_symbol('S', [5, 7], high_clouds, color='green')

    sp.ax.set_xlim(1, 5)
    sp.ax.set_ylim(1.75, 4.25)

    return fig
示例#5
0
def test_stationplot_api():
    """Test the StationPlot API."""
    fig = plt.figure(figsize=(9, 9))

    # testing data
    x = np.array([1, 5])
    y = np.array([2, 4])

    # Make the plot
    sp = StationPlot(fig.add_subplot(1, 1, 1), x, y, fontsize=16)
    sp.plot_barb([20, 0], [0, -50])
    sp.plot_text('E', ['KOKC', 'ICT'], color='blue')
    sp.plot_parameter('NW', [10.5, 15] * units.degC, color='red')
    sp.plot_symbol('S', [5, 7], high_clouds, color='green')

    sp.ax.set_xlim(0, 6)
    sp.ax.set_ylim(0, 6)

    return fig
示例#6
0
def test_simple_layout():
    """Test metpy's simple layout for station plots."""
    fig = plt.figure(figsize=(9, 9))

    # testing data
    x = np.array([1, 5])
    y = np.array([2, 4])
    data = {'air_temperature': np.array([32., 212.]) * units.degF,
            'dew_point_temperature': np.array([28., 80.]) * units.degF,
            'air_pressure_at_sea_level': np.array([29.92, 28.00]) * units.inHg,
            'eastward_wind': np.array([2, 0]) * units.knots,
            'northward_wind': np.array([0, 5]) * units.knots, 'cloud_coverage': [3, 8],
            'present_weather': [65, 75], 'unused': [1, 2]}

    # Make the plot
    sp = StationPlot(fig.add_subplot(1, 1, 1), x, y, fontsize=12)
    simple_layout.plot(sp, data)

    sp.ax.set_xlim(0, 6)
    sp.ax.set_ylim(0, 6)

    return fig
示例#7
0
ax.coastlines(resolution='110m', zorder=2, color='black')
ax.add_feature(state_boundaries, edgecolor='black')
ax.add_feature(feat.BORDERS, linewidth='2', edgecolor='black')

# Set plot bounds
ax.set_extent((-118, -73, 23, 50))

#
# Here's the actual station plot
#

# Start the station plot by specifying the axes to draw on, as well as the
# lon/lat of the stations (with transform). We also the fontsize to 12 pt.
stationplot = StationPlot(ax,
                          data['lon'].values,
                          data['lat'].values,
                          clip_on=True,
                          transform=ccrs.PlateCarree(),
                          fontsize=12)

# Plot the temperature and dew point to the upper and lower left, respectively, of
# the center point. Each one uses a different color.
stationplot.plot_parameter('NW', data['air_temperature'], color='red')
stationplot.plot_parameter('SW',
                           data['dew_point_temperature'],
                           color='darkgreen')

# A more complex example uses a custom formatter to control how the sea-level pressure
# values are plotted. This uses the standard trailing 3-digits of the pressure value
# in tenths of millibars.
stationplot.plot_parameter('NE',
                           data['slp'],
示例#8
0
           s=30,
           marker='+',
           transform=ccrs.PlateCarree(),
           color='lightgrey',
           zorder=-1)

# Add gridlines for every 5 degree lat/lon
ax.gridlines(linestyle='solid',
             ylocs=range(15, 71, 5),
             xlocs=range(-150, -49, 5))

# Start the station plot by specifying the axes to draw on, as well as the
# lon/lat of the stations (with transform). We also the fontsize to 10 pt.
stationplot = StationPlot(ax,
                          df['longitude'].values,
                          df['latitude'].values,
                          clip_on=True,
                          transform=ccrs.PlateCarree(),
                          fontsize=10)

# Plot the temperature and dew point to the upper and lower left, respectively, of
# the center point.
stationplot.plot_parameter('NW', df['temperature'], color='black')
stationplot.plot_parameter('SW', df['dewpoint'], color='black')

# A more complex example uses a custom formatter to control how the geopotential height
# values are plotted. This is set in an earlier if-statement to work appropriate for
# different levels.
stationplot.plot_parameter('NE', df['height'], formatter=hght_format)

# Add wind barbs
stationplot.plot_barb(df['u_wind'], df['v_wind'], length=7, pivot='tip')
示例#9
0
def plot_map_temperature(proj,
                         point_locs,
                         df_t,
                         area='EU',
                         west=-5.5,
                         east=32,
                         south=42,
                         north=62,
                         fonts=14,
                         cm='gist_ncar',
                         path=None,
                         SLP=False):
    if path is None:
        # set up the paths and test for existence
        path = expanduser('~') + '/Documents/Metar_plots'
        try:
            os.listdir(path)
        except FileNotFoundError:
            os.mkdir(path)
    else:
        path = path
    df = df_t
    plt.rcParams['savefig.dpi'] = 300
    # =========================================================================
    # Create the figure and an axes set to the projection.
    fig = plt.figure(figsize=(20, 16))
    ax = fig.add_subplot(1, 1, 1, projection=proj)
    if area == 'Antarctica':
        df = df.loc[df['latitude'] < north]
        ax.set_extent([-180, 180, -90, -60], ccrs.PlateCarree())
        theta = np.linspace(0, 2 * np.pi, 100)
        center, radius = [0.5, 0.5], 0.5
        verts = np.vstack([np.sin(theta), np.cos(theta)]).T
        circle = mpath.Path(verts * radius + center)
        ax.set_boundary(circle, transform=ax.transAxes)
    elif area == 'Arctic':
        df = df.loc[df['latitude'] > south]
        ax.set_extent([-180, 180, 60, 90], ccrs.PlateCarree())
        theta = np.linspace(0, 2 * np.pi, 100)
        center, radius = [0.5, 0.5], 0.5
        verts = np.vstack([np.sin(theta), np.cos(theta)]).T
        circle = mpath.Path(verts * radius + center)
        ax.set_boundary(circle, transform=ax.transAxes)

    else:
        ax.set_extent((west, east, south, north))
    # Set up a cartopy feature for state borders.
    state_boundaries = feat.NaturalEarthFeature(category='cultural',
                                                name='admin_0_countries',
                                                scale='10m',
                                                facecolor='#d8dcd6',
                                                alpha=0.5)
    ax.coastlines(resolution='10m', zorder=1, color='black')
    ax.add_feature(state_boundaries, zorder=1, edgecolor='black')
    # ax.add_feature(cartopy.feature.OCEAN, zorder=0)
    # Set plot bounds
    # reset index for easier loop
    df = df.dropna(how='any', subset=['TT'])
    df = df.reset_index()
    cmap = matplotlib.cm.get_cmap(cm)
    norm = matplotlib.colors.Normalize(vmin=-30.0, vmax=30.0)
    # Start the station plot by specifying the axes to draw on, as well as the
    # lon/lat of the stations (with transform). We also the fontsize to 12 pt.
    index = 0
    a = np.arange(-30, 30, 1)
    for x in a:
        if index == 0:
            df_min = df.loc[df['TT'] < min(a)]
            df_max = df.loc[df['TT'] > max(a)]
            j = 0
            list_ex = [min(a) - 5, max(a) + 5]
            for arr in [df_min, df_max]:
                stationplot = StationPlot(ax,
                                          arr['longitude'],
                                          arr['latitude'],
                                          clip_on=True,
                                          transform=ccrs.PlateCarree(),
                                          fontsize=fonts)
                Temp = stationplot.plot_parameter('NW',
                                                  arr['TT'],
                                                  color=cmap(norm(list_ex[j])))
                try:
                    Temp.set_path_effects([
                        path_effects.Stroke(linewidth=1.5, foreground='black'),
                        path_effects.Normal()
                    ])
                except AttributeError:
                    pass
                j += 1
        # slice out values between x and x+1
        df_cur = df.loc[(df['TT'] < x + 1) & (df['TT'] >= x)]
        stationplot = StationPlot(ax,
                                  df_cur['longitude'],
                                  df_cur['latitude'],
                                  clip_on=True,
                                  transform=ccrs.PlateCarree(),
                                  fontsize=fonts)
        # plot the sliced values with a different color for each loop
        Temp = stationplot.plot_parameter('NW',
                                          df_cur['TT'],
                                          color=cmap(norm(x + 0.5)))
        try:
            Temp.set_path_effects([
                path_effects.Stroke(linewidth=1.5, foreground='black'),
                path_effects.Normal()
            ])
        except AttributeError:
            pass
        print('x={} done correctly '.format(x))
        index += 1
    # fontweight = 'bold'
    # More complex ex. uses custom formatter to control how sea-level pressure
    # values are plotted. This uses the standard trailing 3-digits of


# the pressure value in tenths of millibars.
    stationplot = StationPlot(ax,
                              df['longitude'].values,
                              df['latitude'].values,
                              clip_on=True,
                              transform=ccrs.PlateCarree(),
                              fontsize=fonts)
    try:
        u, v = wind_components(((df['ff'].values) * units('knots')),
                               (df['dd'].values * units.degree))
        cloud_frac = df['cloud_cover']
        if area != 'Arctic':
            stationplot.plot_barb(u, v, zorder=1000, linewidth=2)
            stationplot.plot_symbol('C', cloud_frac, sky_cover)
            # stationplot.plot_text((2, 0), df['Station'])

        for val in range(0, 2):
            wx = df[['ww', 'StationType']]
            if val == 0:
                # mask all the unmanned stations
                wx['ww'].loc[wx['StationType'] > 3] = np.nan
                wx2 = wx['ww'].fillna(00).astype(int).values.tolist()
                stationplot.plot_symbol('W', wx2, current_weather, zorder=2000)
            else:
                # mask all the manned stations
                wx['ww'].loc[(wx['StationType'] <= 3)] = np.nan
                # mask all reports smaller than 9
                # =7 is an empty symbol!
                wx['ww'].loc[wx['ww'] <= 9] = 7
                wx2 = wx['ww'].fillna(7).astype(int).values.tolist()
                stationplot.plot_symbol('W',
                                        wx2,
                                        current_weather_auto,
                                        zorder=2000)
        # print(u, v)
    except (ValueError, TypeError) as error:
        pass

    if SLP is True:
        lon = df['longitude'].loc[(df.PressureDefId == 'mean sea level')
                                  & (df.Hp <= 750)].values
        lat = df['latitude'].loc[(df.PressureDefId == 'mean sea level')
                                 & (df.Hp <= 750)].values
        xp, yp, _ = proj.transform_points(ccrs.PlateCarree(), lon, lat).T
        sea_levelp = df['SLP'].loc[(df.PressureDefId == 'mean sea level')
                                   & (df.Hp <= 750)]
        x_masked, y_masked, pres = remove_nan_observations(
            xp, yp, sea_levelp.values)
        slpgridx, slpgridy, slp = interpolate_to_grid(x_masked,
                                                      y_masked,
                                                      pres,
                                                      interp_type='cressman',
                                                      search_radius=400000,
                                                      rbf_func='quintic',
                                                      minimum_neighbors=1,
                                                      hres=100000,
                                                      rbf_smooth=100000)
        Splot_main = ax.contour(slpgridx,
                                slpgridy,
                                slp,
                                colors='k',
                                linewidths=2,
                                extent=(west, east, south, north),
                                levels=list(range(950, 1050, 10)))
        plt.clabel(Splot_main, inline=1, fontsize=12, fmt='%i')

        Splot = ax.contour(slpgridx,
                           slpgridy,
                           slp,
                           colors='k',
                           linewidths=1,
                           linestyles='--',
                           extent=(west, east, south, north),
                           levels=[
                               x for x in range(950, 1050, 1)
                               if x not in list(range(950, 1050, 10))
                           ])
        plt.clabel(Splot, inline=1, fontsize=10, fmt='%i')

    # stationplot.plot_text((2, 0), df['Station'])
    # Also plot the actual text of the station id. Instead of cardinal
    # directions, plot further out by specifying a location of 2 increments
    # in x and 0 in y.stationplot.plot_text((2, 0), df['station'])

    if (area == 'Antarctica' or area == 'Arctic'):
        plt.savefig(path + '/CURR_SYNOP_color_' + area + '.png',
                    bbox_inches='tight',
                    pad_inches=0)
    else:
        plt.savefig(path + '/CURR_SYNOP_color_' + area + '.png',
                    bbox_inches='tight',
                    transparent="True",
                    pad_inches=0)
示例#10
0
def main():
    ### START OF USER SETTINGS BLOCK ###

    # FILE/DATA SETTINGS
    # file path to input file
    datafile = '/home/jgodwin/python/sfc_observations/surface_observations.txt'
    timefile = '/home/jgodwin/python/sfc_observations/validtime.txt'
    # file path to county shapefile
    ctyshppath = '/home/jgodwin/python/sfc_observations/shapefiles/counties/countyl010g.shp'
    # file path to ICAO list
    icaopath = '/home/jgodwin/python/sfc_observations/icao_list.csv'
    icaodf = pd.read_csv(icaopath, index_col='STATION')

    # MAP SETTINGS
    # map names (doesn't go anywhere (yet), just for tracking purposes)
    maps = ['CONUS', 'Texas', 'Tropical Atlantic']
    # minimum radius allowed between points (in km)
    radius = [100.0, 50.0, 75.0]
    # map boundaries (longitude/latitude degrees)
    west = [-122, -108, -100]
    east = [-73, -93, -60]
    south = [23, 25, 10]
    north = [50, 38, 35]
    restart_projection = [True, False, True]
    # use county map? (True/False): warning, counties load slow!
    usecounties = [False, False, False]

    # OUTPUT SETTINGS
    # save directory for output
    savedir = '/var/www/html/images/'
    # filenames for output
    savenames = ['conus.png', 'texas.png', 'atlantic.png']

    # TEST MODE SETTINGS
    test = False  # True/False
    testnum = 5  # which map are you testing? corresponds to index in "maps" above

    ### END OF USER SETTING SECTION ###

    # if there are any missing weather codes, add them here
    wx_code_map.update({
        '-RADZ': 59,
        '-TS': 17,
        'VCTSSH': 80,
        '-SGSN': 77,
        'SHUP': 76,
        'FZBR': 48,
        'FZUP': 76
    })

    ### READ IN DATA / SETUP MAP ###
    # read in the valid time file
    vt = open(timefile).read()
    # read in the data
    for i in range(len(maps)):
        if test and i != testnum:
            continue
        with open(datafile) as f:
            data = pd.read_csv(f,header=0,names=['siteID','lat','lon','elev','slp','temp','sky','dpt','wx','wdr',\
                'wsp'],na_values=-99999)
            # drop rows with missing winds
            data = data.dropna(how='any', subset=['wdr', 'wsp'])

        # remove data not within our domain

        data = data[(data['lat'] >= south[i]-2.0) & (data['lat'] <= north[i]+2.0) \
            & (data['lon'] >= west[i]-2.0) & (data['lon'] <= east[i]+2.0)]

        # filter data (there seems to be one site always reporting a really anomalous temperature
        data = data[data['temp'] <= 50]

        print("Working on %s" % maps[i])
        # set up the map projection central longitude/latitude and the standard parallels
        cenlon = (west[i] + east[i]) / 2.0
        cenlat = (south[i] + north[i]) / 2.0
        sparallel = cenlat
        if cenlat > 0:
            cutoff = -30
            flip = False
        elif cenlat < 0:
            cutoff = 30
            flip = True
        # create the projection
        if restart_projection:
            proj = ccrs.LambertConformal(central_longitude=cenlon,
                                         central_latitude=cenlat,
                                         standard_parallels=[sparallel],
                                         cutoff=cutoff)
            point_locs = proj.transform_points(ccrs.PlateCarree(),
                                               data['lon'].values,
                                               data['lat'].values)
        data = data[reduce_point_density(point_locs, radius[i] * 1000)]
        # state borders
        state_boundaries = cfeature.NaturalEarthFeature(category='cultural',\
            name='admin_1_states_provinces_lines',scale='50m',facecolor='none')
        # county boundaries
        if usecounties[i]:
            county_reader = shpreader.Reader(ctyshppath)
            counties = list(county_reader.geometries())
            COUNTIES = cfeature.ShapelyFeature(counties, ccrs.PlateCarree())
        ### DO SOME CONVERSIONS ###
        # get the wind components
        u, v = wind_components(data['wsp'].values * units('knots'),
                               data['wdr'].values * units.degree)
        # convert temperature from Celsius to Fahrenheit
        data['temp'] = cToF(data['temp'])
        data['dpt'] = cToF(data['dpt'])
        # convert the cloud fraction value into a code of 0-8 (oktas) and compenate for NaN values
        cloud_frac = (8 * data['sky'])
        cloud_frac[np.isnan(cloud_frac)] = 10
        cloud_frac = cloud_frac.astype(int)
        # map weather strings to WMO codes (only use first symbol if multiple are present
        data['wx'] = data.wx.str.split('/').str[0] + ''
        wx = [
            wx_code_map[s.split()[0] if ' ' in s else s]
            for s in data['wx'].fillna('')
        ]

        # get the minimum and maximum temperatures in domain
        searchdata = data[(data['lat'] >= south[i]) & (data['lat'] <= north[i]) \
            & (data['lon'] >= west[i]) & (data['lon'] <= east[i])]
        min_temp = searchdata.loc[searchdata['temp'].idxmin()]
        max_temp = searchdata.loc[searchdata['temp'].idxmax()]
        max_dewp = searchdata.loc[searchdata['dpt'].idxmax()]

        # look up the site names for the min/max temp locations
        min_temp_loc = icaoLookup(min_temp['siteID'], icaodf)
        max_temp_loc = icaoLookup(max_temp['siteID'], icaodf)
        max_dewp_loc = icaoLookup(max_dewp['siteID'], icaodf)
        text_str = "Min temp: %.0f F at %s (%s)\nMax temp: %.0f F at %s (%s)\nMax dewpoint: %.0f F at %s (%s)"\
             % (min_temp['temp'],min_temp['siteID'],min_temp_loc,\
                max_temp['temp'],max_temp['siteID'],max_temp_loc,\
                max_dewp['dpt'],max_dewp['siteID'],max_dewp_loc)

        ### PLOTTING SECTION ###
        # change the DPI to increase the resolution
        plt.rcParams['savefig.dpi'] = 255
        # create the figure and an axes set to the projection
        fig = plt.figure(figsize=(20, 10))
        ax = fig.add_subplot(1, 1, 1, projection=proj)
        # add various map elements
        ax.add_feature(cfeature.LAND, zorder=-1)
        ax.add_feature(cfeature.OCEAN, zorder=-1)
        ax.add_feature(cfeature.LAKES, zorder=-1)
        ax.add_feature(cfeature.COASTLINE, zorder=2, edgecolor='black')
        ax.add_feature(state_boundaries, edgecolor='black')
        if usecounties[i]:
            ax.add_feature(COUNTIES,
                           facecolor='none',
                           edgecolor='gray',
                           zorder=-1)
        ax.add_feature(cfeature.BORDERS, linewidth=2, edgecolor='black')
        # set plot bounds
        ax.set_extent((west[i], east[i], south[i], north[i]))

        ### CREATE STATION PLOTS ###
        # lat/lon of the station plots
        stationplot = StationPlot(ax,data['lon'].values,data['lat'].values,clip_on=True,\
            transform=ccrs.PlateCarree(),fontsize=6)
        # plot the temperature and dewpoint
        stationplot.plot_parameter('NW', data['temp'], color='red')
        stationplot.plot_parameter('SW', data['dpt'], color='darkgreen')
        # plot the SLP using the standard trailing three digits
        stationplot.plot_parameter(
            'NE', data['slp'], formatter=lambda v: format(10 * v, '.0f')[-3:])
        # plot the sky condition
        stationplot.plot_symbol('C', cloud_frac, sky_cover)
        # plot the present weather
        stationplot.plot_symbol('W', wx, current_weather)
        # plot the wind barbs
        stationplot.plot_barb(u, v, flip_barb=flip)
        # plot the text of the station ID
        stationplot.plot_text((2, 0), data['siteID'])
        # plot the valid time
        plt.title('Surface Observations valid %s' % vt)
        # plot the min/max temperature info and draw circle around warmest and coldest obs
        props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
        plt.text(west[i],
                 south[i],
                 text_str,
                 fontsize=12,
                 verticalalignment='top',
                 bbox=props,
                 transform=ccrs.Geodetic())
        projx1, projy1 = proj.transform_point(min_temp['lon'], min_temp['lat'],
                                              ccrs.Geodetic())
        ax.add_patch(
            matplotlib.patches.Circle(xy=[projx1, projy1],
                                      radius=50000,
                                      facecolor="None",
                                      edgecolor='blue',
                                      linewidth=3,
                                      transform=proj))
        projx2, projy2 = proj.transform_point(max_temp['lon'], max_temp['lat'],
                                              ccrs.Geodetic())
        ax.add_patch(
            matplotlib.patches.Circle(xy=[projx2, projy2],
                                      radius=50000,
                                      facecolor="None",
                                      edgecolor='red',
                                      linewidth=3,
                                      transform=proj))
        projx3, projy3 = proj.transform_point(max_dewp['lon'], max_dewp['lat'],
                                              ccrs.Geodetic())
        ax.add_patch(
            matplotlib.patches.Circle(xy=[projx3, projy3],
                                      radius=30000,
                                      facecolor="None",
                                      edgecolor='green',
                                      linewidth=3,
                                      transform=proj))
        # save the figure
        outfile_name = savedir + savenames[i]
        plt.savefig(outfile_name, bbox_inches='tight')

        # clear and close everything
        fig.clear()
        ax.clear()
        plt.close(fig)
        f.close()

    print("Script finished.")
def plot_station_data(date, site, sitetitle, df):
    '''Given site station ID, the title of that site, and a dataframe of ASOS observation data from the last 3 days,
    returns a plot of the last 3-days of weather at that site. 
    
    Parameters: 
    site (str): string of ASOS station ID
    sitetitle (str): string of ASOS station full name 
    df (dataframe): dataframe containing last 72 hours (3 days) of ASOS station data 
    
    Returns: 
    None
    
    *saves plots to plot_dir listed near top of script*
    '''
    #if isinstance(df, int): #Returns if the station is not reporting
    #    return

    if df.empty:
        print('dataframe is empty -- go to next plot')
        return

    lower_site = site.lower()
    timestamp_end = str(df.index[-1].strftime('%Y%m%d%H%M'))
    dt = df.index[:]
    dt_array = np.array(dt.values)
    graphtimestamp_start = dt[0].strftime("%m/%d/%y")
    graphtimestamp = dt[-1].strftime("%m/%d/%y")
    #now = datetime.datetime.utcnow()
    now = datetime.strptime(date, '%Y%m%d')
    today_date = dt[-1].strftime('%Y%m%d')
    markersize = 1.5
    linewidth = 1.0

    #make figure and axes
    fig = plt.figure()
    fig.set_size_inches(18, 10)
    if 'snow_depth_set_1' in df.keys():  #six axes if snow depth
        ax1 = fig.add_subplot(6, 1, 1)
        ax2 = fig.add_subplot(6, 1, 2, sharex=ax1)
        ax3 = fig.add_subplot(6, 1, 3, sharex=ax1)
        ax4 = fig.add_subplot(6, 1, 4, sharex=ax1)
        ax5 = fig.add_subplot(6, 1, 5, sharex=ax1)
        ax6 = fig.add_subplot(6, 1, 6, sharex=ax1)
        ax6.set_xlabel('Time (UTC)')
    else:
        ax1 = fig.add_subplot(5, 1, 1)  #five axes if no snow depth
        ax2 = fig.add_subplot(5, 1, 2, sharex=ax1)
        ax3 = fig.add_subplot(5, 1, 3, sharex=ax1)
        ax4 = fig.add_subplot(5, 1, 4, sharex=ax1)
        ax5 = fig.add_subplot(5, 1, 5, sharex=ax1)
        ax5.set_xlabel('Time (UTC)')

    #ax1.set_title(site+' '+sitetitle+' '+graphtimestamp_start+' - '+graphtimestamp+' '+now.strftime("%H:%MZ"))
    ax1.set_title(site + ' ' + sitetitle + ' ' + graphtimestamp_start + ' - ' +
                  graphtimestamp)

    #------------------
    #plot airT and dewT
    #------------------
    if 'tmpc' in df.keys():
        airT = df['tmpc']
        airT_new = airT.dropna()
        airT_list = list(airT_new.values)
        airT_dt_list = []
        for i in range(0, len(airT)):
            if pd.isnull(airT[i]) == False:
                airT_dt_list.append(dt[i])
        #ax1.plot_date(airT_dt_list,airT_list,'o-',label="Temp",color="blue",linewidth=linewidth,markersize=markersize)
        ax1.plot_date(airT_dt_list,
                      airT_list,
                      linestyle='solid',
                      label="Temp",
                      color="blue",
                      linewidth=linewidth,
                      marker='None')
        #ax1.plot_date(dt,airT,'-',label="Temp",color="blue",linewidth=linewidth)
    if 'dwpc' in df.keys():
        dewT = df['dwpc']
        dewT_new = dewT.dropna()
        dewT_list = list(dewT_new.values)
        dewT_dt_list = []
        for i in range(0, len(dewT)):
            if pd.isnull(dewT[i]) == False:
                dewT_dt_list.append(dt[i])
        #ax1.plot_date(dewT_dt_list,dewT_list,'o-',label="Dew Point",color="black",linewidth=linewidth,markersize=markersize)
        ax1.plot_date(dewT_dt_list,
                      dewT_list,
                      linestyle='solid',
                      label="Dew Point",
                      color="black",
                      linewidth=linewidth,
                      marker='None')
    if ax1.get_ylim()[0] < 0 < ax1.get_ylim()[1]:
        ax1.axhline(0, linestyle='-', linewidth=1.0, color='deepskyblue')
        trans = transforms.blended_transform_factory(
            ax1.get_yticklabels()[0].get_transform(), ax1.transData)
        ax1.text(0,
                 0,
                 '0C',
                 color="deepskyblue",
                 transform=trans,
                 ha="right",
                 va="center")  #light blue line at 0 degrees C
    ax1.set_ylabel('Temp ($^\circ$C)')
    ax1.legend(loc='best', ncol=2)
    axes = [ax1]  #begin axes

    #----------------------------
    #plotting wind speed and gust
    #----------------------------
    if 'sknt' in df.keys():
        wnd_spd = df['sknt']
        #ax2.plot_date(dt,wnd_spd,'o-',label='Speed',color="forestgreen",linewidth=linewidth,markersize=markersize)
        ax2.plot_date(dt,
                      wnd_spd,
                      linestyle='solid',
                      label='Speed',
                      color="forestgreen",
                      linewidth=linewidth,
                      marker='None')
    if 'gust' in df.keys():
        wnd_gst = df['gust']
        max_wnd_gst = wnd_gst.max(skipna=True)
        ax2.plot_date(dt,
                      wnd_gst,
                      'o-',
                      label='Gust (Max ' + str(round(max_wnd_gst, 1)) + 'kt)',
                      color="red",
                      linewidth=0.0,
                      markersize=markersize)
    ax2.set_ylabel('Wind (kt)')
    ax2.legend(loc='best', ncol=2)
    axes.append(ax2)

    #-----------------------
    #plotting wind direction
    #-----------------------
    if 'drct' in df.keys():
        wnd_dir = df['drct']
        wnd_dir_new = wnd_dir.dropna()
        wnd_dir_list = list(wnd_dir_new.values)
        wnd_dir_dt_list = []
        for i in range(0, len(wnd_dir)):
            if pd.isnull(wnd_dir[i]) == False:
                wnd_dir_dt_list.append(dt[i])
        #ax3.plot_date(dt,wnd_dir,'o-',label='Direction',color="purple",linewidth=0.2, markersize=markersize)
        #ax3.plot_date(wnd_dir_dt_list,wnd_dir_list,'o-',label='Direction',color="purple",linewidth=0.2, markersize=markersize)
        ax3.plot_date(wnd_dir_dt_list,
                      wnd_dir_list,
                      linestyle='solid',
                      label='Direction',
                      color="purple",
                      linewidth=linewidth,
                      marker='None')
    ax3.set_ylim(-10, 370)
    ax3.set_ylabel('Wind Direction')
    ax3.set_yticks([0, 90, 180, 270, 360])
    axes.append(ax3)

    #-------------
    #plotting MSLP
    #-------------
    if 'mslp' in df.keys():
        mslp = df['mslp']
        mslp_new = mslp.dropna()
        mslp_list = list(mslp_new.values)
        mslp_dt_list = []
        for i in range(0, len(mslp)):
            if pd.isnull(mslp[i]) == False:
                mslp_dt_list.append(dt[i])
        max_mslp = mslp.max(skipna=True)
        min_mslp = mslp.min(skipna=True)
        labelname = 'Min ' + str(round(min_mslp, 1)) + 'hPa, Max ' + str(
            round(max_mslp, 2)) + 'hPa'
        #ax4.plot_date(mslp_dt_list,mslp_list,'o-',label=labelname,color='darkorange',linewidth=linewidth,markersize=markersize)
        ax4.plot_date(mslp_dt_list,
                      mslp_list,
                      linestyle='solid',
                      label=labelname,
                      color='darkorange',
                      linewidth=linewidth,
                      marker='None')
    ax4.legend(loc='best')
    ax4.set_ylabel('MSLP (hPa)')
    ax4.set_xlabel('Time (UTC)')
    axes.append(ax4)

    #-------------------------------------------
    #plotting precip accumulation & precip types
    #-------------------------------------------

    # Move date_time from index to column
    df = df.reset_index()

    if 'p01m' in df.keys():
        df['p01m'] = df['p01m'].fillna(0)
        last_val = df.iloc[0]['p01m']
        last_time = df.iloc[0]['time']
        last_hour = last_time.strftime('%H')
        last_minute = last_time.strftime('%M')
        precip_inc = [last_val]
        precip_accum = 0.0
        precip_accum_list = [last_val]
        num_ge_55_for_curr_hour = 0

        for index in range(1, len(df)):
            #for index in range(1,12):
            val = df.iloc[index]['p01m']
            time = df.iloc[index]['time']
            hour = time.strftime('%H')
            minute = time.strftime('%M')
            #print('LAST: val=',last_val,' hour=',last_hour,' minute=',last_minute)
            #print('CURR: val=',val,' hour=',hour,' minute=',minute)
            if hour != last_hour:
                num_ge_55_for_curr_hour = 0

            #if val == last_val:
            #    increment = 0.0
            #else:
            #    #if last_minute == '53':
            #    if last_minute > '50' and last_minute < '55':
            #        increment = val
            #    else:
            #        increment = val-last_val

            if minute >= '55':
                if num_ge_55_for_curr_hour == 0:
                    increment = val
                else:
                    if val > last_val:
                        increment = val - last_val
                    else:
                        increment = 0
                num_ge_55_for_curr_hour = num_ge_55_for_curr_hour + 1
            else:
                if val == last_val:
                    increment = 0
                else:
                    if val > last_val:
                        increment = val - last_val
                    else:
                        increment = 0

            precip_accum = precip_accum + increment
            precip_accum_list.append(precip_accum)
            precip_inc.append(increment)
            last_val = val
            last_hour = hour
            last_minute = minute
        #df['p01m_mod'] = precip_inc
        max_precip = sum(precip_inc)
        # max_precip is also precip_accum_list[-1]
        #p01m_mod = list(df['p01m_mod'].values)
        p01m_mod_dt = list(df['time'].values)

        #max_precip = max(precip_accum_list)
        labelname = 'Precip (' + str(round(max_precip, 2)) + 'mm)'
        #ax5.plot_date(p01m_mod_dt,precip_accum_list,'o-',label=labelname,color='navy',linewidth=linewidth,markersize=markersize)
        ax5.plot_date(p01m_mod_dt,
                      precip_accum_list,
                      linestyle='solid',
                      label=labelname,
                      color='navy',
                      linewidth=linewidth,
                      marker='None')
        if max_precip > 0:
            ax5.set_ylim(-0.1 * max_precip, max_precip + max_precip * 0.2)
        else:
            ax5.set_ylim(-0.1, 0.5)

    # Add weather_code info to plot
    if 'wxcodes' in df.keys():
        df['wxcodes'] = df['wxcodes'].fillna('')
        wxcodes_wto = []
        for index in range(0, len(df)):
            time = df.iloc[index]['time']
            minute = time.strftime('%M')
            #if minute == '53':
            if minute > '50' and minute < '55':
                # convert alphanumeric code to wto code number
                wxcodes = df.iloc[index]['wxcodes']

                # Added in a check in case of unexpected weather codes
                # Used to resolve case when code set to -FZRAGR instead of -FZRA GR
                # Unidata says this will work as well:
                #   wxcode_num = wx_code_map.get(wxcodes.split()[0], 0)
                # Here is reference: https://docs.python.org/3/library/stdtypes.html#dict.get
                if len(wxcodes) > 0 and wxcodes.split()[0] in wx_codes.keys():
                    wxcode_num = wx_code_map[wxcodes.split()[0]]
                else:
                    wxcode_num = 0

            else:
                wxcode_num = 0
            wxcodes_wto.append(wxcode_num)
        #df['wxcodes_wto'] = wxcode_wto
        #wxcodes_wto = list(df['wxcodes_wto'].values)
        wxcodes_wto_dt = list(df['time'].values)

        if max_precip > 0:
            dummy_y_vals = np.ones(len(wxcodes_wto)) * (0.10 * max_precip)
        else:
            dummy_y_vals = np.ones(len(wxcodes_wto)) * (0.10 * 0.5)

        sp = StationPlot(ax5, wxcodes_wto_dt, dummy_y_vals)
        #ax.plot(dates, temps)
        sp.plot_symbol('C',
                       wxcodes_wto,
                       current_weather,
                       fontsize=16,
                       color='red')
        #sp.plot_symbol('C', wxcodes_wto, current_weather, fontsize=14, color='red')

    ax5.legend(loc='best')
    ax5.set_ylabel('Precip (mm)')
    axes.append(ax5)

    # Axes formatting
    for ax in axes:
        ax.spines["top"].set_visible(
            False)  #darker borders on the grids of each subplot
        ax.spines["right"].set_visible(False)
        ax.spines["left"].set_visible(False)
        ax.spines["bottom"].set_visible(False)
        ax.tick_params(axis='x', which='both', bottom='on',
                       top='off')  #add ticks at labeled times
        ax.tick_params(axis='y', which='both', left='on', right='off')

        ax.xaxis.set_major_locator(DayLocator())
        ax.xaxis.set_major_formatter(DateFormatter('%b-%d'))

        ax.xaxis.set_minor_locator(HourLocator(np.linspace(6, 18, 3)))
        ax.xaxis.set_minor_formatter(DateFormatter('%H'))
        ax.fmt_xdata = DateFormatter('Y%m%d%H%M%S')
        ax.yaxis.grid(linestyle='--')
        ax.get_yaxis().set_label_coords(-0.06, 0.5)

    # Write plot to file
    plot_path = plot_dir + '/' + today_date
    if not os.path.exists(plot_path):
        os.makedirs(plot_path)
    try:
        catalogName = 'surface.Meteogram.' + timestamp_end + '.ASOS_' + asos_sites[
            lower_site] + '.png'
        #plt.savefig(plot_path+'/ops.asos.'+timestamp_end+'.'+lower_site+'.png',bbox_inches='tight')
        plt.savefig(plot_path + '/' + catalogName, bbox_inches='tight')
    except:
        print("Problem saving figure for %s. Usually a maxticks problem" %
              site)
    plt.close()

    # DON'T NEED THIS CHECK FOR RT PROCESSING
    # ftp plot if in asos_for_cat list
    #if lower_site in asos_for_cat:

    # Open ftp connection
    if test:
        catalogFTP = FTP(ftpCatalogServer, ftpCatalogUser, ftpCatalogPassword)
        catalogFTP.cwd(catalogDestDir)
    else:
        catalogFTP = FTP(ftpCatalogServer, ftpCatalogUser)
        catalogFTP.cwd(catalogDestDir)

    catalogFTP.set_pasv(False)

    # ftp image
    ftpFile = open(os.path.join(plot_path, catalogName), 'rb')
    catalogFTP.storbinary('STOR ' + catalogName, ftpFile)
    ftpFile.close()

    # Close ftp connection
    catalogFTP.quit()
def plot_station_data(date,site,sitetitle,df):
    '''Given site station ID, the title of that site, and a dataframe of ASOS observation data from the last 3 days,
    returns a plot of the last 3-days of weather at that site. 
    
    Parameters: 
    site (str): string of ASOS station ID
    sitetitle (str): string of ASOS station full name 
    df (dataframe): dataframe containing last 72 hours (3 days) of ASOS station data 
    
    Returns: 
    None
    
    *saves plots to plot_dir listed near top of script*
    '''
    if isinstance(df, int): #Returns if the station is not reporting
        return
    
    lower_site = site.lower()
    timestamp_end=str(df.index[-1].strftime('%Y%m%d%H%M'))
    dt = df.index[:]
    dt_array = np.array(dt.values)
    graphtimestamp_start=dt[0].strftime("%m/%d/%y") 
    graphtimestamp=dt[-1].strftime("%m/%d/%y")      
    #now = datetime.datetime.utcnow()
    now = datetime.strptime(date,'%Y%m%d')
    today_date = dt[-1].strftime('%Y%m%d')
    markersize = 1.5
    linewidth = 1.0

    #make figure and axes
    fig = plt.figure()
    fig.set_size_inches(18,10)
    if 'snow_depth_set_1' in df.keys():          #six axes if snow depth 
        ax1 = fig.add_subplot(6,1,1)
        ax2 = fig.add_subplot(6,1,2,sharex=ax1)
        ax3 = fig.add_subplot(6,1,3,sharex=ax1)
        ax4 = fig.add_subplot(6,1,4,sharex=ax1)
        ax5 = fig.add_subplot(6,1,5,sharex=ax1)
        ax6 = fig.add_subplot(6,1,6,sharex=ax1)
        ax6.set_xlabel('Time (UTC)')
    else:
        ax1 = fig.add_subplot(5,1,1)             #five axes if no snow depth
        ax2 = fig.add_subplot(5,1,2,sharex=ax1)
        ax3 = fig.add_subplot(5,1,3,sharex=ax1)
        ax4 = fig.add_subplot(5,1,4,sharex=ax1)
        ax5 = fig.add_subplot(5,1,5,sharex=ax1)
        ax5.set_xlabel('Time (UTC)')
    
    #ax1.set_title(site+' '+sitetitle+' '+graphtimestamp_start+' - '+graphtimestamp+' '+now.strftime("%H:%MZ"))
    ax1.set_title(site+' '+sitetitle+' '+graphtimestamp_start+' - '+graphtimestamp)

    #------------------
    #plot airT and dewT
    #------------------
    if 'tmpc' in df.keys():
        airT = df['tmpc']
        airT_new = airT.dropna()
        airT_list = list(airT_new.values)
        airT_dt_list = []
        for i in range(0,len(airT)):
            if pd.isnull(airT[i]) == False:
                airT_dt_list.append(dt[i])
        ax1.plot_date(airT_dt_list,airT_list,'o-',label="Temp",color="blue",linewidth=linewidth,markersize=markersize)  
        #ax1.plot_date(dt,airT,'-',label="Temp",color="blue",linewidth=linewidth)  
    if 'dwpc' in df.keys():
        dewT = df['dwpc']
        dewT_new = dewT.dropna()
        dewT_list = list(dewT_new.values)
        dewT_dt_list = []
        for i in range(0,len(dewT)):
            if pd.isnull(dewT[i]) == False:
                dewT_dt_list.append(dt[i])
        ax1.plot_date(dewT_dt_list,dewT_list,'o-',label="Dew Point",color="black",linewidth=linewidth,markersize=markersize)
    if ax1.get_ylim()[0] < 0 < ax1.get_ylim()[1]:
        ax1.axhline(0, linestyle='-', linewidth = 1.0, color='deepskyblue')
        trans = transforms.blended_transform_factory(ax1.get_yticklabels()[0].get_transform(), ax1.transData)
        ax1.text(0,0,'0C', color="deepskyblue", transform=trans, ha="right", va="center") #light blue line at 0 degrees C
    ax1.set_ylabel('Temp ($^\circ$C)')
    ax1.legend(loc='best',ncol=2)
    axes = [ax1]                             #begin axes

    #----------------------------
    #plotting wind speed and gust
    #----------------------------
    if 'sknt' in df.keys():
        wnd_spd = df['sknt']
        ax2.plot_date(dt,wnd_spd,'o-',label='Speed',color="forestgreen",linewidth=linewidth,markersize=markersize)
    if 'gust' in df.keys():
        wnd_gst = df['gust']
        max_wnd_gst = wnd_gst.max(skipna=True)
        ax2.plot_date(dt,wnd_gst,'o-',label='Gust (Max ' + str(round(max_wnd_gst,1)) + 'kt)',color="red",linewidth=0.0,markersize=markersize) 
    ax2.set_ylabel('Wind (kt)')
    ax2.legend(loc='best',ncol=2)
    axes.append(ax2)
    
    #-----------------------
    #plotting wind direction
    #-----------------------
    if 'drct' in df.keys():
        wnd_dir = df['drct']
        ax3.plot_date(dt,wnd_dir,'o-',label='Direction',color="purple",linewidth=0.2, markersize=markersize)
    ax3.set_ylim(-10,370)
    ax3.set_ylabel('Wind Direction')
    ax3.set_yticks([0,90,180,270,360])
    axes.append(ax3)
    
    #-------------
    #plotting MSLP
    #-------------
    if 'mslp' in df.keys():
        mslp = df['mslp']
        mslp_new = mslp.dropna()
        mslp_list = list(mslp_new.values)
        mslp_dt_list = []
        for i in range(0,len(mslp)):
            if pd.isnull(mslp[i]) == False:
                mslp_dt_list.append(dt[i])
        max_mslp = mslp.max(skipna=True)
        min_mslp = mslp.min(skipna=True)
        labelname = 'Min ' + str(round(min_mslp,1)) + 'hPa, Max ' + str(round(max_mslp,2)) + 'hPa'
        ax4.plot_date(mslp_dt_list,mslp_list,'o-',label=labelname,color='darkorange',linewidth=linewidth,markersize=markersize)
    ax4.legend(loc='best')
    ax4.set_ylabel('MSLP (hPa)')
    ax4.set_xlabel('Time (UTC)')
    axes.append(ax4)
    
    #-------------------------------------------
    #plotting precip accumulation & precip types
    #-------------------------------------------        

    # Move date_time from index to column
    df = df.reset_index()

    # MODIFY THIS SO THAT WHEN READINGS COME IN WE KEEP THEM INSTEAD OF JUST ACCEPTING HOURLY ACCUMS
    # WILL MAKE PLOT LESS CHOPPY
    # Plot precip time series (use only values at minute 53)
    if 'p01m' in df.keys():
        df['p01m'] = df['p01m'].fillna(0)
        precip_inc = list(df['p01m'].values)
        precip_inc_dt = list(df['date_time'].values)

        precip_accum = 0.0
        precip_accum_list = []
        precip_dt_list = []
        precip_accum_indices = []
        
        for i in range(0,len(precip_inc)):
            time_obj = pd.to_datetime(precip_inc_dt[i])
            minutes = time_obj.strftime('%M')
            if minutes == '53':
                precip_accum = precip_accum + precip_inc[i]
                precip_accum_list.append(precip_accum)
                precip_dt_list.append(precip_inc_dt[i])
                precip_accum_indices.append(i)
        times = precip_dt_list
        precip_accums = precip_accum_list

        """
        precip_accum = 0.0
        precip_accum_list = []
        last_increment = df.loc[0].p01m
        precip_accum_indices = []

        for index in range(1,len(df)):
            if df.loc[index].p01m < last_increment:
                precip_accum = precip_accum + last_increment
                precip_accum_list.append(precip_accum)
                precip_accum_indices.append(index)
            else:
                precip_accum_list.append(precip_accum)
            last_increment = df.loc[index].p01m
        # append last element in dataframe in case there's some precip there
        precip_accum = precip_accum + last_increment
        precip_accum_list.append(precip_accum)
        # values to use for the plot
        times = [precip_dt_list[i] for i in precip_accum_indices]
        precip_accums = [precip_accum_list[i] for i in precip_accum_indices]
        """
                       
        max_precip = max(precip_accum_list)
        labelname = 'Precip (' + str(round(max_precip,2)) + 'mm)'
        ax5.plot_date(precip_dt_list,precip_accum_list,'o-',label=labelname,color='navy',linewidth=linewidth,markersize=markersize)
        if max_precip > 0:
            ax5.set_ylim(-0.1*max_precip,max_precip+max_precip*0.2)
        else:
            ax5.set_ylim(-0.5,5)
            
    # Add weather_code info to plot
    if 'wxcodes' in df.keys():
        df['wxcodes'] = df['wxcodes'].fillna('')
        wxcodes_list = list(df['wxcodes'].values)
        #wxcodes_dt_list = list(df['date_time'].values)
        wxcodes_num_list = []
        for i in range(0,len(wxcodes_list)):
            wxcodes = wxcodes_list[i]
            if len(wxcodes) > 0:
                wxcode_wto = wx_code_map[wxcodes.split()[0]]
            else:
                wxcode_wto = 0
            wxcodes_num_list.append(wxcode_wto)
        wxcodes = [wxcodes_num_list[i] for i in precip_accum_indices]
        # Set y values for weather symbols on plot
        dummy_y_vals = np.ones(len(wxcodes)) * (0.10*max_precip)  

        sp = StationPlot(ax5, times, dummy_y_vals)
        #ax.plot(dates, temps)
        #sp.plot_symbol('C', wxcodes, current_weather, fontsize=16, color='red')
        sp.plot_symbol('C', wxcodes, current_weather, fontsize=14, color='red')
        
        """
        wxcodes_num_list_hrly = []
        wxcodes_dt_list_hrly = []
        for i in range(0,len(wxcodes_num_list)):
            time_obj = pd.to_datetime(wxcodes_dt_list[i])
            minutes = time_obj.strftime('%M')
            if minutes == '00':
                wxcodes_num_list_hrly.append(wxcodes_num_list[i])
                wxcodes_dt_list_hrly.append(wxcodes_dt_list[i])
        dummy_y_vals = np.zeros(len(wxcodes_num_list_hrly))  # only to place on plot
        sp = StationPlot(ax5, wxcodes_dt_list_hrly, dummy_y_vals)
        #ax5.plot(precip_dt_list,precip_accum_list)
        sp.plot_symbol('C', wxcodes_num_list_hrly, current_weather, fontsize=16, color='red')
        """

    ax5.legend(loc='best')
    ax5.set_ylabel('Precip (mm)')
    axes.append(ax5)

    """
    #-------------------
    #plotting snow depth
    #-------------------
    if 'snow_depth_set_1' in df.keys():
        snow_depth = df['snow_depth_set_1']
        snow_depth_new = snow_depth.dropna()
        snow_depth_dt_list = []
        for i in range(0,len(snow_depth)):
            if pd.isnull(snow_depth[i]) == False:
                snow_depth_dt_list.append(dt[i])  
        max_snow_depth = snow_depth.max(skipna=True)
        min_snow_depth = snow_depth.min(skipna=True)
        labelname = 'Min Depth ' + str(round(min_snow_depth,2)) + 'mm, Max Depth ' + str(round(max_snow_depth,2)) + 'mm'
        ax6.plot_date(snow_depth_dt_list,snow_depth_new,'o-',label=labelname,color='deepskyblue',linewidth=linewidth,markersize=markersize)
        if max_snow_depth > 0:
            ax6.set_ylim(-0.1*max_snow_depth,max_snow_depth+max_snow_depth*0.2)
        else:
            ax6.set_ylim(-0.5,5)
        ax6.legend(loc='best')
        ax6.set_ylabel('Snow Depth (mm)')
        axes.append(ax6)
    """

    # Axes formatting
    for ax in axes: 
        ax.spines["top"].set_visible(False)  #darker borders on the grids of each subplot
        ax.spines["right"].set_visible(False)  
        ax.spines["left"].set_visible(False)
        ax.spines["bottom"].set_visible(False)
        ax.tick_params(axis='x',which='both',bottom='on',top='off')     #add ticks at labeled times
        ax.tick_params(axis='y',which='both',left='on',right='off') 

        ax.xaxis.set_major_locator( DayLocator() )
        ax.xaxis.set_major_formatter( DateFormatter('%b-%d') )
        
        ax.xaxis.set_minor_locator( HourLocator(np.linspace(6,18,3)) )
        ax.xaxis.set_minor_formatter( DateFormatter('%H') )
        ax.fmt_xdata = DateFormatter('Y%m%d%H%M%S')
        ax.yaxis.grid(linestyle = '--')
        ax.get_yaxis().set_label_coords(-0.06,0.5)

    # Write plot to file
    plot_path = plot_dir+'/'+today_date
    if not os.path.exists(plot_path):
            os.makedirs(plot_path)
    try:
        plt.savefig(plot_path+'/ops.asos.'+timestamp_end+'.'+lower_site+'.png',bbox_inches='tight')
    except:
        print("Problem saving figure for %s. Usually a maxticks problem" %site)
    plt.close()
示例#13
0
def uaPlot(data, level, date, save_dir, ds, td_option):

    custom_layout = StationPlotLayout()
    custom_layout.add_barb('eastward_wind', 'northward_wind', units='knots')
    custom_layout.add_value('NW',
                            'air_temperature',
                            fmt='.0f',
                            units='degC',
                            color='darkred')

    # Geopotential height and smooth
    hght = ds.Geopotential_height_isobaric.metpy.sel(
        vertical=level * units.hPa,
        time=date,
        lat=slice(85, 15),
        lon=slice(360 - 200, 360 - 10))
    smooth_hght = mpcalc.smooth_n_point(hght, 9, 10)

    # Temperature, smooth, and convert to Celsius
    tmpk = ds.Temperature_isobaric.metpy.sel(vertical=level * units.hPa,
                                             time=date,
                                             lat=slice(85, 15),
                                             lon=slice(360 - 200, 360 - 10))
    smooth_tmpc = (mpcalc.smooth_n_point(tmpk, 9, 10)).to('degC')

    #Calculate Theta-e
    rh = ds.Relative_humidity_isobaric.metpy.sel(vertical=level * units.hPa,
                                                 time=date,
                                                 lat=slice(85, 15),
                                                 lon=slice(
                                                     360 - 200, 360 - 10))
    td = mpcalc.dewpoint_from_relative_humidity(tmpk, rh)
    te = mpcalc.equivalent_potential_temperature(level * units.hPa, tmpk, td)
    smooth_te = mpcalc.smooth_n_point(te, 9, 10)

    #decide on the height format based on the level
    if level == 250:
        custom_layout.add_value('NE',
                                'height',
                                fmt=lambda v: format(v, '1')[1:4],
                                units='m',
                                color='black')
        cint = 120
        tint = 5
    if level == 300:
        custom_layout.add_value('NE',
                                'height',
                                fmt=lambda v: format(v, '1')[1:4],
                                units='m',
                                color='black')
        cint = 120
        tint = 5
    if level == 500:
        custom_layout.add_value('NE',
                                'height',
                                fmt=lambda v: format(v, '1')[0:3],
                                units='m',
                                color='black')
        cint = 60
        tint = 5
    if level == 700:
        custom_layout.add_value('NE',
                                'height',
                                fmt=lambda v: format(v, '1')[1:4],
                                units='m',
                                color='black')
        custom_layout.add_value('SW', 'tdd', units='degC', color='green')
        custom_layout.add_value('SE', 'thetae', units='degK', color='orange')
        temps = 'Tdd, and Theta-e'
        cint = 30
        tint = 4
    if level == 850:
        custom_layout.add_value('NE',
                                'height',
                                fmt=lambda v: format(v, '1')[1:4],
                                units='m',
                                color='black')
        if td_option == True:
            custom_layout.add_value('SW',
                                    'dew_point_temperature',
                                    units='degC',
                                    color='green')
            temps = 'Td, and Theta-e'
        if td_option == False:
            custom_layout.add_value('SW', 'tdd', units='degC', color='green')
            temps = 'Tdd, and Theta-e'
        # custom_layout.add_value('SW', 'tdd', units='degC', color='green')
        # temps = 'Tdd, and Theta-e'
        custom_layout.add_value('SE', 'thetae', units='degK', color='orange')
        cint = 30
        tint = 4
    if level == 925:
        custom_layout.add_value('NE',
                                'height',
                                fmt=lambda v: format(v, '1')[1:4],
                                units='m',
                                color='black')
        if td_option == True:
            custom_layout.add_value('SW',
                                    'dew_point_temperature',
                                    units='degC',
                                    color='green')
            temps = 'Td, and Theta-e'
        if td_option == False:
            custom_layout.add_value('SW', 'tdd', units='degC', color='green')
            temps = 'Tdd, and Theta-e'
        custom_layout.add_value('SE', 'thetae', units='degK', color='orange')
        cint = 30
        tint = 4

    globe = ccrs.Globe(ellipse='sphere',
                       semimajor_axis=6371200.,
                       semiminor_axis=6371200.)
    proj = ccrs.Stereographic(central_longitude=-105.,
                              central_latitude=90.,
                              globe=globe,
                              true_scale_latitude=60)
    # Plot the image
    fig = plt.figure(figsize=(40, 40))
    ax = fig.add_subplot(1, 1, 1, projection=proj)
    state_boundaries = feat.NaturalEarthFeature(
        category='cultural',
        name='admin_1_states_provinces_lines',
        scale='10m',
        facecolor='none')
    coastlines = feat.NaturalEarthFeature('physical',
                                          'coastline',
                                          '50m',
                                          facecolor='none')
    lakes = feat.NaturalEarthFeature('physical',
                                     'lakes',
                                     '50m',
                                     facecolor='none')
    countries = feat.NaturalEarthFeature('cultural',
                                         'admin_0_countries',
                                         '50m',
                                         facecolor='none')
    ax.add_feature(state_boundaries, zorder=2, edgecolor='grey')
    ax.add_feature(lakes, zorder=2, edgecolor='grey')
    ax.add_feature(coastlines, zorder=2, edgecolor='grey')
    ax.add_feature(lakes, zorder=2, edgecolor='grey')
    ax.add_feature(countries, zorder=2, edgecolor='grey')
    ax.coastlines(resolution='50m', zorder=2, color='grey')
    ax.set_extent([-132., -70, 26., 80.], ccrs.PlateCarree())

    stationData = dataDict(data)
    stationplot = StationPlot(ax,
                              stationData['longitude'],
                              stationData['latitude'],
                              transform=ccrs.PlateCarree(),
                              fontsize=22)
    custom_layout.plot(stationplot, stationData)

    # Plot Solid Contours of Geopotential Height
    cs = ax.contour(hght.lon,
                    hght.lat,
                    smooth_hght.m,
                    range(0, 20000, cint),
                    colors='black',
                    transform=ccrs.PlateCarree())
    clabels = plt.clabel(cs,
                         fmt='%d',
                         colors='white',
                         inline_spacing=5,
                         use_clabeltext=True,
                         fontsize=22)

    # Contour labels with black boxes and white text
    for t in clabels:
        t.set_bbox({'facecolor': 'black', 'pad': 4})
        t.set_fontweight('heavy')

    #Check levels for different contours
    if level == 250 or level == 300 or level == 500:
        # Plot Dashed Contours of Temperature
        cs2 = ax.contour(hght.lon,
                         hght.lat,
                         smooth_tmpc.m,
                         range(-60, 51, tint),
                         colors='red',
                         transform=ccrs.PlateCarree())
        clabels = plt.clabel(cs2,
                             fmt='%d',
                             colors='red',
                             inline_spacing=5,
                             use_clabeltext=True,
                             fontsize=22)
        # Set longer dashes than default
        for c in cs2.collections:
            c.set_dashes([(0, (5.0, 3.0))])
        temps = 'T'
    if level == 700 or level == 850 or level == 925:
        # Plot Dashed Contours of Temperature
        cs2 = ax.contour(hght.lon,
                         hght.lat,
                         smooth_te.m,
                         range(210, 360, tint),
                         colors='orange',
                         transform=ccrs.PlateCarree())
        clabels = plt.clabel(cs2,
                             fmt='%d',
                             colors='orange',
                             inline_spacing=5,
                             use_clabeltext=True,
                             fontsize=22)
        # Set longer dashes than default
        for c in cs2.collections:
            c.set_dashes([(0, (5.0, 3.0))])

    dpi = plt.rcParams['savefig.dpi'] = 255
    date = date + timedelta(hours=6)
    text = AnchoredText(str(level) + 'mb Wind, Heights, and ' + temps +
                        ' Valid: {0:%Y-%m-%d} {0:%H}:00UTC'.format(date),
                        loc=3,
                        frameon=True,
                        prop=dict(fontsize=22))
    ax.add_artist(text)
    plt.tight_layout()
    save_fname = '{0:%Y%m%d_%H}z_'.format(date) + str(level) + 'mb.pdf'
    plt.savefig(save_dir / save_fname, dpi=dpi, bbox_inches='tight')
def makeStationPlot(plotTitle, plotFileName, maxDataAge, maxLat, minLat,
                    maxLon, minLon, stationDensity, textSize, figX, figY, dpi,
                    showCountryBorders, showStateBorders, showCountyBorders):

    #
    # Data Polling

    # Get data from AWC TDS
    dataURL = "https://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=csv&minLat=" + str(
        minLat) + "&minLon=" + str(minLon) + "&maxLat=" + str(
            maxLat) + "&maxLon=" + str(maxLon) + "&hoursBeforeNow=" + str(
                maxDataAge)

    # First read in the data. We use pandas because it simplifies a lot of tasks, like dealing
    # with strings
    data = pd.read_csv(dataURL,
                       header=5,
                       usecols=(1, 3, 4, 5, 6, 7, 8, 12, 21, 22),
                       names=[
                           'stid', 'lat', 'lon', 'air_temperature',
                           'dew_point_temperature', 'wind_dir', 'wind_speed',
                           'slp', 'weather', 'cloud_fraction'
                       ],
                       na_values=-99999)

    #
    # Data Handling

    # convert T and Td from °C to °F
    data['air_temperature'] = (data['air_temperature'] * (9 / 5.0)) + 32
    data['dew_point_temperature'] = (data['dew_point_temperature'] *
                                     (9 / 5.0)) + 32

    # change sky category to %
    data['cloud_fraction'] = data['cloud_fraction'].replace(
        'SKC', 0.0).replace('CLR', 0.0).replace('CAVOK', 0.0).replace(
            'FEW', 0.1875).replace('SCT',
                                   0.4375).replace('BKN', 0.750).replace(
                                       'OVC', 1.000).replace('OVX', 1.000)

    # Drop rows with missing winds
    data = data.dropna(how='any', subset=['wind_dir', 'wind_speed'])

    # Set up the map projection
    proj = ccrs.LambertConformal(
        central_longitude=(minLon + (maxLon - minLon) / 2),
        central_latitude=(minLat + (maxLat - minLat) / 2))

    # Set station density, in x meter radius
    point_locs = proj.transform_points(ccrs.PlateCarree(), data['lon'].values,
                                       data['lat'].values)
    data = data[reduce_point_density(point_locs, stationDensity * 1000)]

    # Get the wind components, converting from m/s to knots as will be appropriate
    u, v = wind_components(
        (data['wind_speed'].values * units('m/s')).to('knots'),
        data['wind_dir'].values * units.degree)

    # Convert the fraction value into a code of 0-8 and compensate for NaN values
    cloud_frac = (8 * data['cloud_fraction'])
    cloud_frac[np.isnan(cloud_frac)] = 10
    cloud_frac = cloud_frac.astype(int)

    # Map weather strings to WMO codes. Only use the first symbol if there are multiple
    wx = [
        wx_code_map[s.split()[0] if ' ' in s else s]
        for s in data['weather'].fillna('')
    ]

    #
    # Plot Setup

    # Set DPI of the resulting figure
    plt.rcParams['savefig.dpi'] = dpi

    # Create the figure and an axes set to the projection.
    fig = plt.figure(figsize=(figX, figY))
    ax = fig.add_subplot(1, 1, 1, projection=proj)

    # Set plot bounds
    ax.set_extent((minLon, maxLon, minLat, maxLat))

    # Add geographic features
    if showCountyBorders:
        ax.add_feature(USCOUNTIES.with_scale('500k'),
                       edgecolor='gray',
                       linewidth=0.25)

    if showStateBorders:
        state_borders = cfeature.NaturalEarthFeature(
            category='cultural',
            name='admin_1_states_provinces_lakes',
            scale='50m',
            facecolor='none')
        ax.add_feature(state_borders, edgecolor='gray', linewidth=0.5)

    if showCountryBorders:
        country_borders = cfeature.NaturalEarthFeature(
            category='cultural',
            name='admin_0_countries',
            scale='50m',
            facecolor='none')
        ax.add_feature(country_borders, edgecolor='black', linewidth=0.7)

    #
    # Create Station Plots

    # Set station location, setup plot
    stationplot = StationPlot(ax,
                              data['lon'].values,
                              data['lat'].values,
                              clip_on=True,
                              transform=ccrs.PlateCarree(),
                              fontsize=textSize)

    # Plot the temperature and dew point
    stationplot.plot_parameter('NW', data['air_temperature'], color='red')
    stationplot.plot_parameter('SW',
                               data['dew_point_temperature'],
                               color='darkgreen')

    # Plot pressure data
    stationplot.plot_parameter('NE',
                               data['slp'],
                               formatter=lambda v: format(10 * v, '.0f')[-3:])

    # Plot cloud cover
    stationplot.plot_symbol('C', cloud_frac, sky_cover)

    # Plot current weather
    stationplot.plot_symbol('W', wx, current_weather)

    # Add wind barbs
    stationplot.plot_barb(u, v)

    # Plot station id
    stationplot.plot_text((2, 0), data['stid'])

    # Set a title and show the plot
    ax.set_title(plotTitle)

    # Export fig
    fig.savefig('/home/CarterHumphreys/bin/send2web/' +
                datetime.utcnow().strftime("%Y%m%d-%H00") + '_' +
                plotFileName + '.png',
                bbox_inches='tight')
    fig.savefig('/home/CarterHumphreys/bin/send2web/' + plotFileName + '.png',
                bbox_inches='tight')
示例#15
0
def plot_map_standard(proj,
                      point_locs,
                      df_t,
                      area='EU',
                      west=-9.5,
                      east=28,
                      south=35,
                      north=62,
                      fonts=14,
                      path=None,
                      SLP=False,
                      gust=False):
    if path == None:
        # set up the paths and test for existence
        path = expanduser('~') + '/Documents/Metar_plots'
        try:
            os.listdir(path)
        except FileNotFoundError:
            os.mkdir(path)
    else:
        path = path
    df = df_t.loc[(df_t['longitude'] >= west - 4)
                  & (df_t['longitude'] <= east + 4)
                  & (df_t['latitude'] <= north + 4) &
                  (df_t['latitude'] >= south - 4)]
    plt.rcParams['savefig.dpi'] = 300
    # =========================================================================
    # Create the figure and an axes set to the projection.
    fig = plt.figure(figsize=(20, 16))
    ax = fig.add_subplot(1, 1, 1, projection=proj)
    if area == 'Antarctica':
        df = df.loc[df['latitude'] < north]
        ax.set_extent([-180, 180, -90, -60], ccrs.PlateCarree())
        theta = np.linspace(0, 2 * np.pi, 100)
        center, radius = [0.5, 0.5], 0.5
        verts = np.vstack([np.sin(theta), np.cos(theta)]).T
        circle = mpath.Path(verts * radius + center)
        ax.set_boundary(circle, transform=ax.transAxes)
    elif area == 'Arctic':
        df = df.loc[df['latitude'] > south]
        ax.set_extent([-180, 180, 60, 90], ccrs.PlateCarree())
        theta = np.linspace(0, 2 * np.pi, 100)
        center, radius = [0.5, 0.5], 0.5
        verts = np.vstack([np.sin(theta), np.cos(theta)]).T
        circle = mpath.Path(verts * radius + center)
        ax.set_boundary(circle, transform=ax.transAxes)

    else:
        ax.set_extent((west, east, south, north))

    # Get the wind components, converting from m/s to knots as will
    # be appropriate for the station plot.
    df['dd'][df['dd'] > 360] = np.nan
    u, v = wind_components(df['ff'].values * units('knots'),
                           df['dd'].values * units('deg'))
    cloud_frac = df['cloud_cover']
    # Change the DPI of the resulting figure. Higher DPI drastically improves
    # look of the text rendering.

    # Set up a cartopy feature for state borders.
    # state_boundaries = feat.NaturalEarthFeature(category='cultural',
    #                                             name='admin_0_countries',
    #                                             scale='10m',
    #                                             facecolor='#d8dcd6',
    #                                             alpha=0.5)
    # ax.coastlines(resolution='10m', zorder=0, color='black')
    # ax.add_feature(feat.LAND)
    ax.add_feature(feat.COASTLINE.with_scale('10m'),
                   zorder=2,
                   edgecolor='black')
    ax.add_feature(feat.OCEAN.with_scale('50m'), zorder=0)
    ax.add_feature(feat.STATES.with_scale('10m'),
                   zorder=1,
                   facecolor='white',
                   edgecolor='#5e819d')
    # ax.add_feature(cartopy.feature.OCEAN, zorder=0)
    # Set plot bounds

    # Start the station plot by specifying the axes to draw on, as well as the
    # lon/lat of the stations (with transform). We also the fontsize to 12 pt.
    stationplot = StationPlot(ax,
                              df['longitude'].values,
                              df['latitude'].values,
                              clip_on=True,
                              transform=ccrs.PlateCarree(),
                              fontsize=fonts)
    # Plot the temperature and dew point to the upper and lower left,
    # respectively, of the center point. Each one uses a different color.
    Temp = stationplot.plot_parameter('NW',
                                      df['TT'],
                                      color='#fd3c06',
                                      fontweight='bold',
                                      zorder=3)
    Td = stationplot.plot_parameter('SW', df['TD'], color='#01ff07')

    if gust == True:
        maxff = stationplot.plot_parameter('SE',
                                           df['max_gust'],
                                           color='#cb416b',
                                           fontweight='bold',
                                           zorder=3)
        maxff.set_path_effects([
            path_effects.Stroke(linewidth=1.5, foreground='black'),
            path_effects.Normal()
        ])
    # fontweight = 'bold'
    # More complex ex. uses custom formatter to control how sea-level pressure
    # values are plotted. This uses the standard trailing 3-digits of
    # the pressure value in tenths of millibars.

    if (area != 'Antarctica' and area != 'Arctic'):
        p = stationplot.plot_parameter(
            'NE',
            df['SLP'],
            formatter=lambda v: format(10 * v, '.0f')[-3:],
            color="#a2cffe")
        for x in [Temp, Td, p]:
            x.set_path_effects([
                path_effects.Stroke(linewidth=1.5, foreground='black'),
                path_effects.Normal()
            ])
    else:
        for x in [Temp, Td]:
            x.set_path_effects([
                path_effects.Stroke(linewidth=1.5, foreground='black'),
                path_effects.Normal()
            ])

    # Add wind barbs
    stationplot.plot_barb(u, v, zorder=3, linewidth=2)
    # Plot the cloud cover symbols in the center location. This uses the codes
    # made above and uses the `sky_cover` mapper to convert these values to
    # font codes for the weather symbol font.
    stationplot.plot_symbol('C', cloud_frac, sky_cover)
    # Same this time, but plot current weather to the left of center, using the
    # `current_weather` mapper to convert symbols to the right glyphs.
    for val in range(0, 2):
        wx = df[['ww', 'StationType']]
        if val == 0:
            # mask all the unmanned stations
            wx['ww'].loc[wx['StationType'] > 3] = np.nan
            wx2 = wx['ww'].fillna(00).astype(int).values.tolist()
            stationplot.plot_symbol('W', wx2, current_weather, zorder=4)
        else:
            # mask all the manned stations
            wx['ww'].loc[(wx['StationType'] <= 3)] = np.nan
            # mask all reports smaller than 9
            # =7 is an empty symbol!
            wx['ww'].loc[wx['ww'] <= 9] = 7
            wx2 = wx['ww'].fillna(7).astype(int).values.tolist()
            stationplot.plot_symbol('W', wx2, current_weather_auto, zorder=4)
    if SLP == True:
        lon = df['longitude'].loc[(df.PressureDefId == 'mean sea level')
                                  & (df.Hp <= 750)].values
        lat = df['latitude'].loc[(df.PressureDefId == 'mean sea level')
                                 & (df.Hp <= 750)].values
        xp, yp, _ = proj.transform_points(ccrs.PlateCarree(), lon, lat).T
        sea_levelp = df['SLP'].loc[(df.PressureDefId == 'mean sea level')
                                   & (df.Hp <= 750)]
        x_masked, y_masked, pres = remove_nan_observations(
            xp, yp, sea_levelp.values)
        slpgridx, slpgridy, slp = interpolate_to_grid(x_masked,
                                                      y_masked,
                                                      pres,
                                                      interp_type='cressman',
                                                      search_radius=400000,
                                                      rbf_func='quintic',
                                                      minimum_neighbors=1,
                                                      hres=100000,
                                                      rbf_smooth=100000)
        Splot_main = ax.contour(slpgridx,
                                slpgridy,
                                slp,
                                colors='k',
                                linewidths=2,
                                extent=(west, east, south, north),
                                levels=list(range(950, 1050, 10)))
        plt.clabel(Splot_main, inline=1, fontsize=12, fmt='%i')

        Splot = ax.contour(slpgridx,
                           slpgridy,
                           slp,
                           colors='k',
                           linewidths=1,
                           linestyles='--',
                           extent=(west, east, south, north),
                           levels=[
                               x for x in range(950, 1050, 1)
                               if x not in list(range(950, 1050, 10))
                           ])
        plt.clabel(Splot, inline=1, fontsize=10, fmt='%i')

    # stationplot.plot_text((2, 0), df['Station'])
    # Also plot the actual text of the station id. Instead of cardinal
    # directions, plot further out by specifying a location of 2 increments
    # in x and 0 in y.stationplot.plot_text((2, 0), df['station'])

    if (area == 'Antarctica' or area == 'Arctic'):
        plt.savefig(path + '/CURR_SYNOP_' + area + '.png',
                    bbox_inches='tight',
                    pad_inches=0)
    else:
        plt.savefig(path + '/CURR_SYNOP_' + area + '.png',
                    bbox_inches='tight',
                    transparent="True",
                    pad_inches=0)
示例#16
0
ax.coastlines(resolution='110m', zorder=2, color='black')
ax.add_feature(state_boundaries, edgecolor='black')
ax.add_feature(feat.BORDERS, linewidth='2', edgecolor='black')

# Set plot bounds
ax.set_extent((-118, -73, 23, 50))

#
# Here's the actual station plot
#

# Start the station plot by specifying the axes to draw on, as well as the
# lon/lat of the stations (with transform). We also the fontsize to 12 pt.
stationplot = StationPlot(ax,
                          data['longitude'],
                          data['latitude'],
                          transform=ccrs.PlateCarree(),
                          fontsize=12)

# The layout knows where everything should go, and things are standardized using
# the names of variables. So the layout pulls arrays out of `data` and plots them
# using `stationplot`.
simple_layout.plot(stationplot, data)

plt.show()

###########################################
# or instead, a custom layout can be used:

# Just winds, temps, and dewpoint, with colors. Dewpoint and temp will be plotted
# out to Farenheit tenths. Extra data will be ignored
示例#17
0
def radar_plus_obs(station, my_datetime, radar_title=None, bb=None,
                   station_radius=75000., station_layout=simple_layout,
                  field='reflectivity', vmin=None, vmax=None,
                  sweep=0):
    if radar_title is None:
        radar_title = 'Area '

    radar = get_radar_from_aws(station, my_datetime)

    # Lets get some geographical context
    if bb is None:
        lats = radar.gate_latitude
        lons = radar.gate_longitude

        min_lon = lons['data'].min()
        min_lat = lats['data'].min()
        max_lat = lats['data'].max()
        max_lon = lons['data'].max()
        bb = {'north' : max_lat,
              'south' : min_lat,
              'east' : max_lon,
              'west' : min_lon}
    else:
        min_lon = bb['west']
        min_lat = bb['south']
        max_lon = bb['east']
        max_lat = bb['north']

    print('min_lat:', min_lat, ' min_lon:', min_lon,
          ' max_lat:', max_lat, ' max_lon:', max_lon)

    index_at_start = radar.sweep_start_ray_index['data'][sweep]
    time_at_start_of_radar = num2date(radar.time['data'][index_at_start],
                                      radar.time['units'])
    pacific = pytz.timezone('US/Central')
    local_time = pacific.fromutc(time_at_start_of_radar)
    fancy_date_string = local_time.strftime('%A %B %d at %I:%M %p %Z')
    print(fancy_date_string)

    metar_cat = TDSCatalog('http://thredds.ucar.edu/thredds/catalog/nws/metar/ncdecoded/catalog.xml?'
                           'dataset=nws/metar/ncdecoded/Metar_Station_Data_fc.cdmr')
    dataset = list(metar_cat.datasets.values())[0]
    ncss = NCSS(dataset.access_urls["NetcdfSubset"])

    query = ncss.query().accept('csv').time(time_at_start_of_radar)
    query.lonlat_box(north=max_lat, south=min_lat, east=max_lon, west=min_lon)
    query.variables('air_temperature', 'dew_point_temperature', 'inches_ALTIM',
                    'wind_speed', 'wind_from_direction', 'cloud_area_fraction', 'weather')
    data = ncss.get_data(query)

    lats = data['latitude'][:]
    lons = data['longitude'][:]
    tair = data['air_temperature'][:]
    dewp = data['dew_point_temperature'][:]
    slp = (data['inches_ALTIM'][:] * units('inHg')).to('mbar')

    # Convert wind to components
    u, v = mpcalc.get_wind_components(data['wind_speed'] * units.knot,
                                      data['wind_from_direction'] * units.deg)

    # Need to handle missing (NaN) and convert to proper code
    cloud_cover = 8 * data['cloud_area_fraction']
    cloud_cover[np.isnan(cloud_cover)] = 9
    cloud_cover = cloud_cover.astype(np.int)

    # For some reason these come back as bytes instead of strings
    stid = [s.decode() for s in data['station']]

    # Convert the text weather observations to WMO codes we can map to symbols
    #wx_text = [s.decode('ascii') for s in data['weather']]
    #wx_codes = np.array(list(to_code(wx_text)))

    sfc_data = {'latitude': lats, 'longitude': lons,
                'air_temperature': tair, 'dew_point_temperature': dewp, 'eastward_wind': u,
                'northward_wind': v, 'cloud_coverage': cloud_cover,
                'air_pressure_at_sea_level': slp}#, 'present_weather': wx_codes}

    fig = plt.figure(figsize=(10, 8))
    display = pyart.graph.RadarMapDisplayCartopy(radar)
    lat_0 = display.loc[0]
    lon_0 = display.loc[1]

    # Set our Projection
    projection = cartopy.crs.Mercator(central_longitude=lon_0,
                                      min_latitude=min_lat, max_latitude=max_lat)

    # Call our function to reduce data
    filter_data(sfc_data, projection, radius=station_radius, sort_key='present_weather')
    print(sweep)
    display.plot_ppi_map(
        field, sweep, colorbar_flag=True,
        title=radar_title +' area ' + field + ' \n' + fancy_date_string,
        projection=projection,
        min_lon=min_lon, max_lon=max_lon, min_lat=min_lat, max_lat=max_lat,
        vmin=vmin, vmax=vmax)

    # Mark the radar
    display.plot_point(lon_0, lat_0, label_text='Radar')

    # Get the current axes and plot some lat and lon lines
    gl = display.ax.gridlines(draw_labels=True,
                              linewidth=2, color='gray', alpha=0.5, linestyle='--')
    gl.xlabels_top = False
    gl.ylabels_right = False

    # Make the station plot
    stationplot = StationPlot(display.ax, sfc_data['longitude'], sfc_data['latitude'],
                              transform=cartopy.crs.PlateCarree(),
                              fontsize=12)
    station_layout.plot(stationplot, sfc_data)

    return display, time_at_start_of_radar
示例#18
0
# Create the figure and an axes set to the projection.
fig = plt.figure(figsize=(20, 8))
add_metpy_logo(fig, 70, 30, size='large')
ax = fig.add_subplot(1, 1, 1, projection=proj)

# Add some various map elements to the plot to make it recognizable.
ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.STATES.with_scale('50m'))

# Set plot bounds
ax.set_extent((-104, -93, 33.4, 37.2))

stationplot = StationPlot(ax,
                          longitude.values,
                          latitude.values,
                          clip_on=True,
                          transform=ccrs.PlateCarree(),
                          fontsize=12)

# Plot the temperature and dew point to the upper and lower left, respectively, of
# the center point. Each one uses a different color.
stationplot.plot_parameter('NW', temperature, color='red')
stationplot.plot_parameter('SW', dewpoint, color='darkgreen')

# A more complex example uses a custom formatter to control how the sea-level pressure
# values are plotted. This uses the standard trailing 3-digits of the pressure value
# in tenths of millibars.
stationplot.plot_parameter('NE',
                           pressure.m,
                           formatter=lambda v: format(10 * v, '.0f')[-3:])