Example #1
0
def basemap(zoom=12):
    imagery = OSM()

    ax = plt.axes(projection=imagery.crs)
    ax.set_extent(LONDON)
    extent = ax._get_extent_geom(imagery.crs)
    img, extent, origin = imagery.image_for_domain(extent, zoom)
    plt.close(ax.figure)

    return {'img': img, 'extent': extent, 'origin': origin}
Example #2
0
def main():
    imagery = OSM()

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1, projection=imagery.crs)
    ax.set_extent([-0.14, -0.1, 51.495, 51.515], ccrs.PlateCarree())

    # Construct concentric circles and a rectangle,
    # suitable for a London Underground logo.
    theta = np.linspace(0, 2 * np.pi, 100)
    circle_verts = np.vstack([np.sin(theta), np.cos(theta)]).T
    concentric_circle = Path.make_compound_path(Path(circle_verts[::-1]),
                                                Path(circle_verts * 0.6))

    rectangle = Path([[-1.1, -0.2], [1, -0.2], [1, 0.3], [-1.1, 0.3]])

    # Add the imagery to the map.
    ax.add_image(imagery, 14)

    # Plot the locations twice, first with the red concentric circles,
    # then with the blue rectangle.
    xs, ys = tube_locations().T
    ax.plot(xs, ys, transform=ccrs.OSGB(),
            marker=concentric_circle, color='red', markersize=9, linestyle='')
    ax.plot(xs, ys, transform=ccrs.OSGB(),
            marker=rectangle, color='blue', markersize=11, linestyle='')

    ax.set_title('London underground locations')
    plt.show()
Example #3
0
def create_map(long, lat, ext):
    # Set projection type
    projection = ccrs.PlateCarree()
    # Fetch map tiles
    tiles = OSM()

    # Create figure and ax with gridlines and formated axes
    fig, ax = plt.subplots(figsize=(10, 10),
                           subplot_kw=dict(projection=projection))
    gl = ax.gridlines(draw_labels=True)
    gl.xlabels_top = False
    gl.ylabels_right = False
    gl.xformatter = LONGITUDE_FORMATTER
    gl.yformatter = LATITUDE_FORMATTER

    # Take part of projection calculated by ext
    ax.set_extent(ext, projection)
    # Add tiles to ax with zoom 7 and sline36 interpolation
    ax.add_image(tiles, 7, interpolation='spline36')
    # Plot observing point
    ax.plot([long], [lat], 'bs')
    # Add title to plit
    fig.suptitle('Live Flight Tracker', fontsize=16)

    # Create empty scatter plot
    track_flights = ax.scatter([], [],
                               marker='o',
                               c=[],
                               s=14,
                               alpha=.85,
                               edgecolors='k')
    return fig, ax, track_flights
Example #4
0
    def __init__(self, update_interval = 1, trajectory = False):
        self.update_interval = update_interval
        self.trajectory = trajectory
        imagery = OSM()

        self.fig = plt.figure()
        self.fig.subplots_adjust(left = 0, right = 1, bottom = 0, top = 1)
        ax = self.fig.add_subplot(1, 1, 1, projection = imagery.crs)

        ax.set_extent([
            PosePlotter.lng_min,
            PosePlotter.lng_max,
            PosePlotter.lat_min,
            PosePlotter.lat_max
        ], ccrs.PlateCarree())

        ax.add_image(imagery, 17)

        self.poses = dict()
        self.colors = PosePlotter.color_generator()

        plt.ion()
        plt.hold(True)
        plt.draw()
        plt.show()
Example #5
0
 def plotTracks(self, files, osmZoomLevel=10, padding=0.1):
     # ToDo: adapt OSM zoom level automatically
     # Make plot interactive, allow user to zoom, scroll, pan; adapt map bg accordingly
     # Padding: add padding on all four sides so tracks don't end at edge of map.  0.1: 10% padding on all sides.
     if len(files) == 0:
         raise ValueError("gpxTools.plotTracks: need at least one file to work with!")
     if padding < 0:
         raise ValueError("gpxTools.plotTracks: padding value is %f; needs to be non-negative."%padding)
     # Open with fiona:
     # Straightforward to generate shapes, but doesn't retain time information.
     trackShapes=[]
     # extent: bounding box for map plot: minLon, maxLon, minLat, maxLat
     extent=[sys.float_info.max, sys.float_info.min, sys.float_info.max, sys.float_info.min]
     for fn in files:
         tracks=fiona.open(fn, layer='tracks')
         for track in tracks:
             coords=track['geometry']['coordinates']
             shp=sgeom.MultiLineString(coords)
             # shp.bounds has different order than extent...
             if shp.bounds[0]<extent[0]:
                 extent[0] = shp.bounds[0] 
             if shp.bounds[2] > extent[1]:
                 extent[1]=shp.bounds[2]
             if shp.bounds[1] < extent[2]:
                 extent[2] = shp.bounds[1]
             if shp.bounds[3] > extent[3]:
                 extent[3] = shp.bounds[3]
             trackShapes.append(shp)
         # Add padding:
         lonShift=padding*(extent[1]-extent[0])
         extent[0]=extent[0]-lonShift
         extent[1]=extent[1]+lonShift
         latShift=padding*(extent[3]-extent[2])
         extent[2]=extent[2]-latShift
         extent[3]=extent[3]+latShift
         # Start plotting
         osm=OSM()
         # Following https://ocefpaf.github.io/python4oceanographers/blog/2015/08/03/fiona_gpx/
         ax = plt.axes(projection=osm.crs)
         gl=ax.gridlines(draw_labels=True)
         gl.xlabels_top = gl.ylabels_right = False
         gl.xformatter = LONGITUDE_FORMATTER
         gl.yformatter = LATITUDE_FORMATTER
         ax.set_extent(extent)
         ax.add_image(osm,osmZoomLevel) 
         ## Fiona
         for i, track in enumerate(trackShapes):
             ax.add_geometries(track, crs=ccrs.PlateCarree(), edgecolor=self.plotColors[i % len(self.plotColors)], linewidth=2, facecolor='none')
         plt.tight_layout()
         plt.show()
         return
Example #6
0
def get_map_params(image='StamenTerrain', color_palette=None):
    # set color palette
    if color_palette:
        cmap = plt.get_cmap(color_palette)
    else:
        cmap = None

    # set background image
    if image == 'StamenTerrain':
        tiler = StamenTerrain()
    elif image == 'GoogleTiles':
        tiler = GoogleTiles()
    elif image == 'OSM':
        tiler = OSM()

    return cmap, tiler
Example #7
0
def render_pyplot(df, dataset_args=None, render_args=None):
    from cartopy.io.img_tiles import OSM

    tiles = OSM()
    fig = plt.figure(figsize=(18, 18))
    ax = plt.axes(projection=tiles.crs)

    for route in df['route_id'].unique():
        df_route = df.loc[df['route_id'] == route]
        ax.plot(df_route.stop_lon.values,
                df_route.stop_lat.values,
                color=get_color_for_str(route),
                transform=ccrs.Geodetic(),
                markersize=2,
                marker='o')
    filename = 'pyplot_' + \
        '_'.join([dataset_args['dataset'],
                  dataset_args['agency'], dataset_args['route']])
    plt.savefig(f'{filename}.png')
Example #8
0
 def __cartopy_geo_axis(self, zoom: int) -> (GeoAxesSubplot, dict):
     osm = OSM()
     axis = axes(projection=osm.crs)
     axis.set_extent(self.__density.bounds.extent, crs=PlateCarree())
     axis.add_image(osm, zoom)
     axis.text(-0.05,
               0.50,
               'latitude',
               rotation='vertical',
               verticalalignment='center',
               transform=axis.transAxes)
     axis.text(0.5,
               -0.05,
               'longitude',
               rotation='horizontal',
               horizontalalignment='center',
               transform=axis.transAxes)
     plot_params = {
         'cmap': transparent_viridis(),
         'transform': PlateCarree()
     }
     return axis, plot_params
Example #9
0
    def generate(self, figsize, dpi, zoom, markersize):
        """
        This generates the basic map and draws dots on the given location.

        Args:
            figsize (tuple of int): Figure size.
            dpi (int): Dots per inch.
            zoom (int): Map zoom.
            markersize (int): Size of dots.

        """
        imagery = OSM()
        plt.figure(figsize=figsize, dpi=dpi)
        ax = plt.axes(projection=imagery.crs)
        ax.set_extent(
            (min(self.lng) - 0.02, max(self.lng) + 0.02, min(self.lat) - 0.01,
             max(self.lat) + 0.01))
        ax.add_image(imagery, zoom)
        plt.plot(self.lng,
                 self.lat,
                 'bo',
                 transform=ccrs.Geodetic(),
                 markersize=markersize)
        plt.title(self.title)
    def __init__(self, file: str):
        self.is_heading_plotted = False
        self.is_course_plotted = False
        self.file = file
        self.transformation = ccrs.PlateCarree()
        self.color_mapping = 'viridis'
        self.fMin_latitude = -1
        self.fMax_latitude = -1
        self.fMin_longitude = -1
        self.fMax_longitude = -1
        self.fMap_margins = 0.05

        # Initializes lists used to store all data for a particular data attribute
        self.iDate_list = []
        self.fTime_list = []
        self.fLong_list = []  # x coord
        self.fLat_list = []  # y coord
        self.fShip_heading_list = []
        self.fShip_course_list = []
        self.fShip_speed_list = []
        self.fTemperature_list = []
        self.fSalinity_list = []
        self.fConductivity_list = []
        self.fFluorescence_list = []

        # ***********************************************************************
        # * MAP SETUP
        # ***********************************************************************
        # Get map tiles from the OpenStreetMap Server, map tiles allow for maps to be loaded from servers
        self.osm_tiles = OSM()

        # Changes the display size - specifically figsize=(x,y)
        self.fig = plt.figure(figsize=(12, 6))

        # Create a GeoAxes in the tile's projection
        self.ax = plt.axes(projection=self.osm_tiles.crs)
Example #11
0
def create_plot(polygons_df, shape_func, datas, data_plot_funcs, 
                 color_pallete, title, extend, sav_figname, **kargs):
    '''
    Creates plot
    
    Parameters
    ----------
    shapes_in : list of shapely.geometry.multipolygon.MultiPolygon
        Shapes that represent region of interest.
    shapes_out : list of shapely.geometry.multipolygon.MultiPolygon
        All shaps or not in region of interest shapes.
    shape_func : function
        Function that determines how to represent shapes in regions 
        of interest. Parameters: ax, shapes_in, color_pallette, **kargs
    datas : list of obj pd.DataFrame
        Data that needs to be plotted on the plot
    data_plot_funcs : function
        Function that determines how to represent data at plot.
        Parameters: ax, data, color_palleter, **kargs
    color_pallette : dict
        Dictionary of colors
    title : str
        Title of plot
    extend : list of float
        Extend of map
    sav_figname : str
        Name of file in which the plot will be saved
    Keyword argumnets
    -----------------
        A bunch of ^^
        graph_info : str
            Infromation about data sources
    Returns
    -------
    '''
    zorders = {
            'legends':100,
            'ground_in':5,
            'ground_out':20,
            'water_out':15,
            'water_in':1,
            'roads_major_out':22,
            'roads_minor_out':21,
            'roads_major_in':7,
            'roads_minor_in':6,
            'first_layer_top':25,
            'first_layer':20,
            'first_layer_bottom':15,
            'second_layer_top':10,
            'second_layer':5,
            'second_layer_bottom':1,
            }
    tiler = OSM()
    plt.figure(figsize=(10,10))
    fig = plt.gcf()
    ax = plt.axes(projection=tiler.crs)
    ax.coastlines('10m')
    ax.set_extent(extend)

    shape_func(ax, polygons_df, color_pallete, 
               zorder = zorders, tiler=tiler, **kargs)
    legend_lines_list = []
    legend_text_list = []
    for indx, record in enumerate(list(zip(datas, data_plot_funcs))):
        legend_line, legend_text = record[1](ax, record[0], color_pallete, 
                                         fig = fig, ind = indx, **kargs )
        legend_lines_list.append(legend_line)
        legend_text_list.append(legend_text)
    ax.legend(legend_lines_list,legend_text_list,loc=4).set_zorder(
            zorders['legends'])
    if 'graph_info' in kargs and len(kargs['graph_info'])>0: 
        props = dict(boxstyle='round', facecolor='gray', alpha=0.5)
        ax.text(0.02,0.98,kargs['graph_info'],fontsize=7,
                horizontalalignment = 'left',
                verticalalignment = 'top',
                bbox=props,
                transform = ax.transAxes, color='White', zorder=1000)
    ax.text(0.001,
            0.001,
            '© OpenStreetMap contributors',
            fontsize=8,
            horizontalalignment = 'left',
            verticalalignment = 'bottom',
            transform = ax.transAxes, color='White', zorder=1000)
  
        
    plt.savefig(sav_figname)
    return ax
    plt.close()

# This code can be used to test create_cmap function
#hex_s='dbd1c9'
#mcm = create_cmap(['#dbd1c9','#db9a8e','#db6767','#db4848','#ff3a3a'])
#
#plt.figure()
#
#plt.scatter(np.random.random(100),np.random.random(100),c=np.random.random(100),cmap=mcm)
#plt.colorbar()
#plt.show()
#
#rgba = mcm(np.linspace(0, 1, 256))
#fig, ax = plt.subplots(figsize=(4, 3), constrained_layout=True)
#col = ['r', 'g', 'b']
#for xx in [0.25, 0.5, 0.75]:
#    ax.axvline(xx, color='0.7', linestyle='--')
#for i in range(3):
#    ax.plot(np.arange(256)/256, rgba[:, i], color=col[i])
#ax.set_xlabel('index')
#ax.set_ylabel('RGB')
Example #12
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Jul 28 20:34:00 2020

@author: admin
"""

import matplotlib.pyplot as plt

import cartopy.crs as ccrs
from cartopy.io.img_tiles import OSM

imagery = OSM()

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=imagery.crs)
ax.set_extent([13.0, 13.8, 52.0, 52.4], ccrs.PlateCarree())

ax.add_image(imagery, 14)

plt.show()
Example #13
0
from cartopy.io.img_tiles import OSM
import cartopy.feature as cfeature
from cartopy.io import shapereader
from cartopy.io.img_tiles import StamenTerrain
from cartopy.io.img_tiles import GoogleTiles
#from owslib.wmts import WebMapTileService

from matplotlib.path import Path
import matplotlib.patheffects as PathEffects
import matplotlib.patches as mpatches

import numpy as np

# %%
plt.figure(figsize=(13,6.2))
tiler = OSM() #GoogleTiles()
mercator = tiler.crs
ax = plt.axes(projection=mercator)

#ax.set_extent(( 153, 153.2, -26.6, -26.4))

zoom = 3
ax.add_image(tiler, zoom )

# even 1:10m are too coarse for .2 degree square
#ax.coastlines('10m')

home_lat, home_lon = 0,0
# Add a marker for home
#plt.plot(home_lon, home_lat, marker='o', color='red', markersize=5, alpha=0.7, transform=ccrs.Geodetic())
Example #14
0
def get_gif(access_token: str, min_lon: float, max_lat: float, max_lon: float,
            min_lat: float, ratio: float, colour: str, backgroundColour: str,
            alpha: float, activity_type: str, bg_img: str, duration: int):
    activities = requests.get('https://www.strava.com/api/v3/activities' +
                              '?access_token=' + access_token +
                              '&per_page=200' + '&page=' + str(1))
    activities = activities.json()

    # convert activities to pandas dataframe
    df = json_normalize(activities)

    # filter df by type of activity
    if activity_type == 'Run':
        df = df[df['type'] == 'Run']
    elif activity_type == 'Ride':
        df = df[df['type'] == 'Ride']
    else:
        df = df[(df['type'] == 'Run') | (df['type'] == 'Ride')]

    # filter df by start coordinates using the bounding box
    df_bbox = df[(df['start_latitude'] < max_lat)
                 & (df['start_latitude'] > min_lat) &
                 (df["start_longitude"] < max_lon)
                 & (df["start_longitude"] > min_lon)]

    df_bbox = df_bbox.sort_values(by=['start_date'])

    # create imagery based on bg_img
    if bg_img == 'sat':
        imagery = GoogleTiles(style='satellite')
    elif bg_img == 'osm':
        imagery = OSM()
    else:
        imagery = OSM()

    # create figure to plot routes on
    fig = plt.figure(figsize=(8, ratio * 8), frameon=False)
    ax = fig.add_subplot(1, 1, 1, projection=imagery.crs)

    fig.patch.set_visible(False)
    ax.set_extent([min_lon, max_lon, min_lat, max_lat])

    ax.set_axis_off()

    # filepaths
    fp_out = 'image.gif'

    imgs = []
    for i in range(len(df_bbox)):
        try:
            lat, lng = zip(
                *polyline.decode(df_bbox.iloc[i]['map.summary_polyline']))
        except:
            print(i)

        plt.plot(lng,
                 lat,
                 transform=ccrs.Geodetic(),
                 color=colour,
                 alpha=alpha)
        imgs.append(fig2img(fig))

    # create background image
    if bg_img == 'none':
        bg = Image.new(mode='RGBA',
                       size=imgs[0].size,
                       color=ImageColor.getrgb(backgroundColour))

    else:
        fig = plt.figure(figsize=(8, ratio * 8), frameon=False)
        ax = fig.add_subplot(1, 1, 1, projection=imagery.crs)
        ax.set_extent([min_lon, max_lon, min_lat, max_lat])
        fig.patch.set_visible(False)
        ax.set_axis_off()

        # set background imagery if one was sent
        ax.add_image(imagery, 15)

        # converting background to image
        bg = fig2img(fig)

    imgs = map(lambda img: Image.alpha_composite(bg, img), imgs)
    bg.save(fp=fp_out,
            format='GIF',
            append_images=imgs,
            save_all=True,
            duration=duration,
            loop=0)

    file = open('image.gif', 'rb')
    return {'gif': base64.b64encode(file.read())}
Example #15
0
    def getAx(self):
        def newGetImage(self, tile):
            if six.PY3:
                from urllib.request import urlopen, Request
            else:
                from urllib2 import urlopen
            url = self._image_url(tile)  # added by H.C. Winsemius
            req = Request(url)  # added by H.C. Winsemius
            req.add_header('User-agent', 'your bot 0.1')
            # fh = urlopen(url)  # removed by H.C. Winsemius
            fh = urlopen(req)
            im_data = six.BytesIO(fh.read())
            fh.close()
            img = Image.open(im_data)

            img = img.convert(self.desired_tile_form)

            return img, self.tileextent(tile), 'lower'

        def getBoundsZoomLevel(bound, mapDim):
            WORLD_DIM = {"height": 256, "width": 256}
            ZOOM_MAX = 20

            def latRad(lat):
                sin = math.sin(lat * math.pi / 180)
                radX2 = math.log((1 + sin) / (1 - sin)) / 2
                return max(min(radX2, math.pi), -math.pi) / 2

            def zoom(mapPx, worldPx, fraction):
                return math.floor(
                    math.log(mapPx / worldPx / fraction) / math.log(2))

            # 計算採用googlemap格式 (緯度,經度)
            # 右上
            ne = {"lat": bound[3], "lng": bound[1]}
            # 左下
            sw = {"lat": bound[2], "lng": bound[0]}

            latFraction = (latRad(ne["lat"]) - latRad(sw["lat"])) / math.pi

            lngDiff = ne["lng"] - sw["lng"]
            lngFraction = ((lngDiff + 360) /
                           360) if lngDiff < 0 else (lngDiff / 360)

            latZoom = zoom(mapDim["height"], WORLD_DIM["height"], latFraction)
            lngZoom = zoom(mapDim["width"], WORLD_DIM["width"], lngFraction)

            return min(latZoom, lngZoom, ZOOM_MAX)

        def getLngLatBounds():
            # !
            # 迭代各dataframe 回傳經緯度min/max (minx/maxx/miny/maxy)
            bound = [9999, 0, 9999, 0]  # 預設值
            for df in self.df_set:
                if len(df) != 0:
                    bounds = df.geometry.bounds
                    # 檢查各值 有更大的框則更新
                    bound = [
                        min(bounds.minx)
                        if min(bounds.minx) < bound[0] else bound[0],  # 最小經度
                        max(bounds.maxx)
                        if max(bounds.maxx) > bound[1] else bound[1],  # 最大經度
                        min(bounds.miny)
                        if min(bounds.miny) < bound[2] else bound[2],  # 最小緯度
                        max(bounds.maxy)
                        if max(bounds.maxy) > bound[3] else bound[3]
                    ]  # 最大緯度
                    # margin_lng = (bound[0] - bound[1]) * 0.03
                    # margin_lat = (bound[2] - bound[3]) * 0.03
                    # bound = list(map(lambda x, y: x + y, bound, [-margin_lng, +margin_lng, -margin_lat, +margin_lat]))
            return bound

        # 沒有自訂bound 使用資料之最大邊界為bound
        if len(self.bound) == 0:
            self.bound = getLngLatBounds()

        # fig與legend固定4比1
        # 字體大小12pt
        # legend超出則裁切
        # 解決matplotlib本身不支援中文字體 會顯示成方塊的問題
        # see: https://stackoverflow.com/questions/10960463/non-ascii-characters-in-matplotlib
        plt.rcParams['axes.unicode_minus'] = False  # 解決負號 '-' 顯示為方塊的問題
        plt.rc(
            'font',
            **{
                'sans-serif': 'Microsoft JhengHei',  # 指定中文字體 (微軟正黑體)
                'family': 'sans-serif',
                'size': 12
            })  # 指定默認字型
        self.dpi = 300
        fig = plt.figure(dpi=self.dpi)
        ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())

        ax.set_title(self.title)
        ax.set_extent(self.bound, ccrs.PlateCarree())
        # 獲取fig框像素大小
        fig_size = fig.get_size_inches() * fig.dpi
        mapDim = {"height": int(fig_size[0]), "width": int(fig_size[1])}
        # 計算zoom_level
        zoom_lv = getBoundsZoomLevel(self.bound, mapDim)
        print("計算最佳zoom_level: ", zoom_lv)

        OSM.get_image = newGetImage
        imagery = OSM()

        # interpolation: matplotlib抗鋸齒
        # 0.18版更新 可修正下述bug
        # cartopy0.18版interpolation的bug
        # see: https://github.com/SciTools/cartopy/issues/1563
        # cartopy0.17版add_image的bug
        # see: https://github.com/SciTools/cartopy/issues/1341

        inter = 'spline36'
        # regrid_shape: basemap長寬之短邊尺寸
        regrid = max(mapDim.values())
        # ax.add_image(imagery, zoom, interpolation=inter, regrid_shape=regrid)
        #ax.add_image(imagery, zoom_lv, regrid_shape=regrid)
        ax.add_image(imagery, zoom_lv)
        # 色碼表: https://www.ebaomonthly.com/window/photo/lesson/colorList.htm
        return ax
Example #16
0
# import urllib.request
# import json
# import matplotlib.pyplot as plt
# from matplotlib import animation
# import cartopy.crs as ccrs
# from cartopy.io.img_tiles import OSM

import cartopy.crs as ccrs
from cartopy.io.img_tiles import OSM
import matplotlib.pyplot as plt

osm_tiles = OSM()

plt.figure(figsize=(16, 16))

# Use the tile's projection for the underlying map.
ax = plt.axes(projection=osm_tiles.crs)

# Specify a region of interest, in this case, Cardiff.

ax.set_extent([-122.335058, -122.222542, 47.426043, 47.472231],
              ccrs.PlateCarree())

# Add the tiles at zoom level 12.
ax.add_image(osm_tiles, 12, interpolation='spline36')

ax.coastlines('10m')

plt.show()

# #DEFINE FIGURE
Example #17
0
def main():
    """
    
    lon0 = 35.25; lat0 = -23.60
    lon1 = 35.25; lat1 = -24.0
    lon2 = 35.65; lat2 = -24.0
    lon3 = 35.65; lat3 = -23.60
   
    
    https://stackoverflow.com/questions/52356926/how-to-set-offset-for-python-cartopy-geometry
    """


    # Create the figure
    fig = plt.figure(figsize=(5,6))
 
    from cartopy.io.img_tiles import OSM 

           
    # Add OSM image as background for the selected extension
    tiler = OSM()
    ax = plt.axes(projection=tiler.crs)

    # Openstreet layer zoom detail
    zoom=12
    
    ax.add_image(tiler, zoom, alpha=0.75)

    extent = [35.25, 35.65, -24.05, -23.60]

    ax.set_extent(extent)

    # Set figure title
    ax.set_title('Study area',fontsize=10)


    # Plot coastline from GSHHSF
    coast_line=cfeature.GSHHSFeature(scale='full')
    
    ax.add_feature(coast_line,  alpha=1.0,  linewidths=0.5, edgecolor='black' )

        
    plotWetlands(ax)
    plotRivers(ax)
    

    plotInterestPoint(ax)
 
    # plot difters track
    plotTrack(ax) 


    # Plot escale bar
    scaleBar(ax, length=10, location=(0.8, 0.80), linewidth=1.5)
    
    plotGridLines(ax)
    
    # Criate a subfigure 
    #subfigure = [.58, .09, .30, .20]
    ax2 = fig.add_axes([.58, .09, .30, .20]) 
    plotMozambique(ax2)

    # Adjust plot the the figure
    plt.tight_layout()

    plt.show()

    saveFig(fig, file='estudyarea')
    def plot_static(self, format="png", dpi=150):
        '''Creates a map of the contact list using a cartopy map.'''

        # Plotting work horse, basically we want a big plot and then a zoom in
        # on contact area
        def do_plot(ax, t1s, t2s, contact_ts, extend, imagery, level=14):
            '''Add to axis'''
            ax.set_extent(extend)
            ax.add_image(imagery, level)

            lons = t1s["longitude"].to_numpy()
            lats = t1s["latitude"].to_numpy()
            size = t1s["accuracy"].to_numpy()

            # do coordinate conversion of (lat,y)
            xynps = ax.projection.transform_points(ccrs.Geodetic(), lons, lats)
            ax.scatter(xynps[:, 0],
                       xynps[:, 1],
                       size,
                       marker='o',
                       alpha=.5,
                       color="blue",
                       label="Patient")

            lons = t2s["longitude"].to_numpy()
            lats = t2s["latitude"].to_numpy()
            size = t2s["accuracy"].to_numpy()
            # do coordinate conversion of (x,y)
            xynps = ax.projection.transform_points(ccrs.Geodetic(), lons, lats)
            ax.scatter(xynps[:, 0],
                       xynps[:, 1],
                       size,
                       marker='o',
                       alpha=.5,
                       color="green",
                       label="Infected")

            lons = contact_ts["longitude"].to_numpy()
            lats = contact_ts["latitude"].to_numpy()
            size = contact_ts["accuracy"].to_numpy()
            # do coordinate conversion of (x,y)
            xynps = ax.projection.transform_points(ccrs.Geodetic(), lons, lats)
            ax.scatter(xynps[:, 0],
                       xynps[:, 1],
                       size,
                       marker='o',
                       alpha=.5,
                       color="red",
                       label="Contacts")

        def safe_concat(l):
            if len(l) > 0:
                return pd.concat(l)
            else:
                return pd.DataFrame(
                    columns=['time', 'longitude', 'latitude', 'accuracy'])

        contact_ts = safe_concat([
            pd.DataFrame(c.trajectory(),
                         columns=['time', 'longitude', 'latitude', 'accuracy'],
                         dtype=np.float64) for c in self
        ])
        # It should not be needed to plot if there are no contacts
        if not len(contact_ts): return None

        t1s = safe_concat([c.t1.pd_frame for c in self if len(c.t1.data) > 0])
        t2s = safe_concat([c.t2.pd_frame for c in self if len(c.t2.data) > 0])

        # We are going to plot addition zoom in plots on clusters of
        # contacts. A cluster of contacts are events seperated by edge
        # of large distance. We say distance is large relative to max blue
        # and green distances
        contact_ts = contact_ts.sort_values(by='time').reset_index(drop=True)

        all = pd.concat([t1s, t2s, contact_ts])

        if len(all) == 0: return None

        # This would be related to window size
        max_separation = max(get_max_dist_meters(t1s),
                             get_max_dist_meters(t2s))
        # We can form a possible cluster iff we make a large step
        edge_lengths = conseq_distance_meters(contact_ts)

        # There will always be at least to global plot
        slack_lon = 0.015
        slack_lat = 0.005

        extends = [(min(all["longitude"]) - slack_lon, max(all["longitude"]) +
                    slack_lon, min(all["latitude"]) - slack_lat,
                    max(all["latitude"]) + slack_lat)]

        # For just one contact we zoom in
        if not len(edge_lengths):
            extends.append((min(all["longitude"]) - slack_lon / 10.,
                            max(all["longitude"]) + slack_lon / 10.,
                            min(all["latitude"]) - slack_lat / 10.,
                            max(all["latitude"]) + slack_lat / 10.))
        # So will we zoom in?
        elif any(e > 0.5 * max_separation for e in edge_lengths):
            # A subplot has different extends
            slack_lon /= 10.
            slack_lat /= 10.
            # Subplots will be for slices based on break points
            bpts = [0] + [
                p[0] for p in enumerate(edge_lengths, 1)
                if p[1] > 0.5 * max_separation
            ] + [len(contact_ts)]

            for start, end in zip(bpts[:-1], bpts[1:]):
                cluster = contact_ts.iloc[start:end]

                extends.append((min(cluster["longitude"]) - slack_lon,
                                max(cluster["longitude"]) + slack_lon,
                                min(cluster["latitude"]) - slack_lat,
                                max(cluster["latitude"]) + slack_lat))

        imagery = OSM()
        fig = plt.figure(figsize=(8, 8))
        # Fill
        nplots = len(extends)
        for idx, extend in enumerate(extends, 1):
            ax = fig.add_subplot(nplots, 1, idx, projection=imagery.crs)
            do_plot(ax,
                    t1s,
                    t2s,
                    contact_ts,
                    extend,
                    imagery=imagery,
                    level=14 if idx == 1 else 16)  # Fine for zoomd

        f = io.BytesIO()
        fig.savefig(f, format=format, quality=95, dpi=dpi)
        f.seek(0)
        plt.close()
        return f.getvalue()