2013-04-12 23 views
6

Sto provando a tracciare poligoni pieni di paesi sulla mappa del mondo con matplotlib in python.shapefile e matplotlib: raccolta poligonale trama delle coordinate dello shapefile

Ho uno shapefile con le coordinate del confine di ogni paese. Ora, voglio convertire queste coordinate (per ogni paese) in un poligono con matplotlib. Senza usare Basemap. Sfortunatamente, le parti si incrociano o si sovrappongono. C'è un workarund, magari usando la distanza da un punto all'altro ... o riordinandoli? enter image description here

+0

Come hai creato questa immagine? Io uso sempre i percorsi per questo, come in questo esempio: http://matplotlib.org/examples/api/donut_demo.html –

risposta

11

Ha! Ho scoperto, come ... ho completamente trascurato, le informazioni di sf.shapes [i] .parts! Poi si tratta di:

# -- import -- 
import shapefile 
import matplotlib.pyplot as plt 
import matplotlib.patches as patches 
from matplotlib.patches import Polygon 
from matplotlib.collections import PatchCollection 
# -- input -- 
sf = shapefile.Reader("./shapefiles/world_countries_boundary_file_world_2002") 
recs = sf.records() 
shapes = sf.shapes() 
Nshp = len(shapes) 
cns  = [] 
for nshp in xrange(Nshp): 
    cns.append(recs[nshp][1]) 
cns = array(cns) 
cm = get_cmap('Dark2') 
cccol = cm(1.*arange(Nshp)/Nshp) 
# -- plot -- 
fig  = plt.figure() 
ax  = fig.add_subplot(111) 
for nshp in xrange(Nshp): 
    ptchs = [] 
    pts  = array(shapes[nshp].points) 
    prt  = shapes[nshp].parts 
    par  = list(prt) + [pts.shape[0]] 
    for pij in xrange(len(prt)): 
    ptchs.append(Polygon(pts[par[pij]:par[pij+1]])) 
    ax.add_collection(PatchCollection(ptchs,facecolor=cccol[nshp,:],edgecolor='k', linewidths=.1)) 
ax.set_xlim(-180,+180) 
ax.set_ylim(-90,90) 
fig.savefig('test.png') 

allora sarà simile a questa: enter image description here

+0

Molto bello. Se eseguo questo script, vedo che ignora gli anelli interni nei poligoni, non sempre un problema, ma qualcosa di cui essere consapevole. –

+0

Dove definisci la funzione 'get_cmap'? –

+0

Puoi modificare la risposta in base alla risposta di @Elendil riguardo a 'cm = matplotlib.cm.get_cmap ('Dark2')' –

3

Ecco un altro pezzo di codice che ho usato per tracciare shapefile poligonali. Esso utilizza GDAL/OGR per leggere shapefile e trame ciambella correttamente poligoni di forma:

from osgeo import ogr 
import numpy as np 
import matplotlib.path as mpath 
import matplotlib.patches as mpatches 
import matplotlib.pyplot as plt 

# Extract first layer of features from shapefile using OGR 
ds = ogr.Open('world_countries_boundary_file_world_2002.shp') 
nlay = ds.GetLayerCount() 
lyr = ds.GetLayer(0) 

# Get extent and calculate buffer size 
ext = lyr.GetExtent() 
xoff = (ext[1]-ext[0])/50 
yoff = (ext[3]-ext[2])/50 

# Prepare figure 
fig = plt.figure() 
ax = fig.add_subplot(111) 
ax.set_xlim(ext[0]-xoff,ext[1]+xoff) 
ax.set_ylim(ext[2]-yoff,ext[3]+yoff) 

paths = [] 
lyr.ResetReading() 

# Read all features in layer and store as paths 
for feat in lyr: 
    geom = feat.geometry() 
    codes = [] 
    all_x = [] 
    all_y = [] 
    for i in range(geom.GetGeometryCount()): 
     # Read ring geometry and create path 
     r = geom.GetGeometryRef(i) 
     x = [r.GetX(j) for j in range(r.GetPointCount())] 
     y = [r.GetY(j) for j in range(r.GetPointCount())] 
     # skip boundary between individual rings 
     codes += [mpath.Path.MOVETO] + \ 
        (len(x)-1)*[mpath.Path.LINETO] 
     all_x += x 
     all_y += y 
    path = mpath.Path(np.column_stack((all_x,all_y)), codes) 
    paths.append(path) 

# Add paths as patches to axes 
for path in paths: 
    patch = mpatches.PathPatch(path, \ 
      facecolor='blue', edgecolor='black') 
    ax.add_patch(patch) 

ax.set_aspect(1.0) 
plt.show() 
1
from fiona import collection 
import matplotlib.pyplot as plt 
from descartes import PolygonPatch 
from matplotlib.collections import PatchCollection 
from itertools import imap 
from matplotlib.cm import get_cmap 

cm = get_cmap('Dark2') 

figure, axes = plt.subplots(1) 

source_path = "./shapefiles/world_countries_boundary_file_world_2002" 

with collection(source_path, 'r') as source: 
    patches = imap(PolygonPatch, (record['geometry'] for record in source) 

axes.add_collection(PatchCollection (patches, cmap=cm, linewidths=0.1)) 

axes.set_xlim(-180,+180) 
axes.set_ylim(-90,90) 

plt.show() 

Nota questo presuppone poligoni, multipoligoni possono essere le maniglie in modo simile con

map(PolygonPatch, MultiPolygon(record['geometry'])) 
1

Riguardo al @hannesk ' s risposta, è necessario aggiungere le seguenti importazioni: from numpy import array e import matplotlib e sostituire la riga cm = get_cmap('Dark2') per cm = matplotlib.cm.get_cmap('Dark2')

(Non sono così famoso per aggiungere un commento al post notato.)

+0

Ho capito perché l'hai fatto ma non l'avrei fatto. –

+0

Come sembra capire, questo sarebbe più appropriato come commento. Per criticare o richiedere chiarimenti da un autore, lascia un commento sotto il loro post - puoi sempre commentare i tuoi post, e una volta che hai [reputazione] sufficiente (http://stackoverflow.com/help/whats-reputation) essere in grado di [commentare qualsiasi post] (http://stackoverflow.com/help/privileges/comment). – Makyen

+0

La prossima volta che ho lasciato l'errore nel post senza dire niente altro ragazzo lo correggerà in futuro se lo trovassero! Volevo solo aiutare come posso ma non posso farlo come Stack si aspetta scrivendo un commento ... E grazie al tuo voto non avrò mai il diritto di postare commenti :-) – Elendil

Problemi correlati