# AUTOGENERATED! DO NOT EDIT! File to edit: 00_map.ipynb (unless otherwise specified).

__all__ = ['Map', 'Transect']

# Cell
import cartopy.crs as ccrs
import cartopy.io.img_tiles as cimgt

from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from mpl_toolkits.axes_grid1 import make_axes_locatable

from matplotlib.patches import PathPatch

from matplotlib.ticker import MaxNLocator
import matplotlib.tri as tri
import matplotlib.pyplot as plt
from matplotlib import image
import matplotlib.lines as mlines
from matplotlib.path import Path as PathPlt

from matplotlib_scalebar.scalebar import ScaleBar

import numpy as np
from scipy.spatial import Delaunay
import json
import pandas as pd

# Cell
class Map:
    """Represents a map of urban heat island

  Attributes:
    df: numpy's dataframe.
    transects: array of strings.
    legend_stations_label: string.
    otherDf: numpy's dataframe.
    mapbox_username: mapbox's username to plot background map.
    mapbox_token: mapbox's token to plot background map.
    mapbox_map_id: mapbox's map id to plot background map.
  """
    def __init__(self, df,transects=[],legend_stations_label="Estaciones",otherDf=None,mapbox_username=None,mapbox_token=None,mapbox_map_id="ck2hwr0522eal1cm297dkqzis"):
      self.df = df
      self.transects = transects
      self.legend_stations_label = legend_stations_label
      self.otherDf = otherDf
      self.mapbox_username = mapbox_username
      self.mapbox_token = mapbox_token
      self.mapbox_map_id = mapbox_map_id

    def plot(self,extent,hasBorders=None,show=False,file='HeatMap.png',vMin=None,vMax=None,hasImage=True,
             hasScaleBar=True,hasCompassRose=True,hasLegend=True, hasColorbar=True,contour="countourLine",
             transparency=.7,showPoints=True,drawMinMaxT=True,ID_LABEL="ID",LON_LABEL="Longitud",LAT_LABEL="Latitud",Z_LABEL="°C",Z_UNIT="°C"):
      request = cimgt.MapboxStyleTiles(username=self.mapbox_username,map_id=self.mapbox_map_id,access_token=self.mapbox_token)
      projection=request.crs
      fig = plt.figure(figsize=(13,10))
      ax = plt.axes(projection=projection)

      fontSize=23
      ax.set_extent(extent,crs=ccrs.PlateCarree())

      gl=ax.gridlines(draw_labels=True, alpha=0.2)
      gl.xlabels_top = gl.ylabels_right = False
      gl.xlabel_style = {'size': fontSize, 'color': 'black'}
      gl.ylabel_style = {'size': fontSize, 'color': 'black'}
      locator=MaxNLocator(nbins=7)
      gl.xlocator=locator

      tricf=self.ic(ax,hasBorders=hasBorders,vMin=vMin,vMax=vMax,contour=contour,transparency=transparency,showPoints=showPoints,
                    drawMinMaxT=drawMinMaxT,ID_LABEL=ID_LABEL,LON_LABEL=LON_LABEL,LAT_LABEL=LAT_LABEL,Z_LABEL=Z_LABEL,Z_UNIT=Z_UNIT)

      if hasCompassRose:
        axins2 = inset_axes(ax, width="20%", height="20%", loc="lower right")
        axins2.imshow(image.imread("https://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Simple_compass_rose-fr.svg/600px-Simple_compass_rose-fr.svg.png"))
        self.blank_axes(axins2)

      if hasScaleBar:
        scalebar = ScaleBar(dx=1) # 1 pixel = 0.2 meter
        ax.add_artist(scalebar)

      if hasImage:
        ax.add_image(request,14)

      for transect in self.transects:
        xynps = ax.projection.transform_points(ccrs.Geodetic(), transect.x, transect.y)
        x=xynps[:,0]
        y=xynps[:,1]
        ax.plot(x,y, color=transect.color,marker="o",linestyle='-', markersize=5)

      if hasLegend:
        axins3 = inset_axes(ax, width="20%", height="40%", loc="upper left")
        self.legend(axins3)

      if hasColorbar:
        divider = make_axes_locatable(ax)
        ax_cb = divider.new_horizontal(size="5%", pad=0.1, axes_class=plt.Axes)
        fig.add_axes(ax_cb)
        cbar=fig.colorbar(tricf, cax=ax_cb)
        ticklabs = cbar.ax.get_yticklabels()
        cbar.ax.set_yticklabels(ticklabs, fontsize=fontSize)
        ax_cb.set_title(Z_UNIT, fontsize=fontSize)
      if not show:
        plt.close()
      fig.savefig(file,dpi=220,bbox_inches='tight', pad_inches=0)

    def blank_axes(self,ax):
      """
      blank_axes:  blank the extraneous spines and tick marks for an axes

      Input:
      ax:  a matplotlib Axes object

      Output: None
      """
      ax.spines['right'].set_visible(False)
      ax.spines['top'].set_visible(False)
      ax.spines['bottom'].set_visible(False)
      ax.spines['left'].set_visible(False)
      ax.yaxis.set_ticks_position('none')
      ax.xaxis.set_ticks_position('none')
      ax.tick_params(labelbottom='off', labeltop='off', labelleft='off', labelright='off' ,
                      bottom='off', top='off', left='off', right='off' )
      ax.set_axis_off()

    def legend(self,ax5):
      self.blank_axes(ax5)

      # handles is a list of patch handles
      handles = []
      # names is the list of corresponding labels to appear in the legend
      names = []

      if self.otherDf is not None:
        line1 = mlines.Line2D(range(1), range(1), color="white", marker='*',markerfacecolor="black",markersize=17)
        handles.append(line1)
        names.append(self.otherDf.name)

      line2 = mlines.Line2D(range(1), range(1), color="white", marker='o',markerfacecolor="black")
      handles.append(line2)
      names.append(self.legend_stations_label)

      for transect in self.transects:
        tr1 = mlines.Line2D([], [], color=transect.color, ls="-", linewidth=1.5,marker='o')
        handles.append(tr1)
        names.append(transect.name)

      ax5.legend(handles, names)

    def ic(self,ax,hasBorders="map3",vMin=None,vMax=None,transparency=1,showPoints=False,contour="contourLine",drawMinMaxT=False,ID_LABEL="ID",LON_LABEL="Longitud",LAT_LABEL="Latitud",Z_LABEL="°C",Z_UNIT="°C"):
      if self.otherDf is not None and self.otherDf.df is not None:
        xMaq=self.otherDf.df[LON_LABEL].values
        yMaq=self.otherDf.df[LAT_LABEL].values
        xynpsMaq = ax.projection.transform_points(ccrs.Geodetic(), xMaq, yMaq)
        xMaq=xynpsMaq[:,0]
        yMaq=xynpsMaq[:,1]
      x=self.df[LON_LABEL].values
      y=self.df[LAT_LABEL].values
      xynps = ax.projection.transform_points(ccrs.Geodetic(), x, y)
      x=xynps[:,0]
      y=xynps[:,1]
      dely = Delaunay(np.column_stack((x,y)))
      triang = tri.Triangulation(x=x, y=y, triangles=dely.vertices)
      if showPoints:
        ax.triplot(triang, marker="o",linewidth=0,color='k',markersize=4)
      if self.otherDf is not None and self.otherDf.df is not None:
          ax.plot(xMaq,yMaq, color='k',marker="*",  markersize=10)
      if drawMinMaxT:
        max_=self.df[self.df[Z_LABEL]==self.df[Z_LABEL].max()]
        min_=self.df[self.df[Z_LABEL]==self.df[Z_LABEL].min()]
        self.annotate(max_,ax,LON_LABEL,LAT_LABEL,Z_LABEL,Z_UNIT)
        self.annotate(min_,ax,LON_LABEL,LAT_LABEL,Z_LABEL,Z_UNIT)
      if self.otherDf is not None and self.otherDf.df is not None:
          self.annotate(self.otherDf.df,ax,LON_LABEL,LAT_LABEL,Z_LABEL,Z_UNIT)
      if contour=="contourLine":
        temperature=self.df[Z_LABEL].values
        if vMin!=None and vMax!=None:
          tricf=ax.tricontourf(triang,temperature, levels=np.linspace(vMin,vMax,50), cmap="jet",alpha=transparency)
        else:
          tricf=ax.tricontourf(triang,temperature, levels=50, cmap="jet",alpha=transparency)
        if self.otherDf is not None and self.otherDf.df is not None:
          ax.plot(xMaq,yMaq, color='k',marker="*",  markersize=10)
        if hasBorders!=None:
          self.border(ax,tricf,hasBorders)
        return tricf
      elif contour=="triangulation":
        return plt.triplot(triang, marker=None)
      return None

    def annotate(self,df_to_annotate,ax,LON_LABEL,LAT_LABEL,Z_LABEL,Z_UNIT):
        df_t=df_to_annotate[Z_LABEL].values
        df_x=df_to_annotate[LON_LABEL].values
        df_y=df_to_annotate[LAT_LABEL].values
        for i, txt in enumerate(df_t):
          xynps_ = ax.projection.transform_points(ccrs.Geodetic(), df_x,df_y)
          df_x=xynps_[:,0]
          df_y=xynps_[:,1]
          ax.annotate("   {} {}".format(txt,Z_UNIT), (df_x[i], df_y[i]),fontsize='medium',weight='bold')

    def border(self,ax,tricf,path):
      data = json.load(open(path))
      df = pd.DataFrame(data["features"])
      df=df["geometry"].values
      polygon=[]
      for i in df:
        polygon += i["coordinates"][0]
      polygon=np.array(polygon)
      x=polygon[:,0]
      y=polygon[:,1]
      xynps = ax.projection.transform_points(ccrs.Geodetic(), x, y)
      x=xynps[:,0]
      y=xynps[:,1]
      polygon=np.c_[x, y]
      clippath = PathPlt(polygon)
      patch = PathPatch(clippath, facecolor='none',linewidth=0)
      ax.add_patch(patch)
      for c in tricf.collections:
        c.set_clip_path(patch)

class Transect:
    def __init__(self, path, x,y,color,name):
      self.path = path
      self.x = x
      self.y = y
      self.color = color
      self.name = name