Пример #1
0
def getShp(path_glob, ini, end, r_key=4, r_data=5):
    dShapes = {}
    for _shp in iglob(path_glob, recursive=True):
        logging.info(_shp)
        #_shp = os.path.realpath(_shp)
        with shapefile.Reader(_shp) as shp:
            for sr in shp.shapeRecords():
                if sr.shape.points and sr.record and len(sr.record) > 4:
                    natcode = sr.record[r_key]
                    key = natcode[ini:end]
                    if key.isdigit():
                        vals = dShapes.get(key, [])
                        poli = shape(sr.shape)
                        if isinstance(poli, Polygon):
                            poli = MultiPolygon([poli])
                        vals.append((poli, sr.record[r_data]))
                        dShapes[key] = vals
    for key, vals in list(dShapes.items()):
        nombre = set()
        poli = []
        for p, n in vals:
            poli.append(p)
            nombre.add(n)
        if len(nombre) > 1:
            logging.info("Clave %s con varios nombres: %s", key, nombre)
        nombre = nombre.pop()
        main = None
        for ps in poli:
            for p in ps:
                if main is None or main.area < p.area:
                    main = p
        if len(poli) == 1:
            poli = poli[0]
        else:
            poli = cascaded_union(poli)
        dShapes[key] = (poli, nombre)
    dShapes = {k: v for k, v in sorted(dShapes.items(), key=lambda kv: kv[0])}
    return dShapes
Пример #2
0
def calc_gz(GL_FILE='', BASIN_FILE='', VEL_FILE='', region='', dist=0, N=0):
    #-- read the grounding lines
    gdf = gpd.read_file(GL_FILE)
    #-- read the basin file
    basins = gpd.read_file(BASIN_FILE)
    idx = basins.index[basins['NAME'] == region]
    #-- get polygon
    poly = basins['geometry'][idx[0]]

    #-- add a 5km buffer to find the corresponding GLs
    region_poly = poly.buffer(5e3)

    lines = []
    for i in range(len(gdf)):
        #-- extract geometry to see if it's in region of interest
        ll = gdf['geometry'][i]
        if ll.intersects(region_poly):
            lines.append(ll)

    #-- merge all lines into linestring
    lm = ops.linemerge(lines)

    #-- also create a polygon to represent the GZ with a small buffer (10cm)
    gz_file = os.path.join(os.path.dirname(GL_FILE),
                           'GZ_{0}.shp'.format(region))
    if os.path.exists(gz_file):
        print('Reading GZ polygon from file.')
        gz_df = gpd.read_file(gz_file)
        gz_poly = []
        for i in range(len(gz_df)):
            gz_poly.append(gz_df['geometry'][i])
        gz_poly = MultiPolygon(gz_poly)
    else:
        print('Creating GZ polygon.')
        ep = lm.buffer(1e-1)
        #-- get the boundary of the polygon containing all lines to make new polygon of just the envelope
        gz_poly = []
        for ip in ep:
            x, y = ip.exterior.coords.xy
            gz_poly.append(Polygon(zip(x, y)))
        #-- save the error polygon
        #-- first make DataFrame
        df = {'REGION': [], 'center_x': [], 'center_y': []}
        out_geo = []
        for p in gz_poly:
            #-- note the width can be calculated from area and perimeter
            w = (-p.length + np.sqrt(p.length**2 - 16 * p.area)) / 4
            l = p.length / 2 - w
            print(w, l)
            if (w > 1 and l > 1):
                df['REGION'].append(region)
                x, y = p.centroid.coords.xy
                df['center_x'].append(x[0])
                df['center_y'].append(y[0])
                out_geo.append(p)
        out_gdf = gpd.GeoDataFrame(df, geometry=out_geo, crs=gdf.crs)
        out_gdf.to_file(gz_file, driver='ESRI Shapefile')

    #-- read velocity field
    vel_fid = nc.Dataset(VEL_FILE, 'r')
    x = vel_fid['x'][:]
    y = vel_fid['y'][:]
    vx = vel_fid['VX'][:]
    vy = vel_fid['VY'][:]
    #-- also read lat and lon
    # vel_lat = vel_fid['lat'][:]
    # vel_lon = vel_fid['lon'][:]
    vel_fid.close()

    #-- select the points for the calculation of GZ width
    #-- in order to generate points, we randomly draw a line from the
    #-- mutliline, and then draw a random distance to go along the line to get
    #-- a coordinate. We repeat until the specified number of points is reached
    xlist = np.zeros(N)
    ylist = np.zeros(N)
    gz = np.zeros(N)
    vel_transects = {}
    perp_transects = {}
    random.seed(13)
    for i in range(N):
        #-- draw a random index for line along multilines
        ind_line = random.randrange(0, len(lm))
        rand_line = lm[ind_line]
        rand_dist = random.uniform(0, rand_line.length)
        rand_pt = rand_line.interpolate(rand_dist)
        xx, yy = rand_pt.coords.xy
        xlist[i] = float(xx[0])
        ylist[i] = float(yy[0])

    #-- loop through points and calculate GZ
    for i, (xi, yi) in enumerate(zip(xlist, ylist)):
        if i % 100 == 0:
            print(i)

        #-- A) velocity based approach
        #-- get list of distances to get a list of closest points
        #- For a given coordinate, get the flow angle and then the intersecting line
        ii = np.argsort(np.abs(x - xi))
        jj = np.argsort(np.abs(y - yi))

        #-- loop through the first 20 points and get the minimum width, so we dont
        #-- rely on a single point
        tmp_trans = {}
        tmp_dist = np.zeros(25)
        cc = 0
        for k in range(5):
            for w in range(5):
                #-- find flow angle
                ang = np.arctan(vy[jj[w], ii[k]] / vx[jj[w], ii[k]])
                #-- Now constuct a line of a given length, centered at the
                #-- chosen coordinates, with the angle above
                dx, dy = dist * np.cos(ang), dist * np.sin(ang)
                tmp_trans[cc] = LineString([[x[ii[k]] - dx, y[jj[w]] - dy],
                                            [x[ii[k]], y[jj[w]]],
                                            [x[ii[k]] + dx, y[jj[w]] + dy]])

                if tmp_trans[cc].intersects(gz_poly):
                    vel_int = tmp_trans[cc].intersection(gz_poly)
                    tmp_dist[cc] = vel_int.length
                else:
                    print("No intersection. i={0:d}, k={1:d}, w={2:d}".format(
                        i, k, w))
                cc += 1

        ind_min = np.argmin(tmp_dist)
        vel_transects[i] = tmp_trans[ind_min]
        gz[i] = tmp_dist[ind_min]

        # vel_int = vel_transects[i].intersection(gz_poly)
        # gz[i] = vel_int.length

        #-- B) tangent based appriach
        found_match = False
        if gz_poly.geom_type == 'Polygon':
            print("GZ object is polygon.")
            if vel_transects[i].intersects(gz_poly):
                x_ext, y_ext = gz_poly.exterior.coords.xy
                found_match = True
        elif gz_poly.geom_type == 'MultiPolygon':
            for sp in gz_poly:
                if vel_transects[i].intersects(sp):
                    if found_match:
                        print(
                            "More than one intersecting polygon found for point {0:d}"
                            .format(i))
                    else:
                        #-- get coordinates of the exterior of GZ polygon to be used later
                        x_ext, y_ext = sp.exterior.coords.xy
                        found_match = True
        else:
            sys.exit("Exiting. GZ object type: ", gz_poly.geom_type)

        #-- Check if any of the polygons intersect
        if not found_match:
            print("No matches found for point {0:d}".format(i))
            #-- move on to the next point and skip rest of iteration
            continue

        #-- Calculate GZ without velocity for comparison by constructing a perpendicular
        #-- line to the gz polygon at each point
        #-- 1) to get the tangent, get the index of the closest point on the boundary
        #-- of the gz polython
        dist2 = (x_ext - xi)**2 + (y_ext - yi)**2
        # ind = np.argmin(dist2)
        ind = np.argsort(dist2)

        #-- loop through the first few points and get the minimum width, so we dont
        #-- rely on a single point
        tmp_trans = {}
        tmp_dist = np.zeros(10)
        for k in range(10):
            #-- 2) calculate the slope of the tangent
            tangent = (y_ext[ind[k]] - y_ext[ind[k - 1]]) / (x_ext[ind[k]] -
                                                             x_ext[ind[k - 1]])

            #-- 3) calculate slope of perpendicular line
            slope_ang = np.arctan(-1 / tangent)

            #-- 4) construct new transect and calculate width
            dx, dy = dist * np.cos(slope_ang), dist * np.sin(slope_ang)
            tmp_trans[k] = LineString(
                [[x_ext[ind[k]] - dx, y_ext[ind[k]] - dy],
                 [x_ext[ind[k]], y_ext[ind[k]]],
                 [x_ext[ind[k]] + dx, y_ext[ind[k]] + dy]])

            perp_int = tmp_trans[k].intersection(gz_poly)
            tmp_dist[k] = perp_int.length

        ind_min = np.argmin(tmp_dist)
        perp_transects[i] = tmp_trans[ind_min]
        gz[i] = tmp_dist[ind_min]

    #-- write grounding zone widths to file
    outfile = os.path.join(os.path.dirname(GL_FILE),
                           'GZ_widths_{0}.csv'.format(region))
    outfid = open(outfile, 'w')
    outfid.write('X (m),Y (m),width (km)\n')
    for i in range(N):
        outfid.write('{0:.6f},{1:.6f},{2:.3f}\n'.format(
            xlist[i], ylist[i], gz[i] / 1e3))
    outfid.close()

    #-- plot a sample of points to check the grounding zones
    fig = plt.figure(1, figsize=(10, 8))
    ax = fig.add_subplot(111)
    pp = PolygonPatch(poly,
                      alpha=0.3,
                      fc='lawngreen',
                      ec='lawngreen',
                      zorder=1)
    ax.add_patch(pp)
    for il in lines:
        xs, ys = il.coords.xy
        ax.plot(xs, ys, linewidth=0.4, alpha=0.8, color='k', zorder=2)
    for i in range(20):
        ip = random.randrange(0, N)
        #-- while distance to any of the previous points is less than 20km,
        #-- keep trying new indices (doesn't apply to 1st point)
        if i == 0:
            plot_pts = [Point(xlist[ip], ylist[ip])]
        else:
            pt = Point(xlist[ip], ylist[ip])
            while (pt.distance(MultiPoint(plot_pts)) < 20e3):
                ip = random.randrange(0, N)
                pt = Point(xlist[ip], ylist[ip])
            #-- now we can ensure the points aren't overlapping
            print("minimum distance to previous points: ",
                  pt.distance(MultiPoint(plot_pts)))
            plot_pts.append(pt)
        #-- Now plot the transect for the given index
        lx, ly = vel_transects[ip].coords.xy
        ax.plot(lx, ly, linewidth=2.0, alpha=1.0, color='pink', zorder=3)
        if ip in perp_transects.keys():
            lx2, ly2 = perp_transects[ip].coords.xy
            ax.plot(lx2, ly2, linewidth=2.0, alpha=1.0, color='red', zorder=4)
        ax.text(xlist[ip]+5e3,ylist[ip]+5e3,'{0:.1f}km'.format(gz[ip]/1e3),color='darkred',\
         fontsize='small',fontweight='bold',bbox=dict(facecolor='mistyrose', alpha=0.5))
    ax.plot([], [], color='pink', label="Velocity-based Intersect")
    ax.plot([], [], color='red', label="Tangent-based Intersect")
    ax.get_xaxis().set_ticks([])
    ax.get_yaxis().set_ticks([])
    ax.set_title("Grounding Zone Width for {0}".format(region))
    plt.legend()
    plt.tight_layout()
    plt.savefig(outfile.replace('.csv', '.pdf'), format='PDF')
    plt.close(fig)
Пример #3
0

vdf = pd.read_csv('Boston-2-vertices_r.csv')
edf = pd.read_csv('Boston-2-edges-4am_r.csv')


# In[53]:


geometry = []
for i, r in edf.iterrows():
    s = r['s']
    t = r['t']
    ps = Point(vdf['lon'][s], vdf['lat'][s])
    pt = Point(vdf['lon'][t], vdf['lat'][t])
    geometry.append(LineString([ps,pt]))

crs = {'proj': 'latlong', 'ellps': 'WGS84', 'datum': 'WGS84', 'no_defs': True}
crs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"
gdf1 = gpd.GeoDataFrame(edf, geometry=geometry, crs=crs)


# In[48]:


#%matplotlib inline
# fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(8,8), dpi=150)
gdf['color'] = 0.0
ne = 11
gdf.loc[ne,'color'] = 100
gdf.plot(column='color', ax=ax, zorder=1)
Пример #4
0
def calc_gz(GL_FILE='',WIDTH_FILE='',BASIN_FILE='',VEL_FILE='',POINT_FILE='',region='',dist=0,N=0,vel_thr=0):
	#-- read the grounding lines
	df_gl = gpd.read_file(GL_FILE)
	#-- read widths
	df_w = gpd.read_file(WIDTH_FILE)
	#-- read the basin file
	basins = gpd.read_file(BASIN_FILE)
	idx = basins.index[basins['NAME']==region]
	#-- get polygon
	poly = basins['geometry'][idx[0]]

	#-- add a 5km buffer to find the corresponding GLs
	region_poly = poly.buffer(5e3)

	lines = []
	dates = []
	for i in range(len(df_gl)):
		#-- extract geometry to see if it's in region of interest
		ll = df_gl['geometry'][i]
		if ll.intersects(region_poly):
			lines.append(ll)
			dates.append(df_gl['FILENAME'][i].split("_")[2])

	#-- get width lines
	ws = []
	for i in range(len(df_w)):
		ws.append(df_w['geometry'][i])
	widths = MultiLineString(ws)
	
	#-- merge all lines into linestring
	lm = ops.linemerge(lines)

	#-- also create a polygon to represent the GZ with a small buffer (10cm)
	gz_file = os.path.join(os.path.dirname(GL_FILE),'GZ_{0}.shp'.format(region))
	if os.path.exists(gz_file):
		print('Reading GZ polygon from file.')
		gz_df = gpd.read_file(gz_file)
		gz_poly = []
		for i in range(len(gz_df)):
			gz_poly.append(gz_df['geometry'][i])
		gz_poly = MultiPolygon(gz_poly)
	else:
		print('Creating GZ polygon.')
		ep = lm.buffer(1e-1)
		#-- get the boundary of the polygon containing all lines to make new polygon of just the envelope
		gz_poly = []
		for ip in ep:
			x,y = ip.exterior.coords.xy
			gz_poly.append(Polygon(zip(x,y)))
		#-- save the error polygon
		#-- first make DataFrame
		df = {'REGION':[],'center_x':[],'center_y':[]}
		out_geo = []
		for p in gz_poly:
			#-- note the width can be calculated from area and perimeter
			w = (-p.length+np.sqrt(p.length**2 - 16*p.area))/4
			l = p.length/2 - w
			print(w,l)
			if (w > 1 and l > 1):
				df['REGION'].append(region)
				x,y = p.centroid.coords.xy
				df['center_x'].append(x[0])
				df['center_y'].append(y[0])
				out_geo.append(p)
		out_gdf = gpd.GeoDataFrame(df,geometry=out_geo,crs=df_gl.crs)
		out_gdf.to_file(gz_file,driver='ESRI Shapefile')

	#-- read velocity field
	vel_fid = nc.Dataset(VEL_FILE,'r')
	x = vel_fid['x'][:]
	y = vel_fid['y'][:]
	vx = vel_fid['VX'][:]
	vy = vel_fid['VY'][:]
	#-- also read lat and lon
	# vel_lat = vel_fid['lat'][:]
	# vel_lon = vel_fid['lon'][:]
	vel_fid.close()
	
	#-- select the points for the calculation of GZ width
	#-- in order to generate points, we randomly draw a line from the
	#-- mutliline, and then draw a random distance to go along the line to get
	#-- a coordinate. We repeat until the specified number of points is reached
	#-- first we will the array with the given points in POINTS_FILE, and fill
	#-- the rest randomly.
	xlist = np.zeros(N)
	ylist = np.zeros(N)
	gz = np.zeros(N)
	date1_list = [None]*N
	date2_list = [None]*N
	vel_transects = {}
	cn_transects = {}
	
	#-- read given points
	df_pts = gpd.read_file(POINT_FILE)
	#-- reproject to the projection of GL data
	df_pts = df_pts.to_crs(df_gl.crs)
	N_given = len(df_pts)
	print("{0:d} points prescribed out a total of {1:d}".format(N_given,N))
	for i in range(N_given):
		xx,yy = df_pts['geometry'][i].coords.xy
		xlist[i] = float(xx[0])
		ylist[i] = float(yy[0])
	random.seed(13)
	for i in range(N_given,N):
		#-- draw a random index for line along multilines
		ind_line = random.randrange(0,len(lm))
		rand_line = lm[ind_line]
		rand_dist = random.uniform(0, rand_line.length)
		rand_pt = rand_line.interpolate(rand_dist)
		xx,yy = rand_pt.coords.xy
		xlist[i] = float(xx[0])
		ylist[i] = float(yy[0])
	
	#-- make special polygons that require a different transect length
	plong = Polygon([[-1175399.2293594137,-1124281.6845298712],
					[-1166026.3695500833,-1132757.1428680948],
					[-1194493.9384390623,-1149957.337730963],
					[-1198332.822509906,-1146467.4431211061]])
	#-- loop through points and calculate GZ
	for i,(xi,yi) in enumerate(zip(xlist,ylist)):
		if i%100 == 0:
			print(i)
		
		#-- A) velocity based approach
		#-- get list of distances to get a list of closest points
		#- For a given coordinate, get the flow angle and then the intersecting line
		ii = np.argmin(np.abs(x - xi))
		jj = np.argmin(np.abs(y - yi))

		#-- chech if velocity is above required threshold
		vel_mag = np.sqrt(vy[jj,ii]**2 + vx[jj,ii]**2)
		if vel_mag > vel_thr:
			#-- find flow angle
			ang = np.arctan(vy[jj,ii]/vx[jj,ii])
			#-- Now constuct a line of a given length, centered at the 
			#-- chosen coordinates, with the angle above
			if Point(xi,yi).within(plong):
				dx,dy = 25e3*np.cos(ang),25e3*np.sin(ang)
			else:
				dx,dy = dist*np.cos(ang),dist*np.sin(ang)
			vel_transects[i] = LineString([[x[ii]-dx,y[jj]-dy],[x[ii],y[jj]],[x[ii]+dx,y[jj]+dy]])
			#-- get intersection length
			vel_int = vel_transects[i].intersection(gz_poly)
			gz[i] = vel_int.length

			#-- get dates
			pt0 = vel_int.interpolate(0,normalized=True)
			pt1 = vel_int.interpolate(1,normalized=True)
			for l in range(len(lines)):
				if lines[l].distance(pt1) < 0.2:
					date1_list[i] = dates[l]
				elif lines[l].distance(pt0) < 0.2:
					date2_list[i] = dates[l]
		else:
			#-- B) retrieve width from QGIS centerline width calculation
			#-- first get the closest line to the point
			po = Point(xi,yi)
			wdist = np.zeros(len(widths))
			for wi in range(len(widths)):
				wdist[wi] = widths[wi].distance(po)
			ind_w = np.argmin(wdist)

			cn_transects[i] = widths[ind_w]
			#-- get length
			gz[i] = cn_transects[i].length	
			#-- also get the corresponding dates
			pt0 = cn_transects[i].interpolate(0,normalized=True)
			pt1 = cn_transects[i].interpolate(1,normalized=True)
			for l in range(len(lines)):
				if lines[l].distance(pt1) < 0.2:
					date1_list[i] = dates[l]
				elif lines[l].distance(pt0) < 0.2:
					date2_list[i] = dates[l]

	#-- write grounding zone widths to file
	outfile = os.path.join(os.path.dirname(GL_FILE),'GZ_widths-hybrid_{0}.csv'.format(region))
	outfid = open(outfile,'w')
	outfid.write('X (m),Y (m),width (km),date1,date2\n')
	for i in range(N):
		outfid.write('{0:.6f},{1:.6f},{2:.3f},{3},{4}\n'.\
		format(xlist[i],ylist[i],gz[i]/1e3,date1_list[i],date2_list[i]))
	outfid.close()

	#-- plot a sample of points to check the grounding zones
	fig = plt.figure(1,figsize=(10,8))
	ax = fig.add_subplot(111)
	pp = PolygonPatch(poly,alpha=0.3,fc='lawngreen',ec='lawngreen',zorder=1)
	ax.add_patch(pp)
	for il in lines:
		xs,ys = il.coords.xy
		ax.plot(xs,ys,linewidth=0.4,alpha=0.8,color='k',zorder=2)
	for i in range(30):
		if i < N_given:
			ip = copy(i)
			if i == 0:
				plot_pts = [Point(xlist[ip],ylist[ip])]
			else:
				plot_pts.append(Point(xlist[ip],ylist[ip]))
		else:
			ip = random.randrange(0,N)
			#-- while distance to any of the previous points is less than 20km,
			#-- keep trying new indices (doesn't apply to 1st point)
			pt = Point(xlist[ip],ylist[ip])
			while (pt.distance(MultiPoint(plot_pts)) < 12e3):
				ip = random.randrange(0,N)
				pt = Point(xlist[ip],ylist[ip])
			#-- now we can ensure the points aren't overlapping
			print("minimum distance to previous points: ", pt.distance(MultiPoint(plot_pts)))
			plot_pts.append(pt)
		#-- Now plot the transect for the given index
		if ip in vel_transects.keys():
			lx,ly = vel_transects[ip].coords.xy
			ax.plot(lx,ly,linewidth=2.0,alpha=1.0,color='red',zorder=3)
		elif ip in cn_transects.keys():
			lx,ly = cn_transects[ip].coords.xy
			ax.plot(lx,ly,linewidth=2.0,alpha=1.0,color='darkorange',zorder=3)
		ax.text(xlist[ip]+5e3,ylist[ip]+5e3,'{0:.1f}km'.format(gz[ip]/1e3),color='darkred',\
			fontsize=6,fontweight='bold',bbox=dict(facecolor='mistyrose', alpha=0.5))
		# ax.scatter(xlist[ip],ylist[ip],s=10,color='darkorchid',zorder=4,alpha=0.5)
	ax.plot([],[],color='red',label="Velocity-based Intersect")
	ax.plot([],[],color='darkorange',label="Centerline-based Intersect")
	ax.get_xaxis().set_ticks([])
	ax.get_yaxis().set_ticks([])
	ax.set_title("Grounding Zone Width for {0}".format(region))
	plt.legend()
	plt.tight_layout()
	plt.savefig(outfile.replace('.csv','.pdf'),format='PDF')
	plt.close(fig)
Пример #5
0
gdfVM3 = gpd.overlay(gdfCN5, gdfVM2, how='intersection')
gdfVM3.plot()

# 高德地图三沙市的岛屿
file = "D:/temp/geojsonutf8/中华人民共和国/海南省/三沙市/460300.json"
gdfSS = gpd.read_file(file, encoding="utf-8")
gdfSS.plot()
# 用于协助选出岛屿,153个
import simplejson as json
with open(file, encoding='utf-8') as f:
    collection = json.load(f, encoding='utf-8')
# 转换为规范的MultiPolygon
ps = collection['features'][0]["geometry"]["coordinates"]
geos = []
for i in range(len(ps)):
    geos.append(Polygon(ps[i]))
geos = MultiPolygon(geos)
gdfSS2 = gpd.read_file(file, encoding="utf-8")
gdfSS2["geometry"] = [geos]
gdfSS2.plot()
# 转换为wgs84坐标
gdfSS3 = gdf2wgs(gdfSS2)
gdfSS3.plot()
# 替换原admin1中的岛屿数据
gdfIslands2 = gdfIslands.copy()
geos = gdfSS3["geometry"].to_list()[0]
gdfIslands2["geometry"] = [geos]
gdfIslands2.plot()
gdfCN1 = gdfCN.copy()
gdfCN1.drop(gdfCN1[gdfCN1.name == "Paracel Islands"].index, inplace=True)
gdfCN1 = pd.concat([gdfCN1, gdfIslands2], axis=0)