2012-12-10 8 views
9

Ich zeichne eine Karte mit Grundkarte von Matplotlib. Die Daten sind auf der ganzen Welt verteilt, aber ich möchte nur alle Daten auf dem Kontinent behalten und diese auf den Ozean fallen lassen. Gibt es eine Möglichkeit, die Daten zu filtern, oder gibt es eine Möglichkeit, den Ozean erneut zu zeichnen, um die Daten zu erfassen?Plot nur auf Kontinent in Matplotlib

Antwort

6

Es gibt Verfahren, bei matplotlib.basemap: is_land(xpt, ypt)

Es gibt True wenn die gegebenen x, y Punkt (in Projektionskoordinaten) über Land ist, False anderweitig. Die Definition von Land basiert auf den GSHHS-Küstenlinienpolygonen, die der Klasseninstanz zugeordnet sind. Punkte über Seen innerhalb von Landregionen werden nicht als Landpunkte gezählt.

Weitere Informationen finden Sie unter here.

+0

Danke das ist, was ich gesucht habe. Aber wenn ich 'is_land' benutze, stoße ich auf ein Problem. Es ist [hier] (http://stackoverflow.com/q/13800056/1819734). – ZYX

6

is_land() werden alle Polygone durchlaufen, um zu prüfen, ob es sich um Land handelt oder nicht. Für große Datenmengen ist es sehr langsam. Sie können points_inside_poly() von Matplotlib verwenden, um ein Array von Punkten schnell zu überprüfen. Hier ist der Code. Es überprüft nicht lakepolygons, wenn Sie Punkte in Seen entfernen möchten, können Sie Ihr Selbst hinzufügen.

Es dauerte 2,7 Sekunden, um 100000 Punkte auf meinem PC zu überprüfen. Wenn Sie mehr Geschwindigkeit wünschen, können Sie die Polygone in eine Bitmap konvertieren, aber es ist ein wenig schwierig, dies zu tun. Bitte sagen Sie mir, ob der folgende Code für Ihr Dataset nicht schnell genug ist.

from mpl_toolkits.basemap import Basemap 
import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.nxutils as nx 

def points_in_polys(points, polys): 
    result = [] 
    for poly in polys: 
     mask = nx.points_inside_poly(points, poly) 
     result.extend(points[mask]) 
     points = points[~mask] 
    return np.array(result) 

points = np.random.randint(0, 90, size=(100000, 2)) 
m = Basemap(projection='moll',lon_0=0,resolution='c') 
m.drawcoastlines() 
m.fillcontinents(color='coral',lake_color='aqua') 
x, y = m(points[:,0], points[:,1]) 
loc = np.c_[x, y] 
polys = [p.boundary for p in m.landpolygons] 
land_loc = points_in_polys(loc, polys) 
m.plot(land_loc[:, 0], land_loc[:, 1],'ro') 
plt.show() 
+0

Ich denke 'points_inside_poly' (und wenn ich mich an die ganzen 'nxutils' erinnere) wird in MPL 1 abgeschrieben.2, aber es funktioniert auch mit der neuen Methode (kann mich nicht erinnern, was die neue Methode im Moment ist, aber die Abschreibung Warnung wird es sagen) – bmu

+0

https://matplotlib.org/1.2.1/api/path_api.html # matplotlib.path.Path.contains_points – Baz

4

Die Antwort des Hyry wird auf neue Versionen von matplotlib nicht (nxutils ist veraltet). Ich habe eine neue Version gemacht, die funktionieren:

from mpl_toolkits.basemap import Basemap 
import matplotlib.pyplot as plt 
from matplotlib.path import Path 
import numpy as np 

map = Basemap(projection='cyl', resolution='c') 

lons = [0., 0., 16., 76.] 
lats = [0., 41., 19., 51.] 

x, y = map(lons, lats) 

locations = np.c_[x, y] 

polygons = [Path(p.boundary) for p in map.landpolygons] 

result = np.zeros(len(locations), dtype=bool) 

for polygon in polygons: 

    result += np.array(polygon.contains_points(locations)) 

print result 
2

Der einfachste Weg basemap die maskoceans zu verwenden ist.

Nach meshgrid und Interpolation:

from scipy.interpolate import griddata as gd 
from mpl_toolkits.basemap import Basemap, cm, maskoceans 
xi, yi = np.meshgrid(xi, yi) 
zi = gd((mlon, mlat), 
      scores, 
      (xi, yi), 
      method=grid_interpolation_method) 
#mask points on ocean 
data = maskoceans(xi, yi, zi) 
con = m.contourf(xi, yi, data, cmap=cm.GMT_red2green) 
#note instead of zi we have data now. 
1

ich this question beantworten, als mir gesagt wurde, dass es besser wäre, meine Antwort hier zu posten. Im Wesentlichen extrahiert meine Lösung die Polygone, die zum Zeichnen der Küstenlinie der Instanz verwendet werden, und kombiniert diese Polygone mit dem Umriss der Karte, um eine matplotlib.PathPatch zu erzeugen, die die Meeresgebiete der Karte überlagert.

Dies ist besonders nützlich, wenn die Daten grob sind und eine Interpolation der Daten nicht erwünscht ist. In diesem Fall erzeugt die Verwendung von maskoceans einen sehr körnigen Umriss der Küstenlinien, der nicht sehr gut aussieht.

Hier ist das gleiche Beispiel, das ich als Antwort auf die andere Frage gestellt:

from matplotlib import pyplot as plt 
from mpl_toolkits import basemap as bm 
from matplotlib import colors 
import numpy as np 
import numpy.ma as ma 
from matplotlib.patches import Path, PathPatch 

fig, ax = plt.subplots() 

lon_0 = 319 
lat_0 = 72 

##some fake data 
lons = np.linspace(lon_0-60,lon_0+60,10) 
lats = np.linspace(lat_0-15,lat_0+15,5) 
lon, lat = np.meshgrid(lons,lats) 
TOPO = np.sin(np.pi*lon/180)*np.exp(lat/90) 

m = bm.Basemap(resolution='i',projection='laea', width=1500000, height=2900000, lat_ts=60, lat_0=lat_0, lon_0=lon_0, ax = ax) 
m.drawcoastlines(linewidth=0.5) 

x,y = m(lon,lat) 
pcol = ax.pcolormesh(x,y,TOPO) 

##getting the limits of the map: 
x0,x1 = ax.get_xlim() 
y0,y1 = ax.get_ylim() 
map_edges = np.array([[x0,y0],[x1,y0],[x1,y1],[x0,y1]]) 

##getting all polygons used to draw the coastlines of the map 
polys = [p.boundary for p in m.landpolygons] 

##combining with map edges 
polys = [map_edges]+polys[:] 

##creating a PathPatch 
codes = [ 
    [Path.MOVETO] + [Path.LINETO for p in p[1:]] 
    for p in polys 
] 
polys_lin = [v for p in polys for v in p] 
codes_lin = [c for cs in codes for c in cs] 
path = Path(polys_lin, codes_lin) 
patch = PathPatch(path,facecolor='white', lw=0) 

##masking the data: 
ax.add_patch(patch) 

plt.show() 

Daraus ergibt sich die folgende Handlung:

enter image description here

Hoffe, das ist hilfreich für jemand :)