From 9c004dde5ab90826019689208da6130b2c7f0263 Mon Sep 17 00:00:00 2001 From: Anthony <schrapff.ant@gmail.com> Date: Thu, 7 May 2020 09:01:18 -0300 Subject: [PATCH] Add RoutingPPViewer --- Diags/RoutingPPViewer/Voronoi_grid.py | 134 +++++++ Diags/RoutingPPViewer/class_Routing.py | 148 +++++++ Diags/RoutingPPViewer/interactive.py | 523 +++++++++++++++++++++++++ 3 files changed, 805 insertions(+) create mode 100644 Diags/RoutingPPViewer/Voronoi_grid.py create mode 100644 Diags/RoutingPPViewer/class_Routing.py create mode 100644 Diags/RoutingPPViewer/interactive.py diff --git a/Diags/RoutingPPViewer/Voronoi_grid.py b/Diags/RoutingPPViewer/Voronoi_grid.py new file mode 100644 index 0000000..a680363 --- /dev/null +++ b/Diags/RoutingPPViewer/Voronoi_grid.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Thu Apr 30 13:18:21 2020 + +@author: anthony +""" + +from scipy.spatial import Voronoi, voronoi_plot_2d +import numpy as np +import shapely.geometry +import shapely.ops as ops +import shapely +import matplotlib.pyplot as plt + +def voronoi_finite_polygons_2d(vor, radius=None): + """ + Reconstruct infinite voronoi regions in a 2D diagram to finite + regions. + + Parameters + ---------- + vor : Voronoi + Input diagram + radius : float, optional + Distance to 'points at infinity'. + + Returns + ------- + regions : list of tuples + Indices of vertices in each revised Voronoi regions. + vertices : list of tuples + Coordinates for revised Voronoi vertices. Same as coordinates + of input vertices, with 'points at infinity' appended to the + end. + + """ + + if vor.points.shape[1] != 2: + raise ValueError("Requires 2D input") + + new_regions = [] + new_vertices = vor.vertices.tolist() + + center = vor.points.mean(axis=0) + if radius is None: + radius = vor.points.ptp().max() + + # Construct a map containing all ridges for a given point + all_ridges = {} + for (p1, p2), (v1, v2) in zip(vor.ridge_points, vor.ridge_vertices): + all_ridges.setdefault(p1, []).append((p2, v1, v2)) + all_ridges.setdefault(p2, []).append((p1, v1, v2)) + + # Reconstruct infinite regions + for p1, region in enumerate(vor.point_region): + vertices = vor.regions[region] + + if all(v >= 0 for v in vertices): + # finite region + new_regions.append(vertices) + continue + + # reconstruct a non-finite region + ridges = all_ridges[p1] + new_region = [v for v in vertices if v >= 0] + + for p2, v1, v2 in ridges: + if v2 < 0: + v1, v2 = v2, v1 + if v1 >= 0: + # finite ridge: already in the region + continue + + # Compute the missing endpoint of an infinite ridge + + t = vor.points[p2] - vor.points[p1] # tangent + t /= np.linalg.norm(t) + n = np.array([-t[1], t[0]]) # normal + + midpoint = vor.points[[p1, p2]].mean(axis=0) + direction = np.sign(np.dot(midpoint - center, n)) * n + far_point = vor.vertices[v2] + direction * radius + + new_region.append(len(new_vertices)) + new_vertices.append(far_point.tolist()) + + # sort region counterclockwise + vs = np.asarray([new_vertices[v] for v in new_region]) + c = vs.mean(axis=0) + angles = np.arctan2(vs[:,1] - c[1], vs[:,0] - c[0]) + new_region = np.array(new_region)[np.argsort(angles)] + + # finish + new_regions.append(new_region.tolist()) + + return new_regions, np.asarray(new_vertices) + + +def get_voronoi_polygons(P, border): + vor = Voronoi(P) + regions, vertices = voronoi_finite_polygons_2d(vor) + + polygons = [] + for region in regions: + polygon = vertices[region] + if shapely.geometry.Polygon(polygon).intersects(border): + polygons.append(shapely.geometry.Polygon(polygon).intersection(border)) + else: + polygons.append([]) + + # Equivalence points de P et polygons -> get pts de region + [] + + return polygons + + +if __name__ == "__main__": + + border = shapely.geometry.Polygon([[0,0], [0,1], [1,1],[1,0],[0,0]]) + P = np.random.random((35,2)) + + polygons = get_voronoi_polygons(P, border) + x,y = border.exterior.xy + plt.plot(x,y) + + for p in polygons: + p1 = p.intersection(border) + x,y = p1.exterior.xy + plt.plot(x,y) + + plt.show() + + diff --git a/Diags/RoutingPPViewer/class_Routing.py b/Diags/RoutingPPViewer/class_Routing.py new file mode 100644 index 0000000..dcaee35 --- /dev/null +++ b/Diags/RoutingPPViewer/class_Routing.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +class Routing File +@author: anthony +""" + +from netCDF4 import Dataset as NetCDFFile +import numpy as np +import numpy.ma as ma + +import matplotlib.pyplot as plt +import cartopy +import cartopy.crs as ccrs +import cartopy.io.shapereader as shpreader +from shapely.geometry import Polygon + + + +class routing: + def __init__(self, dfile): + self.nc = NetCDFFile(dfile, "r") + self.varlist = list(self.nc.variables.keys()) + + self.get_vars() + self.get_extent() + self.get_grid() + self.get_basin_list() + + ############################## + # Initialization Methods + # + def get_vars(self): + self.var = {} + for v in self.varlist: + self.var[v] = self.nc.variables[v][:] + self.var["basinid"] = ma.masked_where(np.isnan(self.var["basinid"]), self.var["basinid"]) + self.nbpt = int(np.sum(self.var["land"])) + self.nbasmax = self.var["basinid"].shape[0] + self.nbnd = self.var["lon_bnd"].shape[0] + + self.conv_land2ij = [[np.where(self.var["nbpt_glo"] == i)[0][0], \ + np.where(self.var["nbpt_glo"] == i)[1][0]] \ + for i in range(1, self.nbpt+1)] + self.var_land = {} + for v in self.varlist: + if self.var[v].ndim == 2: + self.var_land[v] = [self.var[v][j,i] for j,i in self.conv_land2ij] + elif v == "lon_bnd" or v == "lat_bnd": + self.var_land[v] = [self.var[v][:,j,i] \ + for j,i in self.conv_land2ij] + elif self.var[v].ndim == 3: + self.var_land[v] = [self.var[v][:int(self.var["routenbintobas"][j,i]),j,i] \ + for j,i in self.conv_land2ij] + + def get_grid(self): + self.GRID = [self.get_polygon(i) for i in range(self.nbpt)] + def get_polygon(self, i): + pts = [(self.var_land["lon_bnd"][i][l], self.var_land["lat_bnd"][i][l]) for l in range(self.nbnd)] + return Polygon(pts) + + def get_extent(self, bid = None): + self.resh = np.nanmax(np.diff(self.var["lon"][:,:], axis = 1)) + self.resv = np.nanmax(np.diff(self.var["lat"][:,:], axis = 0)) + + if bid is not None: + mask = self.basin_mask(bid) + mask = np.sum(mask, axis = 0) + A = np.where(mask>0) + lonnd = [self.var["lon_bnd"][:,A[0][i], A[1][i]] for i in range(len(A[0]))] + latnd = [self.var["lat_bnd"][:, A[0][i], A[1][i]] for i in range(len(A[0]))] + + ext = [np.min(lonnd)-self.resh, np.max(lonnd)+self.resh, \ + np.min(latnd)-self.resv, np.max(latnd)+self.resh] + return ext + else: + self.ext = [np.nanmin(self.var["lon_bnd"])-self.resh, np.nanmax(self.var["lon_bnd"])+self.resh, \ + np.nanmin(self.var["lat_bnd"])-self.resv, np.nanmax(self.var["lat_bnd"])+self.resv] + ############################## + # Basic basin operation + # + def get_basin_list(self): + basin_list = ma.masked_where(np.isnan(self.var["basinid"]),self.var["basinid"]) + basin_list = list(ma.unique(basin_list[basin_list.mask == False])) + area = [np.sum(self.basin_area(bid)) for bid in basin_list] + self.basin_list = [[int(basin_list[i]), int(area[i])] for i in np.flip(np.argsort(area))] + + def basin_area(self,bid): + mask = self.basin_mask(bid) + area = np.nansum(mask*self.var["basin_area"], axis = 0) + return area + + def basin_mask(self,bid): + A = ma.where(self.var["basinid"] == float(bid)) + pts = self.where2list(A) + # + mask = np.zeros(self.var["basinid"].shape) + mask[A] = 1 + return mask + + def basin_listpoints(self, bid): + mask = np.sum(self.basin_mask(bid), axis = 0) + lstpts = [i for i in range(self.nbpt) if mask[r1.conv_land2ij[i][0],r1.conv_land2ij[i][1]]> 0] + return lstpts + + def main_fetch(self, bid, p = 90): + mask = self.basin_mask(bid) + pts = self.where2list(np.where(mask==1)) + fetch = [self.var["fetch"][a,b,c] for a,b,c in pts] + # + maxfetch = np.max(np.array(fetch)) + perc = np.percentile(fetch, p) + A = np.where(fetch>perc)[0] + pts_out = [pts[i] for i in A] + return pts_out + + def outflow(self, bid): + mask = self.basin_mask(bid) + pts = self.where2list(np.where(mask==1)) + out1 = ma.filled(self.var["routetobasin"], -99) + outbas1 = np.array([out1[a,b,c] for a,b,c in pts]) + pts_out = [pts[i]for i in np.where(outbas1>self.nbasmax)[0]] + outflow = [[int(self.var["routetobasin"][a,b,c]), int(self.var["fetch"][a,b,c]),[a,b,c]] for a,b,c in pts_out] + + return outflow + + def inflow_outflow_htus(self, htus): + x = [] + y = [] + for a,b,c in htus: + k = int(self.var["routetobasin"][a,b,c]-1) + if k<self.nbasmax: + jj,ii = self.conv_land2ij[int(self.var["routetogrid"][a,b,c]-1)] + x.append((self.var["CG_lon"][a,b,c], self.var["CG_lon"][k,jj,ii])) + y.append((self.var["CG_lat"][a,b,c], self.var["CG_lat"][k,jj,ii])) + else: + x.append([self.var["CG_lon"][a,b,c]]) + y.append([self.var["CG_lat"][a,b,c]]) + + return x,y + + ############################## + # Basic Methods + # + def where2list(self, A): + pts = [[A[0][i],A[1][i], A[2][i]] for i in range(len(A[0]))] + return pts + diff --git a/Diags/RoutingPPViewer/interactive.py b/Diags/RoutingPPViewer/interactive.py new file mode 100644 index 0000000..a6a4f07 --- /dev/null +++ b/Diags/RoutingPPViewer/interactive.py @@ -0,0 +1,523 @@ +from tkinter import * +from tkinter import font +from tkinter import filedialog +import sys +import matplotlib +matplotlib.use("TkAgg") +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as cfeature +import cartopy.io.shapereader as shpreader +import cartopy.io.img_tiles as cimgt +import numpy as np +import matplotlib as mpl +from matplotlib import cm + +# Add the location where the programs are located if necessary +#sys.path.append("/home/anthony/Documents/LOCAL/RoutingPP/ROUTING_Analysis_tools/Programs") + +from class_Routing import routing +from Voronoi_grid import get_voronoi_polygons +import numpy.ma as ma + +################################################ +# +# Class Interface +# Main class of the program + +class Interface(Frame): + def __init__(self, parent, **kwargs): + Frame.__init__(self, parent, width=768, height=576) + + self.container = Frame(self) + self.container.pack(side="top", fill="both", expand = True) + self.container.grid_rowconfigure(0, weight=1) + self.container.grid_columnconfigure(0, weight=1) + self.parent = parent + self.loaded = False + self.grid = False + self.main = False + self.basin_id = 0 + self.nbpt = 0 + self.HTUview = "global" # or local + self.HTUneighbours = False + self.HTUarrow = False + self.initUI() + + + def initUI(self): + self.parent.title("RoutingPP Viewer") + self.pack(fill=BOTH, expand=1) + + menubar = Menu(self.parent) + self.parent.config(menu=menubar) + + fileMenu = Menu(menubar) + fileMenu.add_command(label="Open", command=self.onOpen) + fileMenu.add_command(label="Exit", command=self.parent.quit) + + menubar.add_cascade(label="File", menu=fileMenu) + + self.frames = {} + frame = BASINS(self.container, self) + frame.grid(row=0, column=0, sticky="nsew") + self.frames[BASINS] = frame + self.show_frame(BASINS) + + def show_frame(self, cont): + frame = self.frames[cont] + frame.grid(row=0,column=0,sticky="nsew") + frame.tkraise() + + def update_BASINS(self): + frame = BASINS(self.container, self, self.title) + frame.grid(row=0, column=0, sticky="nsew") + self.frames[BASINS] = frame + self.show_frame(BASINS) + + def update_HTUS(self): + frame = HTUS(self.container, self, self.title) + frame.grid(row=0, column=0, sticky="nsew") + self.frames[HTUS] = frame + self.show_frame(HTUS) + + def get_nbpt(self, nbpt): + self.nbpt = nbpt + self.update_HTUS() + + def grid_button(self): + self.grid = not self.grid + self.update_BASINS() + + def basin_plot(self): + self.update_BASINS() + + def main_river(self): + self.main = not self.main + self.update_BASINS() + + def local_global(self): + if self.HTUview == "global" : + self.HTUview = "local" + elif self.HTUview == "local" : + self.HTUview = "global" + self.update_HTUS() + + def arrows(self): + self.HTUarrow = not self.HTUarrow + self.update_HTUS() + + def neighbours(self): + self.HTUneighbours = not self.HTUneighbours + self.update_HTUS() + + def onOpen(self): + + ftypes = [('NetCDF Routing', '*.nc'), ('All files', '*')] + dlg = filedialog.Open(self, filetypes = ftypes) + fl = dlg.show() + + # to test the program + #fl = "/home/anthony/Documents/LOCAL/RoutingPP/ROUTING_Analysis_tools/Originals/LC_Spain_test_graph_corr.nc" + #fl = "/home/anthony/Documents/LOCAL/RoutingPP/ROUTING_Analysis_tools/Originals/EuroSW_Mallorca.nc" + + self.frames = {} + if fl != '': + self.rr = routing(fl) + self.loaded = True + self.title = fl.split("/")[-1] + frame = BASINS(self.container, self, self.title) + frame.grid(row=0, column=0, sticky="nsew") + self.frames[BASINS] = frame + self.show_frame(BASINS) + +################################################ +# +# Class BASIN +# Class of the page showing the basins + +class BASINS(Frame): + def __init__(self, parent, controller, title = "River routing, select a file"): + Frame.__init__(self, parent) + label = Label(self, text=title) + label.pack(pady=10,padx=10) + self.controller = controller + + if controller.loaded: + + b1 = Label(self, text="Actual mode : Basin view") + b1.pack(pady=10,padx=10) + #b1.pack(side = TOP) + + b2 = Button(self, text="Switch to HTUs view", command = controller.update_HTUS) + b2.pack(side = TOP) + + self.main_fig(controller.rr.ext) + + button1 = Button(self, text="Grid", command = controller.grid_button) + button1.pack(side = TOP) + + + readOnlyText = Text(self) + label1 = Label(self, text =" Select basin : ") + label1.pack(side = TOP) + + OPTIONS = ["None"] + [b[0] for b in controller.rr.basin_list[0:30]] + self.variable = StringVar(parent) + if controller.basin_id == 0: + self.variable.set("None") + else: + self.variable.set(controller.basin_id) + w = OptionMenu(self, self.variable, *OPTIONS) + w.pack(side = TOP) + + button2 = Button(self, text="Show basin", command = self.basin_id) + button2.pack(side = TOP) + + if controller.basin_id != 0: + button3 = Button(self, text="Main river", command = controller.main_river) + button3.pack(side = TOP) + + else: + self.main_fig() + + def basin_id(self): + if self.variable.get() == "None": + self.controller.basin_id = 0 + else: + self.controller.basin_id = self.variable.get() + self.controller.basin_plot() + + def main_fig(self, extent = None): + + df = draw_Figure(self, extent, self.controller.grid, self.controller.basin_id, self.controller.main) + + canvas = FigureCanvasTkAgg(df.fig, master=self) + canvas.draw() + canvas.get_tk_widget().pack(side=LEFT, fill=BOTH, expand=True) + canvas._tkcanvas.pack(side=LEFT, fill=BOTH, expand=True) + +################################################ +# +# Class HTUs +# Class of the page showing the basins + +class HTUS(Frame): + + def __init__(self, parent, controller, title = ""): + Frame.__init__(self, parent) + label = Label(self, text=title) + label.pack(pady=10,padx=10) + self.controller = controller + + b1 = Label(self, text="Actual mode : HTUs View", command = None) + b1.pack(pady=10,padx=10) + + b2 = Button(self, text="Switch to Basin view", command = controller.update_BASINS) + b2.pack(side = TOP) + + if controller.HTUview == "global": # or local + if controller.nbpt == 0: + self.main_fig(controller.rr.ext) + if controller.nbpt != 0: + self.main_fig(controller.rr.ext, True) + elif controller.HTUview == "local": + self.voronoi() + + + # Pour entrer le nbpt ! + b1 = Label(self, text="Enter the grid point number") + b1.pack(pady=10,padx=10) + b1 = Label(self, text="(min: 1; max {0})".format(controller.rr.nbpt)) + b1.pack(pady=10,padx=10) + self.e = Entry(self) + self.e.pack(pady=10,padx=10) + + button1 = Button(self, text="Show selected grid point", command = self.get_nbpt) + button1.pack(side = TOP) + + if controller.HTUview == "local": + text_button4 = "Switch to global map" + + if controller.HTUneighbours: + text_button2 = "Hide neighbours" + else: + text_button2 = "Show neighbours" + + button2 = Button(self, text=text_button2, command = self.neighbours) + button2.pack(side = TOP) + + if controller.HTUarrow: + text_button3 = "Hide arrows" + else: + text_button3 = "Show arrows" + + button3 = Button(self, text=text_button3, command = self.arrows) + button3.pack(side = TOP) + else: + text_button4 = "Switch to local map" + button4 = Button(self, text=text_button4, command = self.local_global_map) + button4.pack(side = TOP) + + def get_nbpt(self): + nbpt = self.e.get() + if nbpt.isnumeric(): + nbpt = int(nbpt) + if (nbpt>0) and (nbpt<=self.controller.rr.nbpt): + self.controller.get_nbpt(nbpt) + else: + print("error") + else: + print("error") + # error + return + + def local_global_map(self): + self.controller.local_global() + + def neighbours(self): + self.controller.neighbours() + + def arrows(self): + self.controller.arrows() + + def main_fig(self, extent = None, grid = False): + df = draw_Figure(self, extent, grid, pt = self.controller.nbpt) + + canvas = FigureCanvasTkAgg(df.fig, master=self) + canvas.draw() + canvas.get_tk_widget().pack(side=LEFT, fill=BOTH, expand=True) + canvas._tkcanvas.pack(side=LEFT, fill=BOTH, expand=True) + + def voronoi(self): + df = draw_Voronoi(self, nb = self.controller.nbpt, neighbour = self.controller.HTUneighbours, arrow = self.controller.HTUarrow) + + canvas = FigureCanvasTkAgg(df.fig, master=self) + canvas.draw() + canvas.get_tk_widget().pack(side=LEFT, fill=BOTH, expand=True) + canvas._tkcanvas.pack(side=LEFT, fill=BOTH, expand=True) + +################################################ +# +# Class draw_figure +# Class of the map figures + + +class draw_Figure: + """ + Global map and local map of the basins + """ + def __init__(self, page, extent, grid, basin_id = 0 , main=False, pt = 0): + self.page = page + self.extent = extent + self.grid = grid + self.basin_id = basin_id + self.main = main + self.pt = pt + + self.init_figure() + if self.extent is not None: + self.local_map() + self.draw_grid() + self.draw_basin() + self.main_river() + self.draw_nbpt_loc() + else: + self.global_map() + + ##### + + def init_figure(self): + self.fig = plt.figure(figsize=(8,4), dpi=100) + self.ax = self.fig.add_axes([0.01, 0.01, 0.98, 0.98], projection=ccrs.PlateCarree()) + + def draw_grid(self): + if self.grid: + for l in self.page.controller.rr.GRID: + x, y = l.exterior.xy + plt.plot(x,y, color = "k") + + def draw_basin(self): + if self.basin_id != 0 : + area = self.page.controller.rr.basin_area(int(self.basin_id)) + area = [area[j,i]/self.page.controller.rr.var["area"][j,i]*100 for j,i in self.page.controller.rr.conv_land2ij] + cmap = cm.get_cmap('viridis', 12) + norm = mpl.colors.Normalize(vmin=0.,vmax=np.max(area)) + for l, ar in zip(self.page.controller.rr.GRID, area): + if ar>0: + x, y = l.exterior.xy + plt.fill(x,y, color = cmap(norm(ar))) + plt.title("basin_id : {0}".format(int(self.basin_id))) + + def draw_nbpt_loc(self): + if self.pt != 0: + l = self.page.controller.rr.GRID[self.pt-1] + x, y = l.exterior.xy + plt.fill(x,y, color = "r") + + def global_map(self): + self.ax.set_global() + self.ax.stock_img() + self.ax.coastlines() + lw = 0.5 + river_50m = cfeature.NaturalEarthFeature('physical', 'rivers_lake_centerlines', '10m', facecolor='none', edgecolor = "#011f4b", lw = lw) + self.ax.add_feature(river_50m) + + def local_map(self): + self.ax.set_extent(self.extent) + if (self.basin_id != 0) or (self.pt != 0): + fc_coast = "none" + fc_ocean = "none" + else: + fc_coast ='#77ab59' + fc_ocean ='#99ccff' + coast = cfeature.NaturalEarthFeature('physical', 'coastline', '50m', facecolor=fc_coast, edgecolor = "k", lw = 1) + self.ax.add_feature(coast) + ocean = cfeature.NaturalEarthFeature('physical', 'ocean', '50m', facecolor=fc_ocean, edgecolor = "none") + self.ax.add_feature(ocean) + lw = 1 + river_50m = cfeature.NaturalEarthFeature('physical', 'rivers_lake_centerlines', '10m', facecolor='none', edgecolor = "#011f4b", lw = lw) + self.ax.add_feature(river_50m) + + + def main_river(self): + if self.main: + pts_out = self.page.controller.rr.main_fetch(int(self.basin_id), p = 90) + outflow = self.page.controller.rr.outflow(int(self.basin_id)) + x,y = self.page.controller.rr.inflow_outflow_htus(pts_out) + + i=0 + for xx, yy in zip(x,y): + if len(xx)>1: + plt.plot(xx,yy,ls = "-", color = "k") + + for xx, yy in zip(x,y): + plt.plot(xx[0], yy[0], "bo", ms = 5) + + x,y = self.page.controller.rr.inflow_outflow_htus([outflow[i][2] for i in range(len(outflow))]) + for xx, yy in zip(x,y): + plt.plot(xx[0], yy[0], "ro", ms = 10) + + plt.title("Basin {0} main htus".format(self.basin_id)) + + +################################################ +# +# Class draw_figure +# Class of the Voronoi diagram figures + +class draw_Voronoi: + """ + Global map and local map of the basins + """ + def __init__(self, page, nb, neighbour, arrow): + + if neighbour: + j,i = page.controller.rr.conv_land2ij[nb-1] + array = ma.array(page.controller.rr.var["nbpt_glo"][j-1:j+2, i-1:i+2]).astype(np.int32) + gridpts = list(ma.unique(array[(array.mask == False)])) + LNB = [pt for pt in gridpts if pt>0] + else: + LNB = [nb] + + self.page = page + self.start_map() + self.get_limits(LNB) + + for pt in LNB: + main = False + if pt == nb: main = True + self.plot_voronoi(pt, arrow, main) + + x, y = page.controller.rr.GRID[nb-1].exterior.xy + plt.plot(x,y, color = "r") + + cbaxes = self.fig.add_axes([0.82, 0.1, 0.03, 0.75]) + cb1 = mpl.colorbar.ColorbarBase(ax = cbaxes, cmap=self.viridis, + norm=self.norm, + orientation='vertical', alpha = 0.6) + cb1.set_label('\% of total area of the grid box') + self.fig.subplots_adjust(left = 0.05, right = 0.8) + + + def start_map(self): + self.viridis = cm.get_cmap('Reds', 12) + self.norm = mpl.colors.Normalize(vmin=0.,vmax=100) + + self.fig = plt.figure(figsize= (7,7)) + self.ax = plt.subplot(1, 1, 1, projection=ccrs.PlateCarree()) + geo_reg_shp = shpreader.natural_earth(resolution='10m', category='physical',\ + name='coastline') + geo_reg = shpreader.Reader(geo_reg_shp) + self.ax.add_geometries(geo_reg.geometries(), ccrs.PlateCarree(), \ + edgecolor="k", facecolor='none') + + def get_limits(self, LNB): + ext = self.page.controller.rr.resh/2. + lat = [] + lon = [] + for pt in LNB: + j,i = self.page.controller.rr.conv_land2ij[pt-1] + lat = lat + list(self.page.controller.rr.var["lat_bnd"][:,j,i]) + lon = lon + list(self.page.controller.rr.var["lon_bnd"][:,j,i]) + + limits = [np.min(lon)-ext, np.max(lon)+ext, np.min(lat)-ext, np.max(lat)+ext] + self.ax.set_extent(limits) + + def plot_voronoi(self, nb, arrow = True, main = False): + rr = self.page.controller.rr + j,i = rr.conv_land2ij[nb-1] + nbas = int(rr.var["routenbintobas"][j,i]) + outgrid = [g for g in rr.var["routetogrid"][:nbas,j,i]] + outbas = [b for b in rr.var["routetobasin"][:nbas,j,i]] + + area = np.array([b for b in rr.var["basin_area"][:nbas,j,i]]) + area =area/rr.var["area"][j,i]*100 + + htus = [[lon, lat] for lon, lat in zip(rr.var["CG_lon"][:nbas,j,i], rr.var["CG_lat"][:nbas,j,i])] + htus = np.array(htus) + + X = [] + Y = [] + for l, htu in enumerate(htus): + jj,ii = rr.conv_land2ij[int(rr.var["routetogrid"][l,j,i]-1)] + k = int(rr.var["routetobasin"][l,j,i]-1) + if (k<rr.nbasmax): + x = [htu[0], rr.var["CG_lon"][k,jj,ii]] + y = [htu[1], rr.var["CG_lat"][k,jj,ii]] + X.append(x) + Y.append(y) + + if arrow: + for x, y in zip(X, Y): + plt.arrow(x[0], y[0], x[1]-x[0], y[1]-y[0], "k", length_includes_head = True, head_length = 0.01, head_width = 0.01) + + A, B = htus[:,0], htus[:,1] + plt.scatter(A, B, marker='.') + + polygons = get_voronoi_polygons(htus, rr.GRID[nb-1]) + for i,p in enumerate(polygons): + if p != []: + x,y = p.exterior.xy + plt.fill(x,y, color = self.viridis(self.norm(area[i])), alpha = 0.6) + plt.plot(x,y,color = "k") + + + x, y = rr.GRID[nb-1].exterior.xy + plt.plot(x,y, color = "k") + + i = 0 + for lon, lat in htus: + plt.plot(lon, lat, "o",alpha = 0.7, color = "b") + if outbas[i]>rr.nbasmax: + plt.plot(lon, lat, "o",alpha = 0.7, ms = 5, color = "r") + i+=1 + +def main(): + root = Tk() + interface = Interface(root) + root.mainloop() + +if __name__ == '__main__': + main() -- GitLab