def global_predstorm_noaa(world_image): fig = plt.figure(1,figsize=[15, 10]) fig.set_facecolor('black') #axis PREDSTORM + OVATION ax1 = plt.subplot(1, 2, 1, projection=ccrs.Orthographic(global_plot_longitude, global_plot_latitude)) #axis NOAA ax2 = plt.subplot(1, 2, 2, projection=ccrs.Orthographic(global_plot_longitude, global_plot_latitude)) #load NOAA nowcast noaa_img, dt = oup.aurora_now() for ax in [ax1,ax2]: ax.gridlines(linestyle='--',alpha=0.5,color='white') #ax.coastlines(alpha=0.5,zorder=3) #ax.add_feature(land_50m, color='darkgreen') #ax.add_feature(land_50m, color='darkslategrey') #ax.add_feature(carfeat.LAND,color='darkslategrey') #ax.add_feature(carfeat.LAKES,color='navy')#,zorder=2,alpha=1) #ax.add_feature(carfeat.OCEAN)#,zorder=2,alpha=1) #ax.add_feature(ocean_50m,linewidth=0.5, color='navy') #ax.add_feature(carfeat.BORDERS, alpha=0.5)#,zorder=2,alpha=0.5) #ax.add_feature(carfeat.COASTLINE)#,zorder=2,alpha=0.5) #ax.add_feature(carfeat.RIVERS)#,zorder=2,alpha=0.8) #ax.add_feature(provinces_50m,alpha=0.5)#,zorder=2,alpha=0.8) ax.stock_img()#alpha=0.2) #ax.add_wmts(nightmap, layer) #for testing with black background #ax.background_patch.set_facecolor('k') if ax==ax1: ax.imshow(world_image, vmin=0, vmax=100, transform=crs, extent=mapextent, origin='lower', zorder=3, alpha=0.9, cmap=oup.aurora_cmap()) ax.add_feature(Nightshade(t0)) if ax==ax2: ax.imshow(noaa_img, vmin=0, vmax=100, transform=crs, extent=mapextent, origin='lower', zorder=3, alpha=0.9, cmap=oup.aurora_cmap()) ax.add_feature(Nightshade(dt)) fig.text(0.01,0.92,'PREDSTORM aurora forecast '+t0.strftime('%Y-%m-%d %H:%M UT' )+ ' NOAA forecast '+dt.strftime('%Y-%m-%d %H:%M UT' ), color='white',fontsize=15) fig.text(0.99,0.02,'C. Möstl / IWF-helio, Austria', color='white',fontsize=8,ha='right') plt.tight_layout() plot_Nhemi_comparison_filename='test/predstorm_aurora_real_Nhemi_'+t0.strftime("%Y_%m_%d_%H%M") +'.jpg' fig.savefig(plot_Nhemi_comparison_filename,dpi=120,facecolor=fig.get_facecolor()) #plt.show() print('Saved image: ',plot_Nhemi_comparison_filename)
def __init__(self, metric_name, date, decorations=True): self.metric_name = metric_name self.date = date self.decorations = decorations self.plotalpha = 0.35 self.fig = plt.figure(figsize=(16,24)) self.ax = plt.axes( projection=ccrs.PlateCarree(), frame_on=self.decorations, ) self.ax.set_global() if self.decorations: self.ax.grid(linewidth=.5, color='black', alpha=0.25, linestyle='--') self.ax.set_xticks([-180, -160, -140, -120,-100, -80, -60,-40,-20, 0, 20, 40, 60,80,100, 120,140, 160,180], crs=ccrs.PlateCarree()) self.ax.set_yticks([-80, -60,-40,-20, 0, 20, 40, 60,80], crs=ccrs.PlateCarree()) else: self.ax.axis(False) self.ax.outline_patch.set_visible(False) self.ax.background_patch.set_visible(False) self.ax.set_xmargin(0) self.ax.set_ymargin(0) self.ax.add_feature(cartopy.feature.NaturalEarthFeature('physical', 'land', '110m', edgecolor='face', facecolor=np.array((0xdd,0xdd,0xcc))/256., zorder=-1 ) ) self.ax.add_feature(Nightshade(self.date, alpha=0.08))
def test_nightshade_floating_point(): # Smoke test for clipping nightshade floating point values date = datetime(1999, 12, 31, 12) # This can cause an error with floating point precision if it is # set to exactly -6 and arccos input is not clipped to [-1, 1] Nightshade(date, refraction=-6.0, color='none')
def test_nightshade_image(): # Test the actual creation of the image ax = plt.axes(projection=ccrs.PlateCarree()) ax.coastlines() dt = datetime(2018, 11, 10, 0, 0) ax.set_global() ax.add_feature(Nightshade(dt, alpha=0.75))
def add_dn_terminator(self, **kwargs): """ Adding day night terminator """ from cartopy.feature.nightshade import Nightshade if self.plot_date: ns_feature = Nightshade(self.plot_date, alpha=0.2) super().add_feature(feature, **kwargs) return
def _plot_orthographic_projection(latitude_sat, longitude_sat, lat_footprint, lon_footprint, epoch): """This method plots the satellite track and footprint in the Orthographic projection. INPUT: ------ latitude_sat = vector of latitudes of the satellite. It must be of the same size of longitude_sat. [deg] longitude_sat = vector of longitudes of the satellite. It must be of the same size of latitude_sat. [deg] lat_footprint = vector of latitudes of the boundary of the satellite footprint. [deg] It must be of the same size of lon_footprint. lon_footprint = vector of longitudes of the boundary of the satellite footprint. [deg] It must be of the same size of lat_footprint. epoch = epoch to display the nightshade on the map. It must be of type datetime. """ plt.figure() ax = plt.axes( projection=ccrs.Orthographic(longitude_sat[0], latitude_sat[0])) points = ccrs.Orthographic(longitude_sat[0], latitude_sat[0]).transform_points( ccrs.Geodetic(), longitude_sat, latitude_sat) footprint_points = ccrs.Orthographic(longitude_sat[0], latitude_sat[0]).transform_points( ccrs.Geodetic(), lon_footprint, lat_footprint) ax.gridlines() ax.coastlines() ax.set_global() ax.add_feature(Nightshade(epoch, alpha=0.4)) ax.plot(points[:, 0], points[:, 1], linewidth=2) ax.plot(footprint_points[:, 0], footprint_points[:, 1], linewidth=2) ax.plot(points[0, 0], points[0, 1], 'h', color='#1e1596', markersize=8)
def plot_clear(dtime, show=True): """ Plot an orthographic projection of clear area. - dtime = datetime instance - show = boolean: whether or not to display a plot Either shows a plot and returns nothing, or returns the axis on which the clear area is plotted, depending on the value of "show". """ print('plotting clear area') # general earth setup ax = plt.axes(projection=constants.ortho) ax.add_feature(cartopy.feature.OCEAN, zorder=0) ax.add_feature(cartopy.feature.LAND, zorder=0, edgecolor='black') ax.add_feature(cartopy.feature.BORDERS, zorder=0, edgecolor='black') ax.add_feature(Nightshade(dtime, alpha=0.2)) # add clear polys clear_polys, _ = earth_data.get_clear(dtime) print("adding", len(clear_polys), "clear polygons to plot") ax.add_geometries(clear_polys, crs=constants.lonlat, facecolor='g') # show the plot if desired if show: plt.show() else: # return the axis so we can plot more things overtop if we want return ax
def main(): fig = plt.figure(figsize=[10, 5]) # We choose to plot in an Orthographic projection as it looks natural # and the distortion is relatively small around the poles where # the aurora is most likely. # ax1 for Northern Hemisphere ax1 = fig.add_subplot(1, 2, 1, projection=ccrs.Orthographic(0, 90)) # ax2 for Southern Hemisphere ax2 = fig.add_subplot(1, 2, 2, projection=ccrs.Orthographic(180, -90)) img, crs, extent, origin, dt = aurora_forecast() for ax in [ax1, ax2]: ax.coastlines(zorder=3) ax.stock_img() ax.gridlines() ax.add_feature(Nightshade(dt)) ax.imshow(img, vmin=0, vmax=100, transform=crs, extent=extent, origin=origin, zorder=2, cmap=aurora_cmap()) plt.show()
def plot_poles(pos_ecf, fig=None, axarr=None, show_night=True, date=None, show_aurora=True): if axarr is None: if fig is None: fig = plt.figure(figsize=(10, 5)) # We choose to plot in an Orthographic projection as it looks natural # and the distortion is relatively small around the poles where # the aurora is most likely. # ax1 for Northern Hemisphere ax1 = fig.add_subplot(1, 2, 1, projection=ccrs.Orthographic(0, 90)) # ax2 for Southern Hemisphere ax2 = fig.add_subplot(1, 2, 2, projection=ccrs.Orthographic(180, -90)) else: ax1, ax2 = axarr img, crs, extent, origin, dt = aurora_forecast() lat, long = ecf_to_latlon(pos_ecf) if show_aurora: img, crs, extent, origin, dt = aurora_forecast() for ax in [ax1, ax2]: ax.coastlines(zorder=3) ax.stock_img() ax.gridlines() ax.plot(long.deg, lat.deg, transform=ccrs.Geodetic()) if show_night: if date is None: date = datetime(2020, 6, 15, 12) ax.set_title("Night time shading for {}".format(date)) ax.add_feature(Nightshade(date, alpha=0.2)) if show_aurora: ax.imshow( img, vmin=0, vmax=100, transform=crs, extent=extent, origin=origin, zorder=2, cmap=aurora_cmap(), ) return ax1, ax2
def _plot_plate_carree_projection(latitude_sat, longitude_sat, lat_footprint, lon_footprint, epoch): """This method plots the satellite track and footprint in the Plate Carree projection. INPUT: ------ latitude_sat = vector of latitudes of the satellite. It must be of the same size of longitude_sat. [deg] longitude_sat = vector of longitudes of the satellite. It must be of the same size of latitude_sat. [deg] lat_footprint = vector of latitudes of the boundary of the satellite footprint. [deg] It must be of the same size of lon_footprint. lon_footprint = vector of longitudes of the boundary of the satellite footprint. [deg] It must be of the same size of lat_footprint. epoch = epoch to display the nightshade on the map. It must be of type datetime. """ # The longitude array is cut in two piece according to positive values and negative. # Positive longitude values will be plotted separately from the negative one. longitude_positive = np.ma.masked_where(longitude_sat < 0, longitude_sat) longitude_negative = np.ma.masked_where(longitude_sat >= 0, longitude_sat) # The longitude array is cut in two piece according to positive values and negative. # Positive longitude values will be plotted separately from the negative one. longitude_footprint_positive = np.ma.masked_where( lon_footprint < 0, lon_footprint) longitude_footprint_negative = np.ma.masked_where( lon_footprint >= 0, lon_footprint) plt.figure() ax = plt.axes(projection=ccrs.PlateCarree()) ax.coastlines() ax.set_global() ax.gridlines() ax.add_feature(Nightshade(epoch, alpha=0.4)) ax.set_xticks([-180, -120, -60, 0, 60, 120, 180], crs=ccrs.PlateCarree()) ax.set_yticks([-90, -60, -30, 0, 30, 60, 90], crs=ccrs.PlateCarree()) lon_formatter = LongitudeFormatter(dateline_direction_label=True) lat_formatter = LatitudeFormatter() ax.xaxis.set_major_formatter(lon_formatter) ax.yaxis.set_major_formatter(lat_formatter) ax.plot(longitude_positive, latitude_sat, color='#1f77b4', linewidth=2) ax.plot(longitude_negative, latitude_sat, color='#1f77b4', linewidth=2) ax.plot(longitude_footprint_positive, lat_footprint, color='#ff7f0e', linewidth=2) ax.plot(longitude_footprint_negative, lat_footprint, color='#ff7f0e', linewidth=2) ax.plot(longitude_sat[0], latitude_sat[0], 'h', color='#1e1596', markersize=8)
def is_light(lons, lats, dtime, night=None): """ Tests whether or not arrays of longitudes and latitudes are dark. - lons = longitudes, array - lats = latitudes, array - dtime = datetime instance - night = Nightshade instance if you have one, otherwise one will be made """ if night is None: night = Nightshade(dtime) dark_poly = list(night.geometries())[0] mesh_lons, mesh_lats = np.meshgrid(lons, lats) # check if each pair of points are inside the dark polygon result = np.empty_like(mesh_lons, dtype=int) for index, lon in np.ndenumerate(mesh_lons): lat = mesh_lats[index] # convert coordinate systems to the dark_poly's coords x, y = night.crs.transform_point(lon, lat, c.lonlat) light = not dark_poly.contains(shapely.geometry.Point(x, y)) result[index] = light return result
def GlobePlotter(solarlat, solarlon, lattrace, lontrace): midlat = np.mean(lattrace) midlon = np.mean(lontrace) projection = ccrs.Orthographic(midlon, midlat) ax = plt.axes(projection=projection) file_location = path.abspath(path.dirname(__file__)) path_to_pic = file_location + '/images/2k_mars.jpg' source_proj = ccrs.PlateCarree() ax.imshow(imread(path_to_pic), origin='upper', transform=source_proj, extent=[-180, 180, -90, 90]) # plot the ground feature labels df = pd.read_csv('mars.csv', encoding='latin-1') df.sort_values(by=["Diameter"], inplace=True, ascending=False) minlen = 30 # plot only the largest 30 objects on the surface of mars. Maybe update to the the best known df = df.head(min(minlen, len(df))) for index, row in df.iterrows(): text = row['Clean_Feature_Name'] x, y, s = row['Center_Longitude'], row['Center_Latitude'], row['Diameter'] ax.text(x, y, text, transform=ccrs.PlateCarree(), ha='left', va='center', fontsize=8, color='#ebc334') ax.scatter(x, y, transform=ccrs.PlateCarree(), s=10, color='#ebc334', edgecolor='None', lw=0) # adjusting the gridlines to fit the occtrace location [10 MIGHT BE TO COARSE] # STILL NEED BETTER SOLUTION minlat = (np.floor(np.min(lattrace)/10))*10 maxlat = (np.ceil(np.max(lattrace)/10))*10 minlon = (np.floor(np.min(lontrace)/10))*10 maxlon = (np.ceil(np.max(lontrace)/10))*10 track = sgeom.LineString(zip(lontrace, lattrace)) ax.add_geometries([track], source_proj, edgecolor='#C852C8', linewidth=8, alpha=0.5, facecolor='none') gl = ax.gridlines(crs=ccrs.PlateCarree(), linewidth=2, color='k', alpha=0.2, linestyle='--', draw_labels=True) gl.top_labels = False gl.left_labels = False gl.right_labels = False gl.xlines = True gl.ylocator = mticker.FixedLocator( list(np.arange(int(minlat), int(maxlat), 10))) gl.xlocator = mticker.FixedLocator( list(np.arange(int(minlon), int(maxlon), 10))) gl.xlabel_style = {'color': 'k'} # <<<< this involves a custom nightshade function, go into the cartopy libs and edit to include lat lon ax.add_feature(Nightshade(solarlat, solarlon)) # plot occultation track ax.add_geometries([track], source_proj, edgecolor='#C852C8', linewidth=8, alpha=0.5, facecolor='none') plt.show()
def __init__(self, metric_name, date, decorations=True, basemaps=True, alpha=0.35, centered=None): self.metric_name = metric_name self.date = date self.decorations = decorations self.basemaps = basemaps self.plotalpha = alpha if centered is None: self.proj = ccrs.PlateCarree() figsize=(16,24) else: self.proj = ccrs.AzimuthalEquidistant(centered[0], centered[1]) figsize=(12,12) self.fig = plt.figure(figsize=figsize) self.ax = plt.axes( projection=self.proj, frame_on=self.decorations, facecolor='white', ) self.ax.spines['geo'].set_edgecolor('#666') self.ax.set_global() if self.decorations: if centered is None: self.ax.grid(True, visible=True, linewidth=.5, color='black', alpha=0.25, linestyle='--') self.ax.set_xticks([-180, -160, -140, -120,-100, -80, -60,-40,-20, 0, 20, 40, 60,80,100, 120,140, 160,180], crs=ccrs.PlateCarree()) self.ax.set_yticks([-80, -60,-40,-20, 0, 20, 40, 60,80], crs=ccrs.PlateCarree()) else: self.ax.gridlines( linewidth=.5, color='black', alpha=0.25, linestyle='--', xlocs=[-180, -160, -140, -120,-100, -80, -60,-40,-20, 0, 20, 40, 60,80,100, 120,140, 160,180], ylocs=[-80, -60,-40,-20, 0, 20, 40, 60,80], ) else: self.ax.axis(False) self.ax.outline_patch.set_visible(False) self.ax.background_patch.set_visible(False) self.ax.set_xmargin(0) self.ax.set_ymargin(0) if basemaps: self.ax.add_feature(cartopy.feature.NaturalEarthFeature('physical', 'land', '110m', edgecolor='face', facecolor=np.array((0xdd,0xdd,0xcc))/256., zorder=-1 ) ) self.ax.add_feature(Nightshade(self.date, alpha=0.08))
def get_light_mask(dtime): """ Get 2D array associated with MERRA grid points, 1 = light 0 = dark, at a given time (dtime = datetime instance) """ light_mask_file = dtime.strftime(c.light_mask_format) if not exists(light_mask_file): print("Creating light_mask, this might take 30 seconds") # this is the polygon that is the "shady" area night = Nightshade(dtime) # get all points not within the dark_poly light_mask = is_light(c.lons, c.lats, dtime, night) # save result to file np.save(light_mask_file, light_mask) return np.load(light_mask_file)
def plot_planisphere(pos_ecf, fig=None, ax=None, show_night=True, date=None, show_aurora=True): if ax is None: if fig is None: fig = plt.figure(figsize=(10, 5)) ax = fig.add_subplot(1, 1, 1, projection=ccrs.Robinson()) # make the map global rather than have it zoom in to # the extents of any plotted data # ax.set_global() ax.stock_img() ax.coastlines() ax.gridlines() lat, long = ecf_to_latlon(pos_ecf) ax.plot(long.deg, lat.deg, transform=ccrs.Geodetic()) if show_night: if date is None: date = datetime(2020, 6, 15, 12) ax.set_title("Night time shading for {}".format(date)) ax.add_feature(Nightshade(date, alpha=0.2)) if show_aurora: img, crs, extent, origin, dt = aurora_forecast() ax.imshow( img, vmin=0, vmax=100, transform=crs, extent=extent, origin=origin, zorder=2, cmap=aurora_cmap(), ) return ax
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sat Dec 29 13:03:47 2018 @author: ahmed """ import datetime import matplotlib.pyplot as plt import cartopy.crs as ccrs from cartopy.feature.nightshade import Nightshade fig = plt.figure(figsize=(10, 5)) ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree()) date = datetime.datetime(2019, 1, 13, 11) ax.set_title('Night time shading for {}'.format(date)) ax.stock_img() ax.add_feature(Nightshade(date, alpha=0.2)) plt.savefig("cartopy1.png"); plt.savefig("cartopy1.pdf") plt.show()
def europe_canada_predstorm(world_image,dt,counter,colormap_input): plt.close('all') #Night map from VIIRS #https://wiki.earthdata.nasa.gov/display/GIBS/GIBS+Available+Imagery+Products#expand-EarthatNight4Products #nightmap = 'https://map1c.vis.earthdata.nasa.gov/wmts-geo/wmts.cgi' #define extent of the produced world maps - defined as: west east south north mapextent=[-180,180,-90,90] #not so good: layer='VIIRS_Black_Marble' #better but takes time #layer = 'VIIRS_CityLights_2012' #need to set alpha linearly increasing in the colormap cmap = plt.get_cmap(colormap_input) # Choose colormap my_cmap = cmap(np.arange(cmap.N)) # Get the colormap colors my_cmap[:,-1] = np.linspace(0.3, 1, cmap.N) # Set alpha my_cmap = ListedColormap(my_cmap) # Create new colormap land_50m = carfeat.NaturalEarthFeature('physical', 'land', '50m', edgecolor='k', facecolor=carfeat.COLORS['land']) ocean_50m = carfeat.NaturalEarthFeature('physical', 'ocean', '50m', edgecolor='k', facecolor='steelblue')#carfeat.COLORS['water']) provinces_50m = carfeat.NaturalEarthFeature('cultural', 'admin_1_states_provinces_lines', '50m', facecolor='none',edgecolor='black') crs=ccrs.PlateCarree() #16/9 ration for full hd output fig = plt.figure(2,figsize=[16, 9],dpi=100) fig.set_facecolor('black') plt.cla() # ax1 Europe ax1 = plt.subplot(1, 2, 2, projection=ccrs.Orthographic(0, 60),position=[0.51,0.05,0.48,0.9])#[left, bottom, width, height] # ax2 northern America ax2 = plt.subplot(1, 2, 1, projection=ccrs.Orthographic(-100, 60), position=[0.01,0.05,0.48,0.9]) #define map extents canada_east = -65 canada_west = -135 canada_north = 75 canada_south = 20 europe_east = 50 europe_west = -20 europe_north = 75 europe_south = 30 #plot one axis after another for ax in [ax1, ax2]: #ax.gridlines(linestyle='--',alpha=0.2,color='white') #ax.coastlines(alpha=0.5,zorder=3) #ax.add_feature(carfeat.LAND,zorder=2,alpha=1) #ax.add_feature(land_50m, color='darkgreen') #ax.add_feature(land_50m, color='darkslategrey') ax.add_feature(land_50m, color='dimgrey') ax.add_feature(provinces_50m,alpha=0.5)#,zorder=2,alpha=0.8) #ax.add_feature(carfeat.COASTLINE)#,zorder=2,alpha=0.5) #ax.add_feature(carfeat.OCEAN,color='mediumslateblue')#,zorder=2,alpha=1) ax.add_feature(ocean_50m, color='darkblue') #ax.add_feature(carfeat.RIVERS)#,zorder=2,alpha=0.8) ax.add_feature(carfeat.LAKES,color='darkblue')#,zorder=2,alpha=1) color navy? ax.add_feature(carfeat.BORDERS, alpha=0.5)#,zorder=2,alpha=0.5) ax.add_feature(Nightshade(dt)) #ax.stock_img() #ax.add_wmts(nightmap, layer) ax.imshow(world_image, vmin=0.001, vmax=5, transform=crs, extent=mapextent, origin='lower', zorder=3, alpha=0.8, cmap=my_cmap) if ax == ax1: ax.set_extent([europe_west, europe_east, europe_south, europe_north]) if ax == ax2: ax.set_extent([canada_west, canada_east, canada_south, canada_north]) fig.text(0.01,0.92,'PREDSTORM aurora forecast '+dt.strftime('%Y-%m-%d %H:%M UT' ), color='white',fontsize=15) fig.text(0.99,0.02,'C. Möstl / IWF-helio, Austria', color='white',fontsize=8,ha='right') #save as image with timestamp in filename plot_europe_canada_filename='results/forecast_europe_canada/predstorm_aurora_real_'+dt.strftime("%Y_%m_%d_%H%M") +'.jpg' fig.savefig(plot_europe_canada_filename,dpi=120,facecolor=fig.get_facecolor()) #save as movie frame framestr = '%05i' % (counter) fig.savefig('results/frames_europe_canada/aurora_'+framestr+'.jpg',dpi=120,facecolor=fig.get_facecolor()) #plt.show() print('Saved image: ',plot_europe_canada_filename)
def plot_map_and_stations(fig, gridspec, station_locations, station_names, station_plot_dict, region_corners=None, ss_location=None, date=None): map_ax = fig.add_subplot(gridspec, projection=ccrs.NearsidePerspective( -95, 57, 15000000)) map_ax.stock_img() # Plot the border of region if region_corners is not None: map_ax.plot(np.linspace(region_corners[0][0], region_corners[1][0], 10), np.ones(10) * region_corners[0][1], '--', color='gray', transform=ccrs.PlateCarree()) map_ax.plot(np.ones(10) * region_corners[1][0], np.linspace(region_corners[0][1], region_corners[1][1], 10), '--', color='gray', transform=ccrs.PlateCarree()) map_ax.plot(np.linspace(region_corners[0][0], region_corners[1][0], 10), np.ones(10) * region_corners[1][1], '--', color='gray', transform=ccrs.PlateCarree()) map_ax.plot(np.ones(10) * region_corners[0][0], np.linspace(region_corners[0][1], region_corners[1][1], 10), '--', color='gray', transform=ccrs.PlateCarree()) # plot all stations map_ax.plot(station_locations[:, 0], station_locations[:, 1], '.', color='black', transform=ccrs.PlateCarree()) # plot special stations for entry in station_plot_dict: map_ax.plot(station_locations[entry['indices'], 0], station_locations[entry['indices'], 1], '.', color=entry['color'], transform=ccrs.PlateCarree(), label=entry['name']) if entry['station names']: for j in entry['indices']: map_ax.text(station_locations[j, 0] - 1, station_locations[j, 1] - 1, station_names[j], horizontalalignment='right', transform=ccrs.PlateCarree()) map_ax.legend() if ss_location is not None: map_ax.plot(ss_location[0], ss_location[1], 'rx', transform=ccrs.PlateCarree()) if date is not None: map_ax.add_feature(Nightshade(date, alpha=0.2))
def plot_data_globe_colour(station_readings, t, list_of_stations=None, ortho_trans=(0, 0)): if np.all(list_of_stations == None): list_of_stations = station_readings.station if np.all(ortho_trans == (0, 0)): ortho_trans = svg.auto_ortho(list_of_stations) station_coords = svg.csv_to_coords() num_stations = len(list_of_stations) x = np.zeros(num_stations) y = np.zeros(num_stations) u = np.zeros(num_stations) v = np.zeros(num_stations) i = 0 for station in list_of_stations: x[i] = station_coords.longitude.loc[dict(station=station)] y[i] = station_coords.latitude.loc[dict(station=station)] u[i] = station_readings.measurements.loc[dict(station=station, time=t, component="E")] v[i] = station_readings.measurements.loc[dict(station=station, time=t, component="N")] i += 1 fig = plt.figure(figsize=(20, 20)) ax = fig.add_subplot(1, 1, 1, projection=ccrs.Orthographic( ortho_trans[0], ortho_trans[1])) #(long, lat) ax.add_feature(cfeature.OCEAN, zorder=0) ax.add_feature(cfeature.LAND, zorder=0, edgecolor='grey') ax.add_feature(cfeature.BORDERS, zorder=0, edgecolor='grey') ax.add_feature(cfeature.LAKES, zorder=0) ax.add_feature(Nightshade(t)) ax.set_global() ax.gridlines() ax.scatter(x, y, color="k", transform=ccrs.Geodetic()) #plots stations colours = np.ones((num_stations, 3)) for i in range(num_stations): colours[i, 0] = station_coords.longitude.loc[dict( station=list_of_stations[i])] / 360 colours[i, 2] = (station_coords.latitude.loc[dict( station=list_of_stations[i])] - 10) / 80 colours = plc.hsv_to_rgb(colours) ax.quiver( x, y, u, v, transform=ccrs.PlateCarree(), #plots vector data width=0.002, color=colours) mytime = t.strftime('%Y.%m.%d %H:%M') plt.title("%s" % mytime, fontsize=30) return fig
def main(): SPH_ORDER = 3 SPH_WEIGHT = 0.8 RESIDUAL_WEIGHT = 0.9 plt.clf() with urllib.request.urlopen(os.getenv("METRICS_URI")) as url: data = json.loads(url.read().decode()) df = json_normalize(data) #delete low confidence measurements df = df.drop(df[pd.to_numeric(df.cs) == 0].index) df = df.drop(df[df[metric] == 0].index) df = df.dropna(subset=[metric]) #filter out data older than 1hr age = (dt.datetime.now() - dt.timedelta(minutes=60)).strftime('%Y-%m-%d %H:%M') df = df.loc[df['time'] > age] df['time'] = pd.to_datetime(df.time) df['time'] = df['time'].dt.strftime('%Y-%m-%d %H:%M') df[[metric]] = df[[metric]].apply(pd.to_numeric) df[['station.longitude']] = df[['station.longitude']].apply(pd.to_numeric) df[['station.latitude']] = df[['station.latitude']].apply(pd.to_numeric) df['longitude_radians'] = df['station.longitude'] * np.pi / 180. df['latitude_radians'] = (df['station.latitude'] + 90) * np.pi / 180. df[['cs']] = df[['cs']].apply(pd.to_numeric) df.loc[df['cs'] == -1, 'cs'] = 80 df[['cs']] = df[['cs']] / 100. df['transformed'] = np.log(df[metric]) df = df.dropna(subset=[metric]) df.loc[df['station.longitude'] > 180, 'station.longitude'] = df['station.longitude'] - 360 df.sort_values(by=['station.longitude'], inplace=True) sph = [] alpha = [] for n in range(SPH_ORDER): for m in range(0 - n, n + 1): sph.append( real_sph(m, n, df['longitude_radians'].values, df['latitude_radians'].values).reshape((-1, 1))) alpha.append(0 if n == 0 else 0.005) sph = np.hstack(sph) wls_model = sm.WLS(df['transformed'].values, sph, df['cs'].values) wls_result = wls_model.fit_regularized(alpha=np.array(alpha), L1_wt=0.6) coeff = wls_result.params numcols, numrows = 360, 180 loni = np.linspace(-180, 180, numcols) lati = np.linspace(-90, 90, numrows) theta = loni * np.pi / 180. phi = (lati + 90) * np.pi / 180. zi = np.zeros((len(phi), len(theta))) theta, phi = np.meshgrid(theta, phi) df['pred'] = np.zeros(len(df)) coeff_idx = 0 for n in range(SPH_ORDER): for m in range(0 - n, n + 1): sh = real_sph(m, n, theta, phi) weight = 1 if n == 0 else SPH_WEIGHT zi = zi + weight * coeff[coeff_idx] * sh df['pred'] = df['pred'] + weight * np.real( coeff[coeff_idx] * real_sph(m, n, df['longitude_radians'].values, df['latitude_radians'].values)) coeff_idx = coeff_idx + 1 df['residual'] = df['transformed'] - df['pred'] #plot data loni, lati = np.meshgrid(loni, lati) x, y, z = sph_to_xyz(df['station.longitude'].values, df['station.latitude'].values) t = df['residual'].values stdev = 0.7 - 0.5 * df['cs'] gp = rbf.gauss.gpiso(rbf.basis.se, (0.0, 0.7, 0.8)) gp_cond = gp.condition(np.vstack((x, y, z)).T, t, sigma=stdev) xxi, yyi, zzi = sph_to_xyz(loni, lati) xyz = np.array([xxi.flatten(), yyi.flatten(), zzi.flatten()]).T resi, sd = gp_cond.meansd(xyz) resi = resi.reshape(xxi.shape) sd = sd.reshape(xxi.shape) zi = zi + RESIDUAL_WEIGHT * resi zi = np.exp(zi) fig = plt.figure(figsize=(16, 24)) ax = plt.axes(projection=ccrs.PlateCarree()) levels = 16 cmap = plt.cm.get_cmap('viridis') cmap.set_under(cmap(1e-5)) cmap.set_over(cmap(1 - 1e-5)) norm = matplotlib.colors.Normalize(clip=False) if metric == 'mufd': levels = [ 3, 3.5, 4, 4.6, 5.3, 6.1, 7, 8.2, 9.5, 11, 12.6, 14.6, 16.9, 19.5, 22.6, 26, 30 ] norm = matplotlib.colors.LogNorm(3.5, 30, clip=False) mycontour = plt.contourf(loni, lati, zi, levels, cmap=cmap, extend='both', transform=ccrs.PlateCarree(), alpha=0.3, norm=norm) ax.add_feature( cartopy.feature.NaturalEarthFeature('physical', 'land', '110m', edgecolor='face', facecolor=np.array( (0xdd, 0xdd, 0xcc)) / 256., zorder=-1)) ax.set_global() ax.add_feature(Nightshade(date, alpha=0.08)) ax.grid(linewidth=.5, color='black', alpha=0.25, linestyle='--') ax.set_xticks([ -180, -160, -140, -120, -100, -80, -60, -40, -20, 0, 20, 40, 60, 80, 100, 120, 140, 160, 180 ], crs=ccrs.PlateCarree()) ax.set_yticks([-80, -60, -40, -20, 0, 20, 40, 60, 80], crs=ccrs.PlateCarree()) for index, row in df.iterrows(): lon = float(row['station.longitude']) lat = float(row['station.latitude']) alpha = 0.2 + 0.6 * row['cs'] ax.text(lon, lat, int(row[metric] + 0.5), fontsize=9, ha='left', transform=ccrs.PlateCarree(), alpha=alpha, bbox={ 'boxstyle': 'circle', 'alpha': alpha - 0.1, 'color': cmap(norm(row[metric])), 'mutation_scale': 0.5, }) CS2 = plt.contour(mycontour, linewidths=.5, alpha=0.66, levels=mycontour.levels[1::1]) prev = None levels = [] for lev in CS2.levels: if prev is None or '%.0f' % (lev) != '%.0f' % (prev): levels.append(lev) prev = lev plt.clabel(CS2, levels, inline=True, fontsize=10, fmt='%.0f', use_clabeltext=True) # Make a colorbar for the ContourSet returned by the contourf call. cbar = plt.colorbar(mycontour, fraction=0.03, orientation='horizontal', pad=0.02, format=matplotlib.ticker.ScalarFormatter()) #cbar.set_label('MHz') #TODO add unit cbar.add_lines(CS2) plt.title(metric + ' ' + str(now)) # df = df[['station.name', 'time', metric, 'cs', 'altitude', 'station.longitude', 'station.latitude']] # df = df.round(2) # the_table = table(ax, df, # bbox=[0,-1.25,1,1], # cellLoc = 'left',) # for key, cell in the_table.get_celld().items(): # cell.set_linewidth(.25) plt.tight_layout() plt.savefig('/output/{}.png'.format(metric), dpi=180, bbox_inches='tight') plt.savefig('/output/{}.svg'.format(metric), dpi=180, bbox_inches='tight') # Convert matplotlib contour to geojson """
place = np.array([0, np.pi / 2., np.pi, 1.5 * np.pi]) lab = ['', 'dawn', 'noon', 'dusk'] plt.xticks(place, lab) #, ) ax1.set_ylim(0, 10) ax1.set_xlim(0, 2. * np.pi) ax1.set_frame_on(False) #ax1.axes.get_xaxis().set_visible(False) #ax1.axes.get_yaxis().set_visible(False) #This will be the geographic plot ax = fig.add_subplot(1, 2, 2, projection=ccrs.Orthographic(180, -90)) ax.coastlines(zorder=3) ax.stock_img() ax.gridlines() ax.add_feature(Nightshade(dt)) for i in range(len(payload)): print('starting to plot payload ', payload[i]) #Here we are just defining the different colors to be used. This could also be done outside the loop in an array and then use mkrcolor[i] in the plotting portion, This was just an easy way for me to make sure I knew which payload was which color... The program would run faster if done the way mentioned above, but it's pretty quick already. Save to change when doing a larger project. if payload[i] == '2I': mkrcolor = cdk #'navy' #Make sure we have the right sting. If I were to do this for a longer period of time, the same would need to be done for the month ect.... if day < 10: strday = '0' + np.str(np.int(day)) else: strday = np.str(day) #Read in the data and get the relavent data bits. payload_ephm = 'data/bar_' + payload[ i] + '_l2_ephm_201401' + strday + '_v04.cdf' data = pycdf.CDF(payload_ephm)
def plot_ISS(trackdf, nhours_plot=1): fig = plt.figure(figsize=(20, 10)) projection_type = ccrs.PlateCarree() ax = fig.add_subplot(1, 1, 1, projection=projection_type) ax.coastlines(resolution='50m', linewidth=0.3) timestart = trackdf.index[-1] - np.timedelta64(nhours_plot, 'h') track = trackdf.iloc[:1000] jump_indices = list(track[abs(track['londiff']) > 330].index) for i in range(len(jump_indices)): if i == 0: subtrack = track[:jump_indices[0]] else: subtrack = track[jump_indices[i - 1]:jump_indices[i]].iloc[1:] track_points = sgeom.LineString(zip(subtrack['Lon'], subtrack['Lat'])) ax.add_geometries([track_points], projection_type,facecolor='none', \ edgecolor='r',alpha=0.8) #plot the locations as points ax.plot(subtrack['Lon'], subtrack['Lat'], 'ko', transform=projection_type, markersize=0.5) #plot the final subtrack subtrack = track[jump_indices[i]:].iloc[1:] track_points = sgeom.LineString(zip(subtrack['Lon'], subtrack['Lat'])) ax.add_geometries([track_points], projection_type,facecolor='none', \ edgecolor='r',alpha=0.8) #plot the locations as points ax.plot(subtrack['Lon'], subtrack['Lat'], 'ko', transform=projection_type, markersize=0.5) #Get current location current_lon, current_lat = getISSloc() ax.plot(current_lon, current_lat, 'bo', transform=projection_type, markersize=20) #Get current time date = datetime.utcnow() ax.set_title('ISS history and position for {}'.format(date)) ax.stock_img() ax.add_feature(Nightshade(date, alpha=0.2)) #plt.show() plt.savefig('Latest_ISS_plot.pdf', dpi=200)
#img, crs, extent, origin, dt = aurora_forecast() fig.set_facecolor((0, 0, 0)) url = 'https://map1c.vis.earthdata.nasa.gov/wmts-geo/wmts.cgi' layer = 'VIIRS_CityLights_2012' for ax in [ax1, ax2]: ax.coastlines(zorder=3, color='grey', alpha=0.9) ax.add_feature(carfeat.BORDERS, zorder=3, alpha=0.9) #ax.stock_img() #takes long!! #ax.add_wmts(url, layer) ax.gridlines(alpha=0.3) ax.add_feature(Nightshade(dtovation), alpha=0.9) #ax.imshow(img, vmin=0, vmax=100, transform=crs, extent=extent, origin=origin, zorder=2, cmap=aurora_cmap()) ax.imshow(pimg, vmin=0, vmax=100, transform=crs, extent=extent, origin=origin, zorder=2, cmap=aurora_cmap()) plt.show() #plt.tight_layout() fig.savefig('predstorm_aurora_pred_' + dtovation.strftime("%Y_%m_%d_%H%M") + '.png', dpi=300)
""" import pygeode as pyg, numpy as np, pylab as pyl from cartopy import crs as ccrs import cartopy from cartopy.feature.nightshade import Nightshade from datetime import datetime as dt lat = pyg.gausslat(60) lon = pyg.regularlon(120) x = pyg.sin(2*np.pi * lon / 180.) * pyg.exp(-(lat - 30)**2 / (2*10**2)) y = pyg.sin(2*np.pi * lon / 180.) * pyg.exp(-(lat + 40)**2 / (2*10**2)) pyl.ioff() prj = dict(central_longitude = 60) #ax = pyg.plot.CartopyAxes(projection = 'NearsidePerspective', prj_args = prj) map = dict(projection = 'NearsidePerspective', prj_args = prj) #map = dict(projection = 'LambertConformal', prj_args = prj) cl = pyg.cldict(0.1, nozero=True) ax = pyg.vcontour(x, map = map, **cl) ax.add_feature(cartopy.feature.OCEAN) ax.add_feature(Nightshade(dt.utcnow())) ax.setp(title = '') pyl.ion() ax.render(2) ax.ax.tissot(facecolor='orange', alpha=0.8)
plt.plot([inv_lon, inv_lon], [inv_lat, inv_lat], 'bo', markersize=radar_marker_size, transform=ccrs.Geodetic(), label="INV") # Add RISR to the map plt.plot([risr_lon, risr_lon], [risr_lat, risr_lat], 'ro', markersize=radar_marker_size, transform=ccrs.Geodetic(), label="RISR", zorder=3) date_time = datetime.utcnow() ax.add_feature(Nightshade(date_time, alpha=0.25)) # ax.set_title("Night time shading for " + str(date_time) + " UT") ax.set_title("One-and-one-half-hop Geometry Check") # Try to plot RKN's FoV # RKN is id 65 ranges = [0, 100] rkn_beam_corners_lats, rkn_beam_corners_lons = radar_fov(65, coords='geo') rkn_fan_shape = rkn_beam_corners_lons.shape inv_beam_corners_lats, inv_beam_corners_lons = radar_fov(64, coords='geo') inv_fan_shape = inv_beam_corners_lons.shape # plot all the RKN beam boundary lines for beam_line in range(rkn_fan_shape[1]):
def ovation_global_north(wic,dt,colormap_input,max_level, outputdir,longitude_bound,equatorial_bound): ''' plots the ovation aurora on the northern hemisphere from a polar view, makes movie frames wic is a world image cube with ovation results 512x1024 dt are the datetimes for each frame colormap_input is the colormap max_level is the maximum level for the colorbar ''' #plotting parameters #-100 for North America, +10 or 0 for Europe global_plot_longitude=-100 #global_plot_longitude=0 global_plot_latitude=90 provinces_50m = carfeat.NaturalEarthFeature('cultural', 'admin_1_states_provinces_lines', '50m', facecolor='none',edgecolor='black') #define extent of the produced world maps - defined as: west east south north mapextent=[-180,180,-90,90] #need to set alpha linearly increasing in the colormap so that it blends into background for #small values cmap = plt.get_cmap(colormap_input) # Choose colormap my_cmap = cmap(np.arange(cmap.N)) # Get the colormap colors my_cmap[:,-1] = np.linspace(0, 1, cmap.N) # Set alpha my_cmap = ListedColormap(my_cmap) # Create new colormap crs=ccrs.PlateCarree() fig = plt.figure(2,figsize=[12, 12],dpi=80) fig.set_facecolor('black') fig.text(0.99,0.01,'C. Möstl / IWF-helio, Austria', color='white',fontsize=10,ha='right',va='bottom') ax = plt.subplot(1, 1, 1, projection=ccrs.Orthographic(global_plot_longitude, global_plot_latitude)) ax.background_patch.set_facecolor('k') gl=ax.gridlines(linestyle='--',alpha=0.5,color='white') #make grid gl.n_steps=100 #make grid finer ax.stock_img() #ax.coastlines('50m',color='black',alpha=0.5) ax.coastlines('50m',color='white',alpha=0.9) ax.add_feature(provinces_50m,alpha=0.2) #,zorder=2,alpha=0.8) ax.add_feature(carfeat.BORDERS, alpha=0.2) #,zorder=2,alpha=0.5) #these are calls that create the first object to be removed from the plot with each frame txt=fig.text(0.5,0.92,'') border=ax.add_feature(Nightshade(dt[0])) #add day night border img=ax.imshow(wic[:,:,0]) bound_e=ax.plot(0,color='k') #equatorial boundary bound_v=ax.plot(0,color='k') #equatorial boundary for i in np.arange(0,np.size(dt)): print('global movie frame',i) #plt.cla() #clear axes txt.set_visible(False) #clear previous plot title #plot title with time txt=fig.text(0.5,0.92,'PREDSTORM aurora '+dt[i].strftime('%Y-%m-%d %H:%M UT'), color='white',fontsize=15, ha='center') img.remove() #remove previous wic border.remove() #remove previous nightshade bound_e[0].remove() #remove equatorial boundary bound_v[0].remove() #remove view line border=ax.add_feature(Nightshade(dt[i])) #add day night border img=ax.imshow(wic[:,:,i], vmin=0.01, vmax=max_level, transform=crs, extent=mapextent, origin='lower', zorder=3, alpha=0.8, cmap=my_cmap) #aurora bound_e=ax.plot(longitude_bound,equatorial_bound[i,:],transform=crs,color='k',alpha=0.8) #equatorial boundary #***cut view line at longitudes which are in daylight bound_v=ax.plot(longitude_bound,equatorial_bound[i,:]-8,transform=crs,color='r',linestyle='--',alpha=0.8) #viewing line after Case et al. 2016 #save as image with timestamp in filename #plot_Nhemi_filename='results/forecast_global/predstorm_aurora_real_Nhemi_'+dt.strftime("%Y_%m_%d_%H%M") +'.jpg' #fig.savefig(plot_Nhemi_filename,dpi=150,facecolor=fig.get_facecolor()) #save as movie frame framestr = '%05i' % (i) fig.savefig('results/'+outputdir+'/frames_global/aurora_'+framestr+'.jpg',dpi=150,facecolor=fig.get_facecolor())
def plotCartoMap(latlim=None, lonlim=None, parallels=None, meridians=None, pole_center_lon=0, figsize=(12, 8), terrain=False, ax=False, projection='stereo', title='', resolution='110m', states=True, grid_linewidth=0.5, grid_color='black', grid_linestyle='--', background_color=None, border_color='k', figure=False, nightshade=False, ns_dt=None, ns_alpha=0.1, apex=False, igrf=False, date=None, mlat_levels=None, mlon_levels=None, alt_km=0.0, mlon_colors='blue', mlat_colors='red', mgrid_width=1, mgrid_labels=True, mgrid_fontsize=12, mlon_cs='mlon', incl_levels=None, decl_levels=None, igrf_param='incl', mlon_labels=True, mlat_labels=True, mgrid_style='--', label_colors='k', decl_colors='k', incl_colors='k'): if lonlim is None: if projection in ['southpole', 'northpole']: lonlim = [-180, 180] else: lonlim = [-40, 40] if latlim is None: if projection is'southpole': latlim = [-90, 0] elif projection is 'northpole': latlim = [90, 0] else: latlim = [0, 75] STATES = cfeature.NaturalEarthFeature( category='cultural', name='admin_1_states_provinces_lines', scale='50m', facecolor='none') if not ax: if figsize is None: fig = plt.figure() else: fig = plt.figure(figsize=figsize) if projection == 'stereo': ax = plt.axes(projection=ccrs.Stereographic(central_longitude=(sum(lonlim) / 2))) elif projection == 'merc': ax = plt.axes(projection=ccrs.Mercator()) elif projection == 'plate': ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=(sum(lonlim) / 2))) elif projection == 'lambert': ax = plt.axes(projection=ccrs.LambertConformal(central_longitude=(sum(lonlim) / 2), central_latitude=(sum(latlim) / 2))) elif projection == 'mollweide': ax = plt.axes(projection=ccrs.Mollweide(central_longitude=(sum(lonlim) / 2))) elif projection == 'northpole': ax = plt.axes(projection=ccrs.NorthPolarStereo()) ax.set_boundary(circle, transform=ax.transAxes) # polarLim(ax, projection) elif projection == 'southpole': ax = plt.axes(projection=ccrs.SouthPolarStereo()) ax.set_boundary(circle, transform=ax.transAxes) # polarLim(ax, projection) if background_color is not None: ax.background_patch.set_facecolor(background_color) ax.set_title(title) ax.coastlines(color=border_color, resolution=resolution) # 110m, 50m or 10m if states: ax.add_feature(STATES, edgecolor=border_color) ax.add_feature(cfeature.BORDERS, edgecolor=border_color) if terrain: ax.stock_img() if nightshade: assert ns_dt is not None assert ns_alpha is not None ax.add_feature(Nightshade(ns_dt, ns_alpha)) # Draw Parallels if projection == 'merc' or projection == 'plate': if isinstance(meridians, np.ndarray): meridians = list(meridians) if isinstance(parallels, np.ndarray): parallels = list(parallels) gl = ax.gridlines(crs=ccrs.PlateCarree(), color=grid_color, draw_labels=False, linestyle=grid_linestyle, linewidth=grid_linewidth) if meridians is None: gl.xlines = False else: if len(meridians) > 0: gl.xlocator = mticker.FixedLocator(meridians) gl.xlabels_bottom = True else: gl.ylines = False if parallels is None: gl.ylines = False else: if len(parallels) > 0: gl.ylocator = mticker.FixedLocator(parallels) # ax.yaxis.set_major_formatter(LONGITUDE_FORMATTER) gl.ylabels_left = True else: gl.ylines = False else: gl = ax.gridlines(crs=ccrs.PlateCarree(), color=grid_color, draw_labels=False, linestyle=grid_linestyle, linewidth=grid_linewidth) if meridians is None: gl.xlines = False else: # if isinstance(meridians, np.ndarray): # meridians = list(meridians) # ax.xaxis.set_major_formatter(LONGITUDE_FORMATTER) # ax.yaxis.set_major_formatter(LATITUDE_FORMATTER) # if isinstance(meridians, np.ndarray): # meridians = list(meridians) gl.xlocator = mticker.FixedLocator(meridians) # else: # gl.xlines = False if parallels is not None: if isinstance(parallels, np.ndarray): parallels = list(parallels) gl.ylocator = mticker.FixedLocator(parallels) else: gl.ylines = False # Geomagnetic coordinates @ Apex if apex: if date is None: date = datetime(2017, 12, 31, 0, 0, 0) assert isinstance(date, datetime) A = ap.Apex(date=date) # Define levels and ranges for conversion if mlon_cs == 'mlt': if mlon_levels is None: mlon_levels = np.array([]) mlon_range = np.arange(0, 24.1, 0.1) elif isinstance(mlon_levels, bool): if mlon_levels == False: mlon_levels = np.array([]) mlon_range = np.arange(0, 24.1, 0.1) else: mlon_range = np.arange(mlon_levels[0], mlon_levels[-1] + 0.1, 0.1) else: if mlon_levels is None: mlon_levels = np.array([]) mlon_range = np.arange(-180, 180, 0.5) elif isinstance(mlon_levels, bool): if mlon_levels == False: mlon_levels = np.array([]) mlon_range = np.arange(-180, 181, 0.1) else: mlon_range = np.arange(mlon_levels[0], mlon_levels[0] + 362, 0.1) if mlat_levels is None: mlat_levels = np.arange(-90, 90.1, 5) mlat_range = np.arange(mlat_levels[0], mlat_levels[-1] + 0.1, 0.1) # Do meridans for mlon in mlon_levels: MLON = mlon * np.ones(mlat_range.size) if mlon_cs == 'mlt': y, x = A.convert(mlat_range, MLON, 'mlt', 'geo', datetime=date) else: y, x = A.convert(mlat_range, MLON, 'apex', 'geo') # Plot meridian inmap = np.logical_and(x >= lonlim[0], x <= lonlim[1]) if np.sum(inmap) > 10: ax.plot(np.unwrap(x, 180), np.unwrap(y, 90), c=mlon_colors, lw=mgrid_width, linestyle=mgrid_style, transform=ccrs.PlateCarree()) # Labels if mlon_labels: ix = np.argmin(abs(y - np.mean(latlim))) mx = x[ix] - 1 if mlon >= 10 else x[ix] - 0.5 my = np.mean(latlim) if np.logical_and(mx >= lonlim[0], mx <= lonlim[1]): if mlon_cs == 'mlt' and mlon != 0: ax.text(mx, my, str(int(mlon)), color=label_colors, fontsize=14, backgroundcolor='white', transform=ccrs.PlateCarree()) elif mlon_cs != 'mlt' and mlon != 360: ax.text(mx, my, str(int(mlon)), color=label_colors, fontsize=14, backgroundcolor='white', transform=ccrs.PlateCarree()) # Do parallels for mlat in mlat_levels: MLAT = mlat * np.ones(mlon_range.size) if mlon_cs == 'mlt': gy, gx = A.convert(MLAT, mlon_range, 'mlt', 'geo', datetime=date) else: gy, gx = A.convert(MLAT, mlon_range, 'apex', 'geo', datetime=date) inmap = np.logical_and(gy >= latlim[0], gy <= latlim[1]) if np.sum(inmap) > 2: ax.plot(np.unwrap(gx, 180), np.unwrap(gy, 90), c=mlat_colors, lw=mgrid_width, linestyle=mgrid_style, transform=ccrs.PlateCarree()) # Labels if mlat_labels: ix = np.argmin(abs(gx - np.mean(lonlim))) mx = np.mean(lonlim) my = gy[ix] - 0.5 if np.logical_and(mx >= lonlim[0], mx <= lonlim[1]) and \ np.logical_and(my >= latlim[0], my <= latlim[1]): ax.text(mx, my, str(int(mlat)), color=label_colors, fontsize=14, backgroundcolor='white', transform=ccrs.PlateCarree()) if igrf: glon = np.arange(lonlim[0] - 40, lonlim[1] + 40.1, 0.5) glat = np.arange(-90, 90 + 0.1, 0.5) longrid, latgrid = np.meshgrid(glon, glat) mag = igrf12.gridigrf12(t=date, glat=latgrid, glon=longrid, alt_km=alt_km) if decl_levels is not None: z = mag.decl.values for declination in decl_levels: ax.contour(longrid, latgrid, z, levels=declination, colors=decl_colors, transform=ccrs.PlateCarree()) if incl_levels is not None: z = mag.incl.values for inclination in incl_levels: ax.contour(longrid, latgrid, z, levels=declination, colors=incl_colors, transform=ccrs.PlateCarree()) # Set Extent ax.set_extent([lonlim[0], lonlim[1], latlim[0], latlim[1]], crs=ccrs.PlateCarree()) if 'fig' in locals(): return fig, ax else: return ax
def process_gcn(payload, root): if write_event: event_log = open(logfile, 'a+') # Respond only to 'test' events. # VERY IMPORTANT! Replace with the following code # to respond to only real 'observation' events. print("starting process") print(datetime.utcnow()) if write_event: event_log.write("starting process") event_log.write('\n') event_log.write(root.attrib['role']) event_log.write('\n') print(root.attrib['role']) """ Uncomment when we only want to do real observations if root.attrib['role'] != 'observation': return """ # Read all of the VOEvent parameters from the "What" section. params = {elem.attrib['name']: elem.attrib['value'] for elem in root.iterfind('.//Param')} # Respond only to 'CBC' events. Change 'CBC' to "Burst' # to respond to only unmodeled burst events. print(params['Group']) if write_event: event_log.write(params['Group']) event_log.write('\n') if params['Group'] != 'CBC': print('not CBC') return if params['AlertType'] != 'Preliminary': print('not Preliminary') return if 'Pkt_Ser_Num' in params: # Test events send same event twice, only choose first one. check = float(params['Pkt_Ser_Num']) if check > 1.1: return """ COMPLETE TO DEFINE WHICH EVENTS WE ARE LOOKING FOR if 'BNS' in params: check = float(params['BNS']) if check < 50.0: print("not BNS event, skipping") return else: print("not BNS event, skipping") return """ # Print all parameters. for key, value in params.items(): print(key, '=', value) if write_event: event_log.writelines(str(key + '=' + value)) if 'skymap_fits' in params: # Read the HEALPix sky map and the FITS header.i skymap, header = hp.read_map(params['skymap_fits'], h=True, verbose=False) header = dict(header) # Print some values from the FITS header. print('Distance =', header['DISTMEAN'], '+/-', header['DISTSTD']) if write_event: event_log.writelines('Distance =' + str(header['DISTMEAN']) + '+/-' + str(header['DISTSTD'])) event_log.write('\n') # write event information to SQL datadict = {'gracedb_id': [params['GraceID']], 'link': [params['EventPage']], 'dist': [header['DISTMEAN']], 'dist_err': [header['DISTSTD']]} sql_engine = sql.create_engine(connect_string) headers = ['gracedb_id', 'link', 'dist', 'dist_err'] dtypes = {'gracedb_id': 'str', 'link': 'str', 'dist': 'float64', 'dist_err': 'float64'} df = pd.DataFrame.from_dict(datadict) df.to_sql('events', sql_engine, if_exists='append', index=False) # get event ID back query = "select * from events ORDER BY 'ID' DESC" df = pd.read_sql_query(query, sql_engine) event = df['ID'].iloc[-1] credible_levels = find_greedy_credible_levels(skymap) if send_slack: slackmsg = "" for key, value in params.items(): slackmsg = slackmsg + str(key) + '=' + str(value) + '\n' slack_client.chat_postMessage(channel=SLACK_CHANNEL, text=slackmsg) # get df of galaxies from SQL query = "select * from galaxies" galaxies = pd.read_sql_query(query, sql_engine) gal_ipix = getPixel(skymap, galaxies['ra'], galaxies['dec']) """ offset = ephem.Observer() offset.lat = '0.0' offset.long = '180' offset.date = datetime.utcnow() offangle = float(offset.sidereal_time() * 180 / np.pi) """ if plot_map: #ax = plt.axes(projection=ccrs.Mollweide(central_longitude=-1 * offangle)) ax = plt.axes(projection=ccrs.Mollweide()) ax.stock_img() galaxies['credible'] = credible_levels[gal_ipix] banana_galaxies = galaxies[(galaxies.credible <= prob_check)] banana_galaxies.sort_values(by=['credible'], inplace=True) #get list of observatories from SQL query = "select * from observers" observatories = pd.read_sql_query(query, sql_engine) #Find Sun RA/DEC sun = ephem.Sun() #setup pyephem observer telescope = ephem.Observer() telescope.date = datetime.utcnow() #create a copy of galaxy list in case it ends up depleted galaxy_list = copy.deepcopy(banana_galaxies) galaxy_list = galaxy_list.values.tolist() galaxy_depleted = False slackmsg = '' matches = [] slack_count = 0 for x in range(0, len(observatories)): extra_matches = [] # Check if all galaxies have been assigned, if so start assigning duplicates if len(galaxy_list) == 0: galaxy_list = copy.deepcopy(banana_galaxies) galaxy_list = galaxy_list.values.tolist() galaxy_depeleted = True telescope.lat = str(observatories['lat'][x]).strip() telescope.long = str(observatories['lon'][x]).strip() sun.compute(telescope) # if sun is up, observatory can be skipped if check_sun: if sun.alt > max_sun: # print(str(observatories['Code'][x]) + " skipped, Sun is up") continue for i in range(0, len(galaxy_list)): star = ephem.FixedBody() star._ra = ephem.degrees(str(galaxy_list[i][2])) star._dec = ephem.degrees(str(galaxy_list[i][3])) star.compute(telescope) # if the first object is more than 20 degrees below elevation, unlikely any objects will be higher than 45 degrees if check_minalt: if star.alt < min_alt: # print(str(observatories['Code'][x]) + " skipped " + str(star.alt) + " is less than -20 degrees") break # assign galaxy to observer if star.alt > max_alt: matches.append( {'event_id': event, 'obs_ID': observatories['ID'][x], 'galaxy_id': galaxy_list[i][0]}) # print(galaxy_list[i]) listing = WEBSITE_URL+'/observe?key=' + str( observatories['key'][x]) + '&event=' + str(event) + '&obs=' + str( observatories['ID'][x]) + '&gal=' + str(galaxy_list[i][0]) + '&ra=' + str( galaxy_list[i][2]) + '&dec=' + str(galaxy_list[i][3]) + '&fov=' + str(observatories['fov'][x]) print(listing) if write_event: event_log.writelines(listing) event_log.write('\n') #only writing the first 5 urls to slack if send_slack: if slack_count < 5: slack_count += 1 slackmsg = slackmsg + listing + '\n' #find extra galaxies within FOV j = i+1 y = [] print(len(galaxy_list[j:])) if galinfov: for z in range(j,len(galaxy_list)): extra = ephem.FixedBody() extra._ra = ephem.degrees(str(galaxy_list[z][2])) extra._dec = ephem.degrees(str(galaxy_list[z][3])) extra.compute(telescope) sep = float(ephem.separation(star,extra))*180/np.pi if sep < 0.5/2: #if sep < observatories['fov'][x]/2: extra_matches.append({'event_id': event, 'obs_ID': observatories['ID'][x], 'galaxy_id': galaxy_list[z][0]}) print(z,sep,ephem.separation(star,extra)) y.append(z) if len(y)>1: print(y) y.reverse() for k in y: del galaxy_list[k] # print(str(observatories['ID'][x]) + " " + observatories['name'][x].strip()[15:] + " at Lat:" +str(telescope.lat) + ",Lon:" + str(telescope.lon) + " gets galaxy " + str(galaxy_list[i][1]) + ' ra='+str(star.ra) + ' dec=' + str(star.dec) + ' alt='+str(star.alt)) del galaxy_list[i] if plot_map: plt.scatter(telescope.lon * 180 / np.pi, telescope.lat * 180 / np.pi, color='red', transform=ccrs.Geodetic()) break if len(extra_matches) > 0: extra_matches = pd.DataFrame(extra_matches) extra_matches.to_sql('matches_extra', sql_engine, if_exists='append', index=False) matches = pd.DataFrame(matches) matches.to_sql('matches', sql_engine, if_exists='append', index=False) event_log.close() if send_slack: if len(slackmsg) > 0: slack_client.chat_postMessage(channel=SLACK_CHANNEL, text=slackmsg) if galaxy_depleted: text = "All" + str(len(banana_galaxies)) + " galaxies assigned" query = "update events set assigned = " + str(len(banana_galaxies)) + ", possible = " + str( len(banana_galaxies)) + " where ID = " + str(event) else: text = str(len(banana_galaxies) - len(galaxy_list)) + " galaxies assigned out of " + str( len(banana_galaxies)) query = "update events set assigned = " + str( len(banana_galaxies) - len(galaxy_list)) + ", possible = " + str( len(banana_galaxies)) + " where ID = " + str(event) slack_client.chat_postMessage(channel=SLACK_CHANNEL, text=text) sql_engine.execute(query) else: slack_client.chat_postMessage(channel=SLACK_CHANNEL, text="No Galaxies Assigned") if plot_map: ax.add_feature(Nightshade(datetime.utcnow(), alpha=0.2)) plt.title("Map of Observable Sites") plt.savefig("map.png") if send_slack: slack_client.files_upload(channels=SLACK_CHANNEL, file="map.png", title=params['GraceID']) filename = download_file(params['skymap_fits'], cache=True) skyplot([filename, '--annotate', '--geo', '--contour', '50', '90']) plt.savefig("hp.png") if send_slack: slack_client.files_upload(channels=SLACK_CHANNEL, file="hp.png", title=params['GraceID']) return
def plot_swath_grid(lon, lat, field, varname, levname, varunits, nrows, ncols, cen_lon, date, nightshade, date_str, title_str): """ ---------------------------------------------------------------------------- This function plots a swath of footprint-level data FLASHFlux, SSF, or CRS ---------------------------------------------------------------------------- :param lon: FOV longitude :param lat: FOV latitude :param field: variable :param varname: variable name :param levname: level name :param varunits: variable units :param nrows: number of rows :param ncols: number of columns :param cen_lon: central longitude :param cmap: colormap :param cmap_lims: colormap limits :param date: date info for nightshade :param nightshade: whether to use nighshade feature :param date_str: date string :param title_str: title string ---------------------------------------------------------------------------- :return: plot of the data """ import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature from mpl_toolkits.axes_grid1 import AxesGrid from cartopy.mpl.geoaxes import GeoAxes from cartopy.feature.nightshade import Nightshade # Map projection projection = ccrs.PlateCarree(central_longitude=cen_lon) # Axis class axes_class = (GeoAxes, dict(map_projection=projection)) # Create figure fig = plt.figure(figsize=(11, 8)) axgr = AxesGrid(fig, 111, axes_class=axes_class, nrows_ncols=(nrows, ncols), axes_pad=(0.4, 0.4), share_all=True, cbar_location='right', cbar_mode='single', cbar_pad=+0.2, cbar_size='3%', label_mode=1) # Loop over axes for i, ax in enumerate(axgr): if i == 14: break ax.add_feature(cartopy.feature.LAND, zorder=1, facecolor='none', edgecolor='darkgrey') ax.gridlines(color='grey', linestyle='--') ax.set_title(title_str + ' surface flux in band ' + str(i + 1) + ' - all sky', fontsize=8) ax.set_extent([-180, 180, -90, 90], projection) ax.text(0.5, -0.1, varname + ' - ' + levname + '\n' + varunits, va='bottom', ha='center', rotation='horizontal', rotation_mode='anchor', transform=ax.transAxes, fontsize=10) if nightshade == 1: ax.add_feature(Nightshade(date, alpha=0.1)) # To use a different colorbar range each time, use a tuple of tuples # limits = ((0, 120), (0, 120), (0, 120), (0, 120), (0, 120), (0, 120), (0, 120), # (0, 120), (0, 120), (0, 120), (0, 120), (0, 120), (0, 120), (0, 120)) limits = (0, 70) for i in range((nrows * ncols)): if i == 14: break im = axgr[i].scatter(lon, lat, c=field[:, i], s=1, transform=ccrs.PlateCarree(), vmin=limits[0], vmax=limits[1], cmap=lw_colormap) axgr.cbar_axes[i].colorbar(im) plt.tight_layout() plt.show() return
def plotCartoMap(latlim=[0, 75], lonlim=[-40, 40], parallels=None, meridians=None, pole_center_lon=0, figsize=(12, 8), terrain=False, ax=False, projection='stereo', title='', resolution='110m', lon0=None, lat0=None, states=True, grid_linewidth=0.5, grid_color='black', grid_linestyle='--', background_color=None, border_color='k', figure=False, nightshade=False, ns_alpha=0.1, apex=False, igrf=False, date=None, mlat_levels=None, mlon_levels=None, alt_km=0.0, mlon_colors='blue', mlat_colors='red', mgrid_width=1, mgrid_labels=True, mgrid_fontsize=12, mlon_cs='mlon', incl_levels=None, decl_levels=None, igrf_param='incl', mlon_labels=True, mlat_labels=True, mgrid_style='--', label_colors='k', apex_alt=0, decl_colors='k', incl_colors='k', terminator=False, terminator_altkm=350, polarization_terminator=False, pt_hemisphere='north', ter_color='red', ter_style='--', ter_width=2, midnight=False, midnight_colors='m', midnight_width=2, midnight_style='--'): if lonlim is None or lonlim == []: lonlim = [-180, 180] STATES = cfeature.NaturalEarthFeature( category='cultural', name='admin_1_states_provinces_lines', scale='50m', facecolor='none') if not ax: if figsize is None: fig = plt.figure() else: fig = plt.figure(figsize=figsize) if projection == 'stereo': ax = plt.axes(projection=ccrs.Stereographic( central_longitude=(sum(lonlim) / 2))) elif projection == 'merc': ax = plt.axes(projection=ccrs.Mercator()) elif projection == 'plate': ax = plt.axes(projection=ccrs.PlateCarree( central_longitude=(sum(lonlim) / 2))) elif projection == 'lambert': ax = plt.axes(projection=ccrs.LambertConformal( central_longitude=(sum(lonlim) / 2), central_latitude=(sum(latlim) / 2))) elif projection == 'mollweide': ax = plt.axes(projection=ccrs.Mollweide( central_longitude=(sum(lonlim) / 2))) elif projection == 'north': if lon0 is None: lon0 = 0 ax = plt.axes(projection=ccrs.NorthPolarStereo( central_longitude=lon0)) elif projection == 'south': if lon0 is None: lon0 = 0 ax = plt.axes(projection=ccrs.SouthPolarStereo( central_longitude=lon0)) elif projection == 'ortographic': if lon0 is None: lon0 = 0 if lat0 is None: lat0 = 0 ax = plt.axes(projection=ccrs.Orthographic(central_longitude=lon0, central_latitude=lat0)) else: print("Projection is invalid. Please enter the right one. \n \ 'stereo', 'merc', 'plate', 'lambret', mollweide', 'north, 'south', 'ortographic'" ) return 0 if background_color is not None: ax.background_patch.set_facecolor(background_color) ax.set_title(title) ax.coastlines(color=border_color, resolution=resolution) # 110m, 50m or 10m if states: ax.add_feature(STATES, edgecolor=border_color) ax.add_feature(cfeature.BORDERS, edgecolor=border_color) if terrain: ax.stock_img() if nightshade: assert date is not None assert ns_alpha is not None ax.add_feature(Nightshade(date, ns_alpha)) # Draw Parralels if projection == 'merc' or projection == 'plate': if isinstance(meridians, np.ndarray): meridians = list(meridians) if isinstance(parallels, np.ndarray): parallels = list(parallels) gl = ax.gridlines(crs=ccrs.PlateCarree(), color=grid_color, draw_labels=False, linestyle=grid_linestyle, linewidth=grid_linewidth) if meridians is None: gl.xlines = False else: if len(meridians) > 0: gl.xlocator = mticker.FixedLocator(meridians) gl.xlabels_bottom = True else: gl.ylines = False if parallels is None: gl.ylines = False else: if len(parallels) > 0: gl.ylocator = mticker.FixedLocator(parallels) gl.ylabels_left = True else: gl.ylines = False else: gl = ax.gridlines(crs=ccrs.PlateCarree(), color=grid_color, draw_labels=False, linestyle=grid_linestyle, linewidth=grid_linewidth) if meridians is None: gl.xlines = False else: gl.xlocator = mticker.FixedLocator(meridians) if parallels is not None: if isinstance(parallels, np.ndarray): parallels = list(parallels) gl.ylocator = mticker.FixedLocator(parallels) else: gl.ylines = False # Geomagnetic coordinates @ Apex if apex: if date is None: date = datetime(2017, 12, 31, 0, 0, 0) assert isinstance(date, datetime) A = ap.Apex(date=date) # Define levels and ranges for conversion if mlon_cs == 'mlt': if mlon_levels is None: mlon_levels = np.array([]) mlon_range = np.arange(0, 24.01, 0.01) elif isinstance(mlon_levels, bool): if mlon_levels == False: mlon_levels = np.array([]) mlon_range = np.arange(0, 24.01, 0.01) else: mlon_range = np.arange(mlon_levels[0], mlon_levels[-1] + 0.1, 0.01) else: if mlon_levels is None: mlon_levels = np.array([]) mlon_range = np.arange(-180, 180, 0.5) elif isinstance(mlon_levels, bool): if mlon_levels == False: mlon_levels = np.array([]) mlon_range = np.arange(-180, 181, 0.1) else: mlon_range = np.arange(mlon_levels[0], mlon_levels[0] + 362, 0.1) if mlat_levels is None: mlat_levels = np.arange(-90, 90.1, 1) mlat_range = np.arange(mlat_levels[0], mlat_levels[-1] + 0.1, 0.1) # Do meridans for mlon in mlon_levels: MLON = mlon * np.ones(mlat_range.size) if mlon_cs == 'mlt': y, x = A.convert(mlat_range, MLON, 'mlt', 'geo', datetime=date, height=apex_alt) else: y, x = A.convert(mlat_range, MLON, 'apex', 'geo', height=apex_alt) mlat_mask_extent = (y >= latlim[0] + 0.2) & (y <= latlim[1] - 0.2) # Plot meridian inmap = np.logical_and(x >= lonlim[0], x <= lonlim[1]) if np.sum(inmap) > 10: ax.plot(np.unwrap(x[mlat_mask_extent], 180), np.unwrap(y[mlat_mask_extent], 90), c=mlon_colors, lw=mgrid_width, linestyle=mgrid_style, zorder=90, transform=ccrs.PlateCarree()) # Labels if mlon_labels: ix = abs(y - np.mean(latlim)).argmin() mx = x[ix] - 1 if mlon >= 10 else x[ix] - 0.5 my = np.mean(latlim) if np.logical_and(mx >= lonlim[0], mx <= lonlim[1]): if mlon_cs == 'mlt' and mlon != 0: ax.text(mx, my, str(int(mlon)), color=label_colors, fontsize=14, backgroundcolor='white', transform=ccrs.PlateCarree()) elif mlon_cs != 'mlt' and mlon != 360: ax.text(mx, my, str(int(mlon)), color=label_colors, fontsize=14, backgroundcolor='white', transform=ccrs.PlateCarree()) # Do parallels for mlat in mlat_levels: MLAT = mlat * np.ones(mlon_range.size) if mlon_cs == 'mlt': gy, gx = A.convert(MLAT, mlon_range, 'mlt', 'geo', datetime=date, height=apex_alt) else: gy, gx = A.convert(MLAT, mlon_range, 'apex', 'geo', datetime=date, height=apex_alt) inmap = np.logical_and(gy >= latlim[0], gy <= latlim[1]) if np.sum(inmap) > 20: ax.plot(np.unwrap(gx, 180), np.unwrap(gy, 90), c=mlat_colors, lw=mgrid_width, linestyle=mgrid_style, zorder=90, transform=ccrs.PlateCarree()) # Labels if mlat_labels: ix = abs(gx - np.mean(lonlim)).argmin() mx = np.mean(lonlim) my = gy[ix] - 0.5 if np.logical_and(mx >= lonlim[0], mx <= lonlim[1]) and \ np.logical_and(my >= latlim[0], my <= latlim[1]): ax.text(mx, my, str(int(mlat)), color=label_colors, fontsize=14, backgroundcolor='white', transform=ccrs.PlateCarree()) if igrf: glon = np.arange(lonlim[0] - 40, lonlim[1] + 40.1, 0.5) glat = np.arange(-90, 90 + 0.1, 0.5) longrid, latgrid = np.meshgrid(glon, glat) mag = igrf12.gridigrf12(t=date, glat=latgrid, glon=longrid, alt_km=alt_km) if decl_levels is not None: z = mag.decl.values for declination in decl_levels: ax.contour(longrid, latgrid, z, levels=declination, zorder=90, colors=decl_colors, transform=ccrs.PlateCarree()) if incl_levels is not None: z = mag.incl.values for inclination in incl_levels: ax.contour(longrid, latgrid, z, levels=declination, zorder=90, colors=incl_colors, transform=ccrs.PlateCarree()) # Terminators if terminator: assert date is not None if not isinstance(terminator_altkm, list): terminator_altkm = [terminator_altkm] for takm in terminator_altkm: try: glon_ter, glat_ter = ter.get_terminator(date, alt_km=takm) if glon_ter is not None and glat_ter is not None: if isinstance(glon_ter, list): for i in range(len(glon_ter)): ax.plot(np.unwrap(glon_ter[i], 180), np.unwrap(glat_ter[i], 90), c=ter_color, lw=ter_width, ls=ter_style, zorder=90, transform=ccrs.PlateCarree()) else: ax.plot(np.unwrap(glon_ter, 180), np.unwrap(glat_ter, 90), c=ter_color, lw=ter_width, ls=ter_style, zorder=90, transform=ccrs.PlateCarree()) except: pass if midnight: mlat_range = np.arange(-89.9, 90.1, 0.1) MLON = 0 * np.ones(mlat_range.size) if mlon_cs == 'mlt': y, x = A.convert(mlat_range, MLON, 'mlt', 'geo', datetime=date, height=apex_alt) else: y, x = A.convert(mlat_range, MLON, 'apex', 'geo', height=apex_alt) mlat_mask_extent = (y >= latlim[0] + 0.2) & (y <= latlim[1] - 0.2) # Plot meridian inmap = np.logical_and(x >= lonlim[0], x <= lonlim[1]) if np.sum(inmap) > 10: ax.plot(np.unwrap(x[mlat_mask_extent], 180), np.unwrap(y[mlat_mask_extent], 90), c=midnight_colors, lw=midnight_width, linestyle=midnight_style, zorder=90, transform=ccrs.PlateCarree()) # Set Extent if projection == 'north' or projection == 'south': import matplotlib.path as mpath ax.set_extent([-180, 181, latlim[0], latlim[1]], crs=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 lonlim[0] != -180 and lonlim[1] != 180: ax.set_extent([lonlim[0], lonlim[1], latlim[0], latlim[1]], crs=ccrs.PlateCarree()) #ccrs.PlateCarree()) if 'fig' in locals(): return fig, ax else: return ax