def hfun_(coastlines, res=.1, R=1.): amask = (coastlines.bounds.miny < coastlines.bounds.miny.min() + .1) anta = coastlines[amask] anta = anta.reset_index(drop=True) ### convert to stereo try: ant = pd.DataFrame(anta.boundary.values[0].coords[:], columns=['lon', 'lat']) except: ant = pd.DataFrame(anta.boundary.explode().values[0].coords[:], columns=['lon', 'lat' ]) # convert boundary values to pandas d1 = ant.where(ant.lon == ant.lon.max()).dropna().index[ 1:] # get artificial boundaries as -180/180 d2 = ant.where(ant.lon == ant.lon.min()).dropna().index[1:] ant = ant.drop(d1).drop(d2) # drop the points d3 = ant.where( ant.lat == ant.lat.min()).dropna().index # drop lat=-90 line ant = ant.drop(d3) ub, vb = to_stereo(ant.lon.values, ant.lat.values, R) ant.lon = ub ant.lat = vb an = gp.GeoDataFrame({ 'geometry': [shapely.geometry.LineString(ant.values)], 'length': shapely.geometry.LineString(ant.values).length }) # put together a LineString # create simple grid d1 = np.linspace(an.bounds.minx, an.bounds.maxx, 100) d2 = np.linspace(an.bounds.miny, an.bounds.maxy, 100) ui, vi = np.meshgrid(d1, d2) # Use Matplotlib for triangulation triang = matplotlib.tri.Triangulation(ui.flatten(), vi.flatten()) tri = triang.triangles #stereo->2D scale ci = 4 * R**2 / (ui**2 + vi**2 + 4 * R**2) ci # create weight field points = np.column_stack([ui.flatten(), vi.flatten()]) dps = pd.DataFrame(points, columns=['u', 'v']) dps['z'] = 0 dps['h'] = res / ci.flatten() tria3 = pd.DataFrame(tri, columns=['a', 'b', 'c']) tria3['w'] = 0 p1 = dps.to_xarray() p1 = p1.rename({'index': 'nodes'}) p1 = p1.assign({'tria': (['elem', 'n'], tria3.values)}) return p1
def sgl(**kwargs): try: geo = gp.GeoDataFrame.from_file(kwargs.get('coastlines', None)) except: logger.warning( 'coastlines is not a file, trying with geopandas Dataset') try: geo = kwargs.get('coastlines', None) except: logger.error('coastlines argument not valid ') sys.exit(1) # Manage coastlines logger.info('preparing coastlines') #Kaspian Sea, if present kasp = ((geo.bounds.miny > 36.) & (geo.bounds.maxy < 48.) & (geo.bounds.maxx < 55.) & (geo.bounds.minx > 45.)) geo = geo.drop(geo.loc[kasp].index) #ANTARTICA anta_mask = (geo.bounds.miny < geo.bounds.miny.min() + .1 ) # indentify antartica anta = geo.loc[anta_mask] indx = anta.index # keep index try: anta = pd.DataFrame(anta.boundary.values[0].coords[:], columns=['lon', 'lat']) except: anta = pd.DataFrame( anta.boundary.explode()[0].coords[:], columns=['lon', 'lat']) # convert boundary values to pandas d1 = anta.where(anta.lon == anta.lon.max()).dropna().index[ 1:] # get artificial boundaries as -180/180 d2 = anta.where(anta.lon == anta.lon.min()).dropna().index[1:] anta = anta.drop(d1).drop(d2) # drop the points d3 = anta.where( anta.lat == anta.lat.min()).dropna().index # drop lat=-90 line anta = anta.drop(d3) an = gp.GeoDataFrame( { 'geometry': [shapely.geometry.LineString(anta.values)], 'length': shapely.geometry.LineString(anta.values).length }, index=indx) # put together a LineString geo.loc[indx] = shapely.geometry.LineString( anta.values) # put it back to geo # International Meridian m1 = geo[geo.bounds.minx == -180.].index m2 = geo[geo.bounds.maxx == 180.].index mm = np.concatenate((m1, m2)) # join them mm = [j for j in mm if j != indx] # subtract antartica # convert to u,v (stereographic coordinates) for idx, poly in geo.iterrows(): geo.loc[idx, 'geometry'] = shapely.ops.transform( lambda x, y, z=None: to_stereo(x, y, R=kwargs.get('R', 1.)), poly.geometry) w = geo.drop(indx) # get all polygons ww = w.loc[mm] # join the split polygons gw = gp.GeoDataFrame( geometry=list(ww.buffer(.0001).unary_union) ) # merge the polygons that are split (around -180/180) w = w.drop(mm) # Check antartica LineString if not geo.iloc[indx].geometry.values[0].is_ring: ca = gp.GeoDataFrame(geometry=[ shapely.geometry.LinearRing(geo.loc[indx].geometry.values[0]) ], index=indx) ca['geometry'] = shapely.geometry.LineString(ca.geometry.values[0]) else: ca = geo.loc[indx] # PUT ALL TOGETHER geo = pd.concat([w, gw, ca], ignore_index=True).reset_index(drop=True) logger.info('storing boundaries') geo['tag'] = -(geo.index + 1) idx = 0 dic = {} for i, line in geo.iloc[:-1].iterrows(): lon = [] lat = [] try: for x, y in line.geometry.boundary.coords[:]: lon.append(x) lat.append(y) dic.update({ 'line{}'.format(idx): { 'lon': lon, 'lat': lat, 'tag': line.tag } }) idx += 1 except: for x, y in line.geometry.boundary[0].coords[:]: lon.append(x) lat.append(y) dic.update({ 'line{}'.format(idx): { 'lon': lon, 'lat': lat, 'tag': line.tag } }) idx += 1 for i, line in geo.iloc[-1:].iterrows(): lon = [] lat = [] for x, y in line.geometry.coords[:]: lon.append(x) lat.append(y) dic.update({ 'line{}'.format(idx): { 'lon': lon, 'lat': lat, 'tag': line.tag } }) dict_of_df = {k: pd.DataFrame(v) for k, v in dic.items()} df = pd.concat(dict_of_df, axis=0) df['z'] = 0 df = df.drop_duplicates() # drop the repeat value on closed boundaries return df