Erstellen Sie geschlossene Polygone aus Grenzpunkten

Ich habe eine Reihe von Längen- und Breitengradpunkten, die die Grenzen eines Gebiets definieren. Ich möchte ein Polygon basierend auf diesen Punkten erstellen und das Polygon auf einer Karte zeichnen und ausfüllen. Derzeit scheint mein Polygon aus vielen Patches zu bestehen, die alle Punkte verbinden, aber die Reihenfolge der Punkte ist nicht korrekt. Wenn ich versuche, das Polygon zu füllen, erhalte ich einen seltsam aussehenden Bereich (siehe Anhang).

Ich sortiere meine Längen- und Breitengrade (mypolyXY-Array) nach der Mitte des Polygons, aber ich vermute, dass dies nicht korrekt ist:

cent=(np.sum([p[0] for p in mypolyXY])/len(mypolyXY),np.sum([p[1] for p in mypolyXY])/len(mypolyXY))
# sort by polar angle
mypolyXY.sort(key=lambda p: math.atan2(p[1]-cent[1],p[0]-cent[0]))

Ich zeichne die Punktpositionen (schwarze Kreise) und meine Polygone (farbige Flecken) mit

scatter([p[0] for p in mypolyXY],[p[1] for p in mypolyXY],2)
p = Polygon(mypolyXY,facecolor=colors,edgecolor='none')
ax.add_artist(p)

Meine Frage ist: Wie kann ich mein Polygon basierend auf meiner Anordnung von Längen- und Breitengradpunkten schließen?

AKTUALISIEREN: Ich habe noch mehr getestet, wie man das Polygon zeichnet. Ich habe die Sortierroutine entfernt und nur die Daten in der Reihenfolge verwendet, in der sie in der Datei vorkommen. Dies scheint das Ergebnis zu verbessern, aber wie bei @tcaswell bereits erwähnt, unterbietet sich die Polygonform immer noch selbst (siehe neue Darstellung). Ich hoffe, dass es eine Routine für Pfade / Polygone geben kann, die mein Problem löst und alle Formen oder Pfade innerhalb der Grenzen des Polygons zusammenführt. Vorschläge sind sehr willkommen.

UPDATE 2:

Ich habe jetzt eine funktionierende Version meines Skripts, die auf Vorschlägen von @Rutger Kassies und Roland Smith basiert. Am Ende las ich das Shapefile mit org, was relativ gut funktionierte. Es funktionierte gut für die Standarddatei lmes_64.shp, aber als ich detailliertere LME-Dateien verwendete, bei denen jede LME aus mehreren Polygonen bestehen konnte, brach dieses Skript zusammen. Ich müsste einen Weg finden, die verschiedenen Polygone für identische LME-Namen zusammenzuführen, damit dies funktioniert. Ich hänge mein Skript an, mit dem ich gelandet bin, für den Fall, dass jemand es sich ansehen würde. Ich freue mich sehr über Kommentare, um dieses Skript zu verbessern oder allgemeiner zu gestalten. Dieses Skript erstellt die Polygone und extrahiert Daten innerhalb des Polygonbereichs, die ich aus einer netcdf-Datei gelesen habe. Das Raster der Eingabedatei beträgt -180 bis 180 und -90 bis 90.

import numpy as np
import math
from pylab import *
import matplotlib.patches as patches
import string, os, sys
import datetime, types
from netCDF4 import Dataset
import matplotlib.nxutils as nx
from mpl_toolkits.basemap import Basemap
import ogr
import matplotlib.path as mpath
import matplotlib.patches as patches


def getLMEpolygon(coordinatefile,mymap,index,first):

    ds = ogr.Open(coordinatefile)
    lyr = ds.GetLayer(0)
    numberOfPolygons=lyr.GetFeatureCount()

    if first is False:
        ft = lyr.GetFeature(index)
        print "Found polygon:",  ft.items()['LME_NAME']
        geom = ft.GetGeometryRef()

        codes = []
        all_x = []
        all_y = []
        all_XY= []

        if (geom.GetGeometryType() == ogr.wkbPolygon):
          for i in range(geom.GetGeometryCount()):

            r = geom.GetGeometryRef(i)
            x = [r.GetX(j) for j in range(r.GetPointCount())]
            y = [r.GetY(j) for j in range(r.GetPointCount())]

            codes += [mpath.Path.MOVETO] + (len(x)-1)*[mpath.Path.LINETO]
            all_x += x
            all_y += y
            all_XY +=mymap(x,y)


        if len(all_XY)==0:
            all_XY=None
            mypoly=None
        else:
            mypoly=np.empty((len(all_XY[:][0]),2))
            mypoly[:,0]=all_XY[:][0]
            mypoly[:,1]=all_XY[:][3]
    else:
        print "Will extract data for %s polygons"%(numberOfPolygons)
        mypoly=None
    first=False
    return mypoly, first, numberOfPolygons


def openCMIP5file(CMIP5name,myvar,mymap):
    if os.path.exists(CMIP5name):
        myfile=Dataset(CMIP5name)
        print "Opened CMIP5 file: %s"%(CMIP5name)
    else:
        print "Could not find CMIP5 input file %s : abort"%(CMIP5name)
        sys.exit()
    mydata=np.squeeze(myfile.variables[myvar][-1,:,:]) - 273.15
    lonCMIP5=np.squeeze(myfile.variables["lon"][:])
    latCMIP5=np.squeeze(myfile.variables["lat"][:])

    lons,lats=np.meshgrid(lonCMIP5,latCMIP5)

    lons=lons.flatten()
    lats=lats.flatten()
    mygrid=np.empty((len(lats),2))
    mymapgrid=np.empty((len(lats),2))

    for i in xrange(len(lats)):
        mygrid[i,0]=lons[i]
        mygrid[i,1]=lats[i]
        X,Y=mymap(lons[i],lats[i])
        mymapgrid[i,0]=X
        mymapgrid[i,1]=Y

    return mydata, mygrid, mymapgrid

def drawMap(NUM_COLORS):

    ax = plt.subplot(111)
    cm = plt.get_cmap('RdBu')
    ax.set_color_cycle([cm(1.*j/NUM_COLORS) for j in range(NUM_COLORS)])
    mymap = Basemap(resolution='l',projection='robin',lon_0=0)

    mymap.drawcountries()

    mymap.drawcoastlines()
    mymap.fillcontinents(color='grey',lake_color='white')
    mymap.drawparallels(np.arange(-90.,120.,30.))
    mymap.drawmeridians(np.arange(0.,360.,60.))
    mymap.drawmapboundary(fill_color='white')

    return ax, mymap, cm

"""Edit the correct names below:"""

LMEcoordinatefile='ShapefileBoundaries/lmes_64.shp'
CMIP5file='tos_Omon_CCSM4_rcp85_r1i1p1_200601-210012_regrid.nc'

mydebug=False
doPoints=False
first=True


"""initialize the map:"""
mymap=None
mypolyXY, first, numberOfPolygons = getLMEpolygon(LMEcoordinatefile, mymap, 0,first)
NUM_COLORS=numberOfPolygons
ax, mymap, cm = drawMap(NUM_COLORS)


"""Get the CMIP5 data together with the grid"""
SST,mygrid, mymapgrid = openCMIP5file(CMIP5file,"tos",mymap)

"""For each LME of interest create a polygon of coordinates defining the boundaries"""
for counter in xrange(numberOfPolygons-1):

    mypolyXY,first,numberOfPolygons = getLMEpolygon(LMEcoordinatefile, mymap,counter,first)

    if mypolyXY != None:
        """Find the indices inside the grid that are within the polygon"""
        insideBoolean = plt.mlab.inside_poly(np.c_[mymapgrid[:,0],mymapgrid[:,1]],np.c_[mypolyXY[:,0],mypolyXY[:,1]])
        SST=SST.flatten()
        SST=np.ma.masked_where(SST>50,SST)

        mymapgrid=np.c_[mymapgrid[:,0],mymapgrid[:,1]]
        myaverageSST=np.mean(SST[insideBoolean])

        mycolor=cm(myaverageSST/SST.max())
        scaled_z = (myaverageSST - SST.min()) / SST.ptp()
        colors = plt.cm.coolwarm(scaled_z)

        scatter([p[0] for p in mypolyXY],[p[1] for p in mypolyXY],2)

        p = Polygon(mypolyXY,facecolor=colors,edgecolor='none')
        ax.add_artist(p)

        if doPoints is True:

            for point in xrange(len(insideBoolean)):
                pointX=mymapgrid[insideBoolean[point],0]
                pointY=mymapgrid[insideBoolean[point],1]
                ax.scatter(pointX,pointY,8,color=colors)
                ax.hold(True)


if doPoints is True:
    colorbar()
print "Extracted average values for %s LMEs"%(numberOfPolygons)
plt.savefig('LMEs.png',dpi=300)
plt.show()

Endgültiges Bild angehängt. Vielen Dank für alle Hilfe.

 Prost, Trond

Antworten auf die Frage(3)

Ihre Antwort auf die Frage