def plot_APWP(APWPlats,APWPlongs,A95,colour='blue',meridian=-100): #generates a polar plot of the smoothed APWP when sent the columns from the pandas dataframe generated by generate_APWP #pandas Dataframe columns not readable by Basemap initially... longs=np.array(APWPlongs, dtype='float') lats=np.array(APWPlats, dtype='float') errors=np.array(A95, dtype='float') m = Basemap(projection='nplaea',boundinglat=60,lon_0=meridian,resolution='l') m.drawcoastlines(linewidth=0.25) m.fillcontinents(color='lightgrey') parallels = np.arange(-90.,90.,30.) m.drawparallels(parallels) meridians = np.arange(0.,360.,30.) m.drawmeridians(meridians) plt_line(longs,lats,m,colour) plt_points(longs,lats,m,colour) for i in range(len(errors)): m.ellipse(longs[i],lats[i],errors[i],errors[i],0.) #ell_x,ell_y=make_ellipse(lats[i],longs[i], errors[i]) #plt_line(ell_x,ell_y,m,colour) return m
def plot_sky(ra, dec, data=None, pix_shape='ellipse', nside=16, label='', projection='eck4', cmap='jet', hide_galactic_plane=False, discrete_colors=True, center_longitude=0, radius=2., epsi=0.2, alpha_tile=0.5, min_color=1, max_color=5, nsteps=5): """ Routine that reads ra and dec with the proper units (requires astropy units) and makes an all-sky plot of the desired data. Requires Basemap installed and astropy.units Parameters ---------- ra : array of :class: `astropy.angle` Right ascension with units. dec : array of :class: `astropy.angle` Declination with units. data : array of :class: `float or int` Weights to use (for example the tile-pass or values of E(B-V)). pix_shape : :class: `string` Desired shape of the pixels on the plot. It can take the values 'ellipse', 'healpix', and 'square' nside : int, it controls the number of pixels with healpix and square pixels. For healpix the whole celestial sphere is divided into 12*nside**2 pixels, for square pixels it is divided into 16*nside**2. label : :class: `string`, optional label for the colorbar. projection : :class: `string`, optional projection scheme used to show the map. 'eck4', 'kav7', and 'moll' recommended for full sky maps: Default 'eck4'. cmap : :class: `string`, optional name of the matplotlib colormap to use. Default 'jet'. hide_galactic_plane : :class: `bool`, optional if True it hides the galactic plane in the plot, if False it shows it. Default False. discrete_colors : :class: `bool`, optional if True it uses the data to create a linear discrete color-scale. center_longitude : :class: `float`, optional center longitude for the plot in degrees. Default 0. radius : :class: `float`, optional radius of the circle in degrees. Default 2. epsi : :class: `float`, optional it prevents ellipses to wrap around the edges. Only ellipses with |ra-180-center_longitude|>radius+epsi are plotted. If you want to plot all the ellipses set epsi to -radius (some ellipses may wrap around the edges). Default 0.2 alpha_tile : :class: `float`, optional value between 0 and 1 of transparency for the ellipses. 1 Opaque, 0 transparent. min_color : :class: `float`, optional minimum value of the color scale if discrete_colors=True. Default 1 max_color : :class: `float`, optional maximum value of the color scale if discrete_colors=True. Default 5 nsteps : :class: `int`, optional number of intervals on the color scale if discrete_colors=True. Default 5 Returns ------- :class:`matplotlib.axes.Axes` The Axes object for the plot. It creates a figure if there was no previous figure and if data is not provided it returns counts per square-degree if healpix or square pixels are created. If you choose the option ellipse it plots as many ellipses as ra,dec points provided (it may be slow). """ from matplotlib.collections import PolyCollection from astropy.coordinates import SkyCoord import matplotlib.pyplot as plt import astropy.units as u import matplotlib.cm as cm import numpy as np from matplotlib.patches import Polygon from mpl_toolkits.basemap import pyproj from mpl_toolkits.basemap import Basemap import matplotlib as mpl #--------- # Add ellipses to Basemap #-------- class Basemap(Basemap): #Code from http://stackoverflow.com/questions/8161144/drawing-ellipses-on-matplotlib-basemap-projections #It adds ellipses to the class Basemap to use in plotsky. This is only used in plotsky and includes the basemap #dependencies. def ellipse(self, x0, y0, a, b, n, ax=None, **kwargs): ax = kwargs.pop('ax', None) or self._check_ax() g = pyproj.Geod(a=self.rmajor, b=self.rminor) azf, azb, dist = g.inv([x0, x0], [y0, y0], [x0 + a, x0], [y0, y0 + b]) tsid = dist[0] * dist[1] # a * b seg = [self(x0 + a, y0)] AZ = np.linspace(azf[0], 360. + azf[0], n) for i, az in enumerate(AZ): # Skips segments along equator (Geod can't handle equatorial arcs). if np.allclose(0., y0) and (np.allclose(90., az) or np.allclose(270., az)): continue # In polar coordinates, with the origin at the center of the # ellipse and with the angular coordinate ``az`` measured from the # major axis, the ellipse's equation is [1]: # # a * b # r(az) = ------------------------------------------ # ((b * cos(az))**2 + (a * sin(az))**2)**0.5 # # Azymuth angle in radial coordinates and corrected for reference # angle. azr = 2. * np.pi / 360. * (az + 90.) A = dist[0] * np.sin(azr) B = dist[1] * np.cos(azr) r = tsid / (B**2. + A**2.)**0.5 lon, lat, azb = g.fwd(x0, y0, az, r) x, y = self(lon, lat) # Add segment if it is in the map projection region. if x < 1e20 and y < 1e20: seg.append((x, y)) poly = Polygon(seg, **kwargs) ax.add_patch(poly) # Set axes limits to fit map region. self.set_axes_limits(ax=ax) return poly ra = ra.to(u.deg).value dec = dec.to(u.deg).value if pix_shape not in ['ellipse', 'healpix', 'square']: print('Pixel shape invalid, try ellipse, healpix or square') if discrete_colors: if (data is None): print('Error discrete_colors expects data!=None') else: # define the colormap cmap = plt.get_cmap(cmap) cmaplist = [cmap(i) for i in range(cmap.N)] cmap = cmap.from_list('Custom cmap', cmaplist, cmap.N) # define the bins and normalize bounds = np.linspace(min_color, max_color, nsteps) norm = mpl.colors.BoundaryNorm(bounds, cmap.N) else: cmap = plt.get_cmap(cmap) norm = None if (pix_shape == 'healpix'): import healpy as hp # get pixel area in degrees pixel_area = hp.pixelfunc.nside2pixarea(nside, degrees=True) #avoid pixels which may cause polygons to wrap around workaround drawing_mask = np.logical_and( np.fabs(ra - 180 - center_longitude) > 2 * np.sqrt(pixel_area) + epsi, np.fabs(ra + 180 - center_longitude) > 2 * np.sqrt(pixel_area) + epsi) ra = ra[drawing_mask] dec = dec[drawing_mask] if data != None: data = data[drawing_mask] # find healpixels associated with input vectors pixels = hp.ang2pix(nside, 0.5 * np.pi - np.radians(dec), np.radians(ra)) # find unique pixels unique_pixels = np.unique(pixels) # count number of points in each pixel bincounts = np.bincount(pixels) # if no data provided, show counts per sq degree # otherwise, show mean per pixel if data is None: values = bincounts[unique_pixels] / pixel_area else: weighted_counts = np.bincount(pixels, weights=data) values = weighted_counts[unique_pixels] / bincounts[unique_pixels] # find pixel boundaries corners = hp.boundaries(nside, unique_pixels, step=1) corner_theta, corner_phi = hp.vec2ang(corners.transpose(0, 2, 1)) corner_ra, corner_dec = np.degrees(corner_phi), np.degrees( np.pi / 2 - corner_theta) # set up basemap m = Basemap(projection=projection, lon_0=center_longitude, resolution='c', celestial=True) m.drawmeridians(np.arange(0, 360, 60), labels=[0, 0, 1, 0], labelstyle='+/-') m.drawparallels(np.arange(-90, 90, 15), labels=[1, 0, 0, 0], labelstyle='+/-') m.drawmapboundary() # convert sky coords to map coords x, y = m(corner_ra, corner_dec) # regroup into pixel corners verts = np.array([x.reshape(-1, 4), y.reshape(-1, 4)]).transpose(1, 2, 0) # Make the collection and add it to the plot. coll = PolyCollection(verts, array=values, cmap=cmap, norm=norm, edgecolors='none') plt.gca().add_collection(coll) plt.gca().autoscale_view() if not hide_galactic_plane: # generate vector in galactic coordinates and convert to equatorial coordinates galactic_l = np.linspace(0, 2 * np.pi, 1000) galactic_plane = SkyCoord(l=galactic_l * u.radian, b=np.zeros_like(galactic_l) * u.radian, frame='galactic').fk5 # project to map coordinates galactic_x, galactic_y = m(galactic_plane.ra.degree, galactic_plane.dec.degree) m.scatter(galactic_x, galactic_y, marker='.', s=2, c='k') # Add a colorbar for the PolyCollection plt.colorbar(coll, orientation='horizontal', cmap=cmap, norm=norm, spacing='proportional', pad=0.01, aspect=40, label=label) if (pix_shape == 'square'): nx, ny = 4 * nside, 4 * nside ra_bins = np.linspace(-180 + center_longitude, 180 + center_longitude, nx + 1) cth_bins = np.linspace(-1., 1., ny + 1) ra[ra > 180 + center_longitude] = ra[ra > 180 + center_longitude] - 360 if data == None: weights = np.ones(len(ra)) else: weights = data density, _, _ = np.histogram2d(ra, np.sin(dec * np.pi / 180.), [ra_bins, cth_bins], weights=weights) ra_bins_2d, cth_bins_2d = np.meshgrid(ra_bins, cth_bins) m = Basemap(projection=projection, lon_0=center_longitude, resolution='l', celestial=True) m.drawmeridians(np.arange(0, 360, 60), labels=[0, 0, 1, 0], labelstyle='+/-') m.drawparallels(np.arange(-90, 90, 15), labels=[1, 0, 0, 0], labelstyle='+/-') m.drawmapboundary() xs, ys = m(ra_bins_2d, np.arcsin(cth_bins_2d) * 180 / np.pi) new_density = np.ma.masked_where(density == 0, density).T pcm = plt.pcolormesh(xs, ys, new_density, cmap=cmap, norm=norm) plt.colorbar(pcm, orientation='horizontal', cmap=cmap, norm=norm, spacing='proportional', pad=0.04, label=label) if not hide_galactic_plane: # generate vector in galactic coordinates and convert to equatorial coordinates galactic_l = np.linspace(0, 2 * np.pi, 1000) galactic_plane = SkyCoord(l=galactic_l * u.radian, b=np.zeros_like(galactic_l) * u.radian, frame='galactic').fk5 # project to map coordinates galactic_x, galactic_y = m(galactic_plane.ra.degree, galactic_plane.dec.degree) m.scatter(galactic_x, galactic_y, marker='.', s=2, c='k') if (pix_shape == 'ellipse'): m = Basemap(projection=projection, lon_0=center_longitude, resolution='l', celestial=True) m.drawmeridians(np.arange(0, 360, 60), labels=[0, 0, 1, 0], labelstyle='+/-') m.drawparallels(np.arange(-90, 90, 15), labels=[1, 0, 0, 0], labelstyle='+/-') m.drawmapboundary() if not hide_galactic_plane: # generate vector in galactic coordinates and convert to equatorial coordinates galactic_l = np.linspace(0, 2 * np.pi, 1000) galactic_plane = SkyCoord(l=galactic_l * u.radian, b=np.zeros_like(galactic_l) * u.radian, frame='galactic').fk5 # project to map coordinates galactic_x, galactic_y = m(galactic_plane.ra.degree, galactic_plane.dec.degree) m.scatter(galactic_x, galactic_y, marker='.', s=2, c='k') if data == None: weights = np.ones(len(ra)) else: weights = data ax = plt.gca() cmm = cm.ScalarMappable(norm=norm, cmap=cmap) color_array = cmm.to_rgba(weights) for i in range(0, len(ra)): if (np.fabs(ra[i] - 180 - center_longitude) > radius + epsi and np.fabs(ra[i] + 180 - center_longitude) > radius + epsi): poly = m.ellipse(ra[i], dec[i], radius, radius, 8, facecolor=color_array[i], zorder=10, alpha=alpha_tile) plt.colorbar(plt.imshow(np.array([(1, 2), (3, 4), (0, 6)]), cmap=cmap, norm=norm), orientation='horizontal', cmap=cmap, norm=norm, spacing='proportional', pad=0.04, label=label) axis = plt.gca() return axis
def plot_fp_act(FP_ID, FP_utilize_df, act_track_data, flight_plan_data, feed_track = None, pred_track = None, pred_track_mu = None, pred_track_cov = None, k = 9, nstd = 3, sort = True, plot_weather_info = False, **kwargs): # TODO: plot error ellipse ori_lat = 29.98333333; ori_lon = -95.33333333 des_lat = 42.36666667; des_lon = -71 fig = plt.figure(figsize=(8,6)) m = Basemap(llcrnrlon = -100,llcrnrlat = 27,urcrnrlon = -68,urcrnrlat = 46,projection='merc') m.drawmapboundary(fill_color='#8aeaff') m.fillcontinents(color='#c5c5c5', lake_color='#8aeaff') m.drawcoastlines(linewidth=0.5) m.drawcountries(linewidth=0.5) m.drawstates(linewidth=0.5) m.drawparallels(np.arange(10.,35.,5.)) m.drawmeridians(np.arange(-120.,-80.,10.)) x1, y1 = m(ori_lon, ori_lat) x2, y2 = m(des_lon, des_lat) plt.plot(x1,y1, 'r*', ms = 15, zorder = 10) plt.plot(x2,y2, 'r*', ms = 15, zorder = 10) fid_fp1 = FP_utilize_df.loc[FP_utilize_df.FLT_PLAN_ID == FP_ID, 'FID'].values print('%d flights filed flight plan %s'%(fid_fp1.shape[0], FP_ID)) plot_track = act_track_data.loc[act_track_data.FID.isin(fid_fp1)] plot_fp = flight_plan_data.loc[flight_plan_data.FLT_PLAN_ID_REAL == FP_ID] x_fp, y_fp = m(plot_fp.LONGITUDE.values, plot_fp.LATITUDE.values) feed_x, feed_y = m(feed_track.Lon.values, feed_track.Lat.values) feed, = plt.plot(feed_x, feed_y, 'o-', ms = 4, linewidth = 3, color='g', label = 'Feed tracks', zorder = 9) for gpidx, gp in plot_track.groupby('FID'): x,y = m(gp.Lon.values, gp.Lat.values) actual, = plt.plot(x,y,'--', linewidth = 2, color='b', label = 'Actual Tracks', zorder = 8) fp, = plt.plot(x_fp, y_fp, '-', linewidth = 2, color='r', label = 'Flight Plans', zorder = 5) if pred_track is not None: if sort: x, y = m(pred_track[k][pred_track[k][:,3].argsort()][:, 1], pred_track[k][pred_track[k][:,3].argsort()][:, 0]) else: x, y = m(pred_track[k, :, 1], pred_track[k, :, 0]) pred_fig, = plt.plot(x,y, 'o--', ms = 3, zorder = 7) if pred_track_mu is not None: if sort: x, y = m(pred_track_mu[k][pred_track_mu[k][:,3].argsort()][:, 1], pred_track_mu[k][pred_track_mu[k][:,3].argsort()][:, 0]) else: x, y = m(pred_track_mu[k][:, 1], pred_track_mu[k][:, 0]) plt.plot(x,y, 'mo--', ms = 4, zorder = 7, label = 'Predicted tracks') if pred_track_cov is not None: for t in range(pred_track_mu[k].shape[0]): lon_a = np.sqrt(pred_track_cov[k, t, 1, 1]) * nstd lat_b = np.sqrt(pred_track_cov[k, t, 0, 0]) * nstd # assume independency # cov_width, cov_height, cov_theta = get_cov_ellipse_wh(predicted_tracks_cov[k, t, :2, :2], nstd = 3) centre_lon, centre_lat = (pred_track_mu[k, t, 1], pred_track_mu[k, t, 0]) poly = m.ellipse(centre_lon, centre_lat, lon_a, lat_b, 50, facecolor='green', zorder=6, alpha=0.25) plt.legend(fontsize = 12, loc = 2) if plot_weather_info: grbs_common_info_file = kwargs.get('grbs_common_info_file', '/media/storage/DATA/filtered_weather_data/grbs_common_info.npz') wind_file_root = kwargs.get('wind_file_root', '../../DATA/filtered_weather_data/namanl_small_npz/') wx_file_root = kwargs.get('wx_file_root', '../../DATA/NCWF/gridded_storm_hourly/') resolution = kwargs.get('resolution', 50) wind_scale = kwargs.get('wind_scale', 1000) wind_fname_list = [os.path.join(wind_file_root, wf) for wf in np.unique(plot_track['wind_fname'])] wx_file_time = plot_track['wx_fname'].values wx_file_time = np.unique(wx_file_time[~pd.isnull(wx_file_time)]) wx_fname_list = [os.path.join(wx_file_root, wf.replace('-', '_').replace(' ', '_').replace(':', '')[:15] + 'Z.npz') for wf in wx_file_time] _ = plot_wx(m, wind_fname_list = wind_fname_list, wx_fname_list = wx_fname_list, grbs_common_info_file = grbs_common_info_file, resolution = resolution, wind_scale = wind_scale) plt.show() return plot_track, m