def plot( self, ax: Axes, text_kw=None, shift=dict(units="dots", x=15), **kwargs ) -> List[Artist]: if text_kw is None: text_kw = {} if "projection" in ax.__dict__ and "transform" not in kwargs: from cartopy.crs import PlateCarree from matplotlib.transforms import offset_copy kwargs["transform"] = PlateCarree() geodetic_transform = PlateCarree()._as_mpl_transform(ax) text_kw["transform"] = offset_copy(geodetic_transform, **shift) if "color" not in kwargs: kwargs["color"] = "black" if "s" not in text_kw: text_kw["s"] = getattr(self, "callsign", "") cumul: List[Artist] = [] cumul.append(ax.scatter(self.longitude, self.latitude, **kwargs)) cumul.append(ax.text(self.longitude, self.latitude, **text_kw)) return cumul
def __init__(self, lat, lon, **kwargs): from cartopy.crs import PlateCarree # Evaluate arguments central_longitude = kwargs.pop('central_longitude', 0.) nvector = kwargs.pop("nvector", False) self.lat = lat self.lon = lon for key, val in kwargs.items(): self.__dict__[key] = val if len(lat.shape) == 1: self.crnrlon, self.crnrlat = grid_cell_corners(lat, lon) self.transform = PlateCarree(central_longitude=0.) self._cent_lon = None self.nvector = False elif nvector: assert lat.shape == lon.shape self.crnrlat, self.crnrlon = nvector_cell_corners(lat, lon) self.transform = PlateCarree(central_longitude=0.) self._cent_lon = None self.nvector = True else: assert lat.shape == lon.shape self.crnrlat, self.crnrlon = linear_cell_corners( lat, lon, central_longitude) self.transform = PlateCarree(central_longitude=central_longitude) self._cent_lon = central_longitude self.nvector = False
def test_metum(self): ds = sio.open_metum_dataset(get_demo_file('rotated_grid.nc')) # One way mylons, mylats = ds.salem.grid.ll_coordinates assert_allclose(mylons, ds.longitude_t, atol=1e-7) assert_allclose(mylats, ds.latitude_t, atol=1e-7) # Round trip i, j = ds.salem.grid.transform(mylons, mylats) ii, jj = ds.salem.grid.ij_coordinates assert_allclose(i, ii, atol=1e-7) assert_allclose(j, jj, atol=1e-7) # Cartopy from salem.gis import proj_to_cartopy from cartopy.crs import PlateCarree cp = proj_to_cartopy(ds.salem.grid.proj) xx, yy = ds.salem.grid.xy_coordinates out = PlateCarree().transform_points(cp, xx.flatten(), yy.flatten()) assert_allclose(out[:, 0].reshape(ii.shape), ds.longitude_t, atol=1e-7) assert_allclose(out[:, 1].reshape(ii.shape), ds.latitude_t, atol=1e-7) # Round trip out = cp.transform_points(PlateCarree(), ds.longitude_t.values.flatten(), ds.latitude_t.values.flatten()) assert_allclose(out[:, 0].reshape(ii.shape), xx, atol=1e-7) assert_allclose(out[:, 1].reshape(ii.shape), yy, atol=1e-7)
def plot( self, ax: Axes, text_kw=None, shift=None, **kwargs ) -> List[Artist]: # coverage: ignore if shift is None: # flake B006 shift = dict(units="dots", x=15) if text_kw is None: text_kw = {} else: # since we may modify it, let's make a copy text_kw = {**text_kw} if "projection" in ax.__dict__ and "transform" not in kwargs: from cartopy.crs import PlateCarree from matplotlib.transforms import offset_copy kwargs["transform"] = PlateCarree() geodetic_transform = PlateCarree()._as_mpl_transform(ax) text_kw["transform"] = offset_copy(geodetic_transform, **shift) if "color" not in kwargs: kwargs["color"] = "black" if "s" not in text_kw: if hasattr(self, "callsign"): text_kw["s"] = getattr(self, "callsign") # noqa: B009 if hasattr(self, "name"): text_kw["s"] = getattr(self, "name") # noqa: B009 cumul: List[Artist] = [] cumul.append(ax.scatter(self.longitude, self.latitude, **kwargs)) cumul.append(ax.text(self.longitude, self.latitude, **text_kw)) return cumul
def interpolate(self, times, proj=PlateCarree()) -> np.ndarray: if proj not in self.interpolator: self.interpolator[proj] = interp1d( np.stack( [t.to_pydatetime().timestamp() for t in self.timestamp]), proj.transform_points(PlateCarree(), *np.stack(list(self.coords)).T).T, ) return PlateCarree().transform_points(proj, *self.interpolator[proj](times))
def interpolate(self, times, proj=PlateCarree()) -> np.ndarray: """Interpolates a trajectory in time. """ if proj not in self.interpolator: self.interpolator[proj] = interp1d( np.stack(t.to_pydatetime().timestamp() for t in self.timestamp), proj.transform_points(PlateCarree(), *np.stack(self.coords).T).T, ) return PlateCarree().transform_points(proj, *self.interpolator[proj](times))
def plot_globe(self, band="I05", show=-1, show_fig=True, save=False): area = self.scene[band].attrs["area"].compute_optimal_bb_area({ "proj": "lcc", "lat_0": self.lat, "lon_0": self.lon, "lat_1": self.lat }) corrected_scene = self.scene.resample( area) # resample image to projection crs = corrected_scene[band].attrs["area"].to_cartopy_crs() from cartopy.crs import PlateCarree ax = plt.axes(projection=crs) # Cartopy methods ax.coastlines() ax.gridlines() ax.set_global() im = ax.imshow(corrected_scene[band], transform=crs, extent=(crs.bounds[0], crs.bounds[1], crs.bounds[2], crs.bounds[3]), origin="upper") for i, a in enumerate(self.rects): box = geometry.box(minx=a.b_lon, miny=a.b_lat, maxx=a.b_lon + a.width, maxy=a.b_lat + a.height) if show == i: ax.add_geometries([box], crs=PlateCarree(), edgecolor="r", facecolor="red", alpha=0.3) else: ax.add_geometries([box], crs=PlateCarree(), edgecolor="k", facecolor="none") ax.set_title( f"{self.metadata['NAME']} on {self.metadata['ISO_TIME']}\nCategory {self.metadata['USA_SSHS']} Wind Speed:{self.metadata['USA_WIND']}kts\nSpeed: {round(self.metadata['STORM_SPEED'])}kts@{round(self.metadata['STORM_DIR'])}\u00b0\n Eye @ {round(self.lat, 2)} \u00b0N , {round(self.lon, 2)}\u00b0E" ) cb = plt.colorbar(im) cb.set_label("Kelvin (K)") if save: plt.savefig(os.path.join(self.get_dir(), "image_grid.png")) plt.close() if show_fig: plt.show()
def zoom(self, event): if (event.num == 5 or event.delta == -120): self.ax.set_extent([-180, 180, -90, 90], crs=PlateCarree()) elif (event.num == 4 or event.delta == 120): x, y = self.ax.transAxes.inverted().transform((event.x, event.y)) lng = x * 360 - 180 lng_min = (-90 + lng) * (-90 + lng >= -180) - 180 * (-90 + lng < -180) lng_max = (90 + lng) * (90 + lng <= 180) + 180 * (90 + lng > 180) lat = (1 - y) * 180 - 90 lat_min = (-45 + lat) * (-45 + lat >= -90) - 90 * (-45 + lat < -90) lat_max = (45 + lat) * (45 + lat <= 90) + 90 * (45 + lat > 90) self.ax.set_extent([lng_min, lng_max, lat_min, lat_max], crs=PlateCarree())
def plot( self, ax: GeoAxesSubplot, **kwargs ) -> List[Artist]: # coverage: ignore """Plots the trajectory on a Matplotlib axis. The Flight supports Cartopy axis as well with automatic projection. If no projection is provided, a default `PlateCarree <https://scitools.org.uk/cartopy/docs/v0.15/crs/projections.html#platecarree>`_ is applied. Example usage: >>> from traffic.drawing import Mercator >>> fig, ax = plt.subplots(1, subplot_kw=dict(projection=Mercator()) >>> flight.plot(ax, alpha=.5) .. note:: See also `geoencode() <#traffic.core.Flight.geoencode>`_ for the altair equivalent. """ if "projection" in ax.__dict__ and "transform" not in kwargs: kwargs["transform"] = PlateCarree() if self.shape is not None: return ax.plot(*self.shape.xy, **kwargs) return []
def plot_weights(ax, weights): lmaps.plot_map() plt.scatter(lon, lat, c=weights, cmap="RdBu_r", norm=lplt.MidPointLogNorm(vmin=min(weights), vmax=max(weights), midpoint=1.0), edgecolors='k', linewidths=0.5, transform=PlateCarree()) formatter = ticker.FuncFormatter(lambda y, _: '{:g}'.format(y)) cb = lplt.nice_colorbar( orientation='horizontal', ticks=[0.3, 0.4, 0.6, 1.0, 1.5, 2.0, 3.0], # np.arange(0.3, 3.0, 0.3), format=formatter, aspect=40, pad=0.075) cb.set_label("Weights") lplt.plot_label(ax, f"min: {np.min(weights):3.2f}\n" f"max: {np.max(weights):3.2f}\n" f"mean: {np.mean(weights):3.2f}\n" f"median: {np.median(weights):3.2f}\n", location=3, box=False, dist=-0.1, fontdict=dict(fontsize='small'))
def on_filter(self, max_alt: int, max_time: datetime) -> None: assert self._traffic is not None west, east, south, north = self.map_plot.ax.get_extent( crs=PlateCarree()) self._tview = self._traffic.before(max_time).sort_values("timestamp") if self._tview is None: return filtered = Traffic.from_flights( Flight(f.data.ffill().bfill()) for f in self._tview) if "altitude" in filtered.data.columns: filtered = filtered.query( f"altitude != altitude or altitude <= {max_alt}") if "latitude" in self._tview.data.columns: filtered = filtered.query("latitude != latitude or " f"({west} <= longitude <= {east} and " f"{south} <= latitude <= {north})") self.identifier_select.clear() text = self.identifier_input.text() # cast is necessary because of the @lru_cache on callsigns which hides # the type annotation for callsign in sorted(cast(Set[str], filtered.callsigns)): if re.match(text, callsign, flags=re.IGNORECASE): self.identifier_select.addItem(callsign) callsigns = cast(Set[str], filtered.callsigns) self.map_plot.default_plot(self._tview[callsigns]) self.set_float_columns()
def plot_map_ccp( lat: tuple or None, lon: tuple or None, stations: bool, slat: list or np.ndarray, slon: list or np.ndarray, bins: bool, bincoords: tuple, dbin, illum: bool, illummatrix: np.ndarray, profile: list or None, p_direct=True, outputfile=None, format='pdf', dpi=300, geology=False, title=None): cl = 0.0 set_mpl_params() plt.figure(figsize=(9, 4.5)) plt.subplot(projection=PlateCarree(central_longitude=cl)) _ = plot_map( cl=cl, lat=lat, lon=lon, profile=profile, p_direct=p_direct, geology=geology, states=True) if bins: plot_bins(bincoords[0], bincoords[1], cl=cl) if illum: plot_illum(bincoords[0][0], bincoords[1][0], dbin, illummatrix, cl=cl) if stations: plot_stations(slat, slon, cl=cl) if bins or illum or stations or profile: # ax.legend() plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left', ncol=4, mode="expand", borderaxespad=0.) # plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left', # ncol=2, mode="expand", borderaxespad=0.) if title: plt.title(title, fontdict={'fontweight': 'bold'}, y=1.1) plt.tight_layout() if outputfile is None: plt.show() else: if format in ["pdf", "epsg", "svg", "ps"]: dpi = None plt.savefig(outputfile, format=format, dpi=dpi, bbox_inches='tight')
def plot_map(ax): # ax.set_global() ax.frameon = True # ax.outline_patch.set_visible(False) # Set gridlines. NO LABELS HERE, there is a bug in the gridlines # function around 180deg gl = ax.gridlines(crs=PlateCarree(), draw_labels=False, linewidth=1, color='lightgray', alpha=0.5, linestyle='-') gl.top_labels = False gl.left_labels = False gl.xlines = True # Change fontsize # font_dict = {"fontsize": "small"} # ax.set_xticklabels(ax.get_xticklabels(), fontdict=font_dict) # ax.set_yticklabels(ax.get_yticklabels(), fontdict=font_dict) ax.add_feature(cartopy.feature.LAND, zorder=0, edgecolor='black', facecolor=(0.85, 0.85, 0.85))
def plot_station_db(slat, slon, lat: tuple or None = None, lon: tuple or None = None, profile=None, p_direct=True, outputfile=None, format='pdf', dpi=300, geology=False): cl = 0.0 set_mpl_params() plt.figure(figsize=(9, 4.5)) plt.subplot(projection=PlateCarree(central_longitude=cl)) plot_map(cl=cl, lat=lat, lon=lon, profile=profile, p_direct=p_direct, geology=geology) plot_stations(slat, slon, cl=cl) plt.tight_layout() if outputfile is None: plt.show() else: if format in ["pdf", "epsg", "svg", "ps"]: dpi = None plt.savefig(outputfile, format=format, dpi=dpi, bbox_inches='tight')
def plot( # type: ignore self, ax, footprint: bool = True, runways: Union[bool, Optional[Dict]] = False, labels: Union[bool, Optional[Dict]] = False, **kwargs, ): # coverage: ignore if footprint: params = { "edgecolor": "silver", "facecolor": "None", "crs": PlateCarree(), **kwargs, } ax.add_geometries( # filter out the contour, helps for useful display # list(self.osm_request()), list(shape for dic, shape in self.osm_request().ways.values() if dic["tags"]["aeroway"] != "aerodrome"), **params, ) if self.runways is None: return if runways is not False or labels is not False: self.runways.plot( ax, labels=labels is not False, text_kw=labels if isinstance(labels, dict) else {}, **(runways if isinstance(runways, dict) else {}), )
def getCoverageCoordinates(self, center_lat, center_lng): """ Returns the coordinates of the day/night terminator. center_lat : float Center latitude of the dark side in degrees center_lng : float Center longitude of the dark side in degrees """ pole_lng = 0 #center_lng if center_lat > 0: pole_lat = -90 + center_lat central_rot_lng = 180 else: pole_lat = 90 + center_lat central_rot_lng = 0 rotated_pole = RotatedPole(pole_latitude=pole_lat, pole_longitude=pole_lng, central_rotated_longitude=central_rot_lng) self.x[:180] = -90 self.y[:180] = arange(-90, 90.) self.x[180:] = 90 self.y[180:] = arange(90, -90., -1) transformed = rotated_pole.transform_points(PlateCarree(), self.x, self.y) self.lng = transformed[:, 0] self.lat = transformed[:, 1] if (center_lat > 0): self.lat += 90 else: self.lat = 90 - self.lat self.lng = (self.lng + 180 + center_lng) % 360
def plot(self, ax, **kwargs): if "projection" in ax.__dict__: from cartopy.crs import PlateCarree kwargs["transform"] = PlateCarree() ax.plot(*self.shape.xy, **kwargs)
def plot(self, ax: GeoAxesSubplot, **kwargs) -> List[Artist]: if "projection" in ax.__dict__ and "transform" not in kwargs: kwargs["transform"] = PlateCarree() if self.shape is not None: return ax.plot(*self.shape.xy, **kwargs) return []
def plot_map(self): ax = plt.gca() ax.set_global() ax.frameon = True ax.outline_patch.set_linewidth(0.75) # Set gridlines. NO LABELS HERE, there is a bug in the gridlines # function around 180deg gl = ax.gridlines(crs=PlateCarree(central_longitude=180.0), draw_labels=False, linewidth=1, color='lightgray', alpha=0.5, linestyle='-', zorder=-1.5) gl.xlabels_top = False gl.ylabels_left = False gl.xlines = True # Add Coastline ax.add_feature(cartopy.feature.LAND, zorder=-2, edgecolor='black', linewidth=0.5, facecolor=(0.9, 0.9, 0.9))
def default_plot(self, traffic: Traffic) -> None: if traffic is None: return # clear all trajectory pieces for key, value in self.trajectories.items(): for elt in value: elt.remove() self.trajectories.clear() lon_min, lon_max, lat_min, lat_max = self.ax.get_extent(PlateCarree()) cur_ats = list(f.at() for f in traffic) cur_flights = list( at for at in cur_ats if at is not None if hasattr(at, "latitude") and at.latitude is not None and lat_min <= at.latitude <= lat_max and lon_min <= at.longitude <= lon_max) def params(at): if len(cur_flights) < 10: return dict(s=8, text_kw=dict(s=at.callsign)) else: return dict(s=8, text_kw=dict(s="")) for at in cur_flights: if at is not None: self.trajectories[at.callsign] += at.plot( self.ax, **params(at)) self.draw()
def annotate(self, ax: GeoAxesSubplot, **kwargs) -> None: # coverage: ignore if "projection" in ax.__dict__: kwargs["transform"] = PlateCarree() if "s" not in kwargs: kwargs["s"] = self.name ax.text(*np.array(self.centroid), **kwargs)
def central_longitude(self, central_longitude): from cartopy.crs import PlateCarree # Inform user of stupidity if len(self.lat.shape) == 1: raise TypeError("central_longitude is not compatible with " "a regular lat/lon grid.") try: if self._cent_lon == central_longitude: # No need to change the cell corners return except AttributeError: pass try: if self.nvector: self.nvector = False raise UserWarning( "Setting central_longitude overwrites nvector") except AttributeError: self.nvector = False # Recalculate cell corners self._cent_lon = central_longitude self.transform = PlateCarree(central_longitude=central_longitude) self.crnrlat, self.crnrlon = linear_cell_corners( self.lat, self.lon, central_longitude)
def pcolormesh(self, ax, z, *args, **kwargs): """Wrapper for pcolormesh, swapping ax for x,y""" from cartopy.crs import PlateCarree xx, yy = np.meshgrid(self.lat_bins, self.lon_bins) kwargs["transform"] = PlateCarree(central_longitude=self.central_longitude) # Apparently dims should be lat, lon, ... for good plotting return ax.pcolormesh(xx, yy, z.T, *args, **kwargs)
def plot( self, ax, *, runways: bool = True, labels: bool = False, shift: int = 300, text_kw: Optional[Dict] = None, **kwargs, ): # coverage: ignore if runways is True: params = { "edgecolor": "#0e1111", "crs": PlateCarree(), "linewidth": 3, **kwargs, } ax.add_geometries([self.shape], **params) if labels is True: if text_kw is None: text_kw = dict() text_kw = { **dict( transform=PlateCarree(), fontsize=18, horizontalalignment="center", verticalalignment="center", rotation_mode="anchor", ), **text_kw, } for thr in self.list: lat, lon, _ = destination(thr.latitude, thr.longitude, thr.bearing + 180, shift) ax.text(lon, lat, thr.name, rotation=360 - thr.bearing, **text_kw)
def plot(self, ax, **kwargs): params = { "edgecolor": "silver", "facecolor": "None", "crs": PlateCarree(), **kwargs, } ax.add_geometries(list(self.osm_request()), **params)
def plotData(self): screen_height = self.root.winfo_screenheight() if (screen_height < 1080): self.fig, self.ax = subplots( figsize=(12, 6), subplot_kw={'projection': PlateCarree()}) elif (screen_height == 1080): self.fig, self.ax = subplots( figsize=(17.5, 8.75), subplot_kw={'projection': PlateCarree()}) else: self.fig, self.ax = subplots( figsize=(18, 9), subplot_kw={'projection': PlateCarree()}) img_extent = (-180, 180, -90, 90) self.map = self.ax.imshow(self.world_map.fillDarkSideFromPicture( self.date), origin='upper', extent=img_extent, transform=PlateCarree()) self.gridAndFormat() tight_layout(pad=-0.26)
def plot( self, ax: "Axes", text_kw: Optional[Dict[str, Any]] = None, shift: Optional[Dict[str, Any]] = None, **kwargs: Any, ) -> List["Artist"]: # coverage: ignore if shift is None: # flake B006 shift = dict(units="dots", x=15) if text_kw is None: text_kw = dict() else: # since we may modify it, let's make a copy text_kw = {**text_kw} if "projection" in ax.__dict__ and "transform" not in kwargs: from cartopy.crs import PlateCarree from matplotlib.transforms import offset_copy kwargs["transform"] = PlateCarree() geodetic_transform = PlateCarree()._as_mpl_transform(ax) text_kw["transform"] = offset_copy(geodetic_transform, **shift) if "color" not in kwargs: kwargs["color"] = "black" if "s" not in text_kw: if hasattr(self, "callsign"): text_kw["s"] = getattr(self, "callsign") # noqa: B009 if hasattr(self, "name"): text_kw["s"] = getattr(self, "name") # noqa: B009 cumul: List["Artist"] = [] cumul.append(ax.scatter(self.longitude, self.latitude, **kwargs)) west, east, south, north = ax.get_extent(PlateCarree()) if west <= self.longitude <= east and south <= self.latitude <= north: cumul.append(ax.text(self.longitude, self.latitude, **text_kw)) return cumul
def plot( self, ax: GeoAxesSubplot, s: int = 10, **kwargs ) -> Artist: # coverage: ignore """Plotting function. All arguments are passed to ax.scatter""" return ax.scatter( self.data.longitude, self.data.latitude, s=s, transform=PlateCarree(), **kwargs, )
def plot(self, ax: GeoAxesSubplot, **kwargs) -> Artist: """Plotting function. All arguments are passed to the geometry""" if "facecolor" not in kwargs: kwargs["facecolor"] = "None" if "edgecolor" not in kwargs: kwargs["edgecolor"] = ax._get_lines.get_next_color() if "projection" in ax.__dict__: return ax.add_geometries([self.shape], crs=PlateCarree(), **kwargs) else: return ax.add_patch( MplPolygon(list(self.shape.exterior.coords), **kwargs))
def plot(self, ax, **kwargs): # coverage: ignore if "color" not in kwargs: kwargs["color"] = "#aaaaaa" if "alpha" not in kwargs: kwargs["alpha"] = 0.5 if "linewidth" not in kwargs and "lw" not in kwargs: kwargs["linewidth"] = 0.8 if "linestyle" not in kwargs and "ls" not in kwargs: kwargs["linestyle"] = "dashed" if "projection" in ax.__dict__: kwargs["transform"] = PlateCarree() ax.plot(*self.shape.xy, **kwargs)