To create a Voronoi polygon with geovoronoi lib i use:
polyShapes, puntos = voronoi_regions_from_coords(coords, milagroShape)
coords is a geoDataFrame object that it contains map´s locations and milagroShape is a polygon.shp. Now, to plot the Voronoi use the code:
fig, ax = subplot_for_map(figsize=[14, 8])
plot_voronoi_polys_with_points_in_area(ax, milagroShape, polyShapes, coords, puntos)
ax.set_title('Diagrama de Voronoi')
plt.tight_layout()
plt.show()
Now it works, the graph is showed on screen, but it´s only a mathplotlib plot.
I guess that I have to convert it into a geodataframe object (to that, I use geopandas library).
This is the map where I need to put the Voronoi graph:
Only the polygon of the city´s area is set, but I want to set the Voronoi too.
To add the city´s area I used the code below:
for _, r in milagro.iterrows(): #milagro is a geodataframe object
#sim_geo = gpd.GeoSeries(r['geometry'])
sim_geo = gpd.GeoSeries(r['geometry']).simplify(tolerance=0.0001)
geo_j = sim_geo.to_json()
geo_j = folium.GeoJson(data=geo_j,
style_function=lambda x: {'fillColor': 'orange'})
#folium.Popup(r['Name']).add_to(geo_j)
geo_j.add_to(mapaMilagro) #mapaMilagro is a folium map object
Libraries that i use for my proyect are:
import folium #map library
import pandas as pd #Data Frame
import matplotlib.pyplot as plt #to plot graphs
import condacolab #To install some libraries
import geopandas as gpd #Geo Data Frame library
from shapely.ops import cascaded_union #I don´t know what is this xd
from geovoronoi.plotting import subplot_for_map, plot_voronoi_polys_with_points_in_area
from geovoronoi import voronoi_regions_from_coords, points_to_coords
polyShapes, puntos = voronoi_regions_from_coords(coords, milagroShape)
polyShapes is a dict where the keys are meaningless (?) numbers and the values are shapely polygons. You can load those into a new gpd dataframe.
Related
there seems to be an issue with my code. My goal is to plot a map that represents an outcome (population) accross the regions of Benin.
import pandas as pd
import matplotlib as mpl
database_path = "datafinalproject.csv"
database = pd.read_csv(database_path)
#Creating a geodataframe
points = gpd.points_from_xy(database["longitude"], database["latitude"], crs="EPSG:4326")
map = gpd.GeoDataFrame (database, geometry=points)
I get this message when I type map.plot and I when I type map.plot(column='population'), I get an empty map.
Can you help me solve this problem?
database.head() gives :
map.plot() will work in a Jupyter notebook but not in a normal Python environment.
You should import matplotlib.pyplot and add plt.show() at the end of your code:
import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt
database_path = "datafinalproject.csv"
database = pd.read_csv(database_path)
#Creating a geodataframe
points = gpd.points_from_xy(database["longitude"], database["latitude"], crs="EPSG:4326")
map = gpd.GeoDataFrame (database, geometry=points)
map.plot()
plt.show()
I have a dataframe that contains thousands of points with geolocation (longitude, latitude) for Washington D.C. The following is a snippet of it:
import pandas as pd
df = pd.DataFrame({'lat': [ 38.897221,38.888100,38.915390,38.895100,38.895100,38.901005,38.960491,38.996342,38.915310,38.936820], 'lng': [-77.031048,-76.898480,-77.021380,-77.036700,-77.036700 ,-76.990784,-76.862907,-77.028131,-77.010403,-77.184930]})
If you plot the points in the map you can see that some of them are clearly within some buildings:
import folium
wash_map = folium.Map(location=[38.8977, -77.0365], zoom_start=10)
for index,location_info in df.iterrows():
folium.CircleMarker(
location=[location_info["lat"], location_info["lng"]], radius=5,
fill=True, fill_color='red',).add_to(wash_map)
wash_map.save('example_stack.html')
import webbrowser
import os
webbrowser.open('file://'+os.path.realpath('example_stack.html'), new=2)
My goal is to exclude all the points that are within buildings. For that, I first download bounding boxes for the city buildings and then try to exclude points within those polygons as follows:
import osmnx as ox
#brew install spatialindex this solves problems in mac
%matplotlib inline
ox.config(log_console=True)
ox.__version__
tags = {"building": True}
gdf = ox.geometries.geometries_from_point([38.8977, -77.0365], tags, dist=1000)
gdf.shape
For computational simplicity I have requested the shapes of all buildings around the White house with a radius of 1 km. On my own code I have tried with bigger radiuses to make sure all the buildings are included.
In order to exclude points within the polygons I developed the following function (which includes the shape obtention):
def buildings(df,center_point,dist):
import osmnx as ox
#brew install spatialindex this solves problems in mac
%matplotlib inline
ox.config(log_console=True)
ox.__version__
tags = {"building": True}
gdf = ox.geometries.geometries_from_point(center_point, tags,dist)
from shapely.geometry import Point,Polygon
# Next step is to put our coordinates in the correct shapely format: remember to run the map funciton before
#df['within_building']=[]
for point in range(len(df)):
if gdf.geometry.contains(Point(df.lat[point],df.lng[point])).all()==False:
df['within_building']=False
else :
df['within_building']=True
buildings(df,[38.8977, -77.0365],1000)
df['within_building'].all()==False
The function always returns that points are outside building shapes although you can clearly see in the map that some of them are within. I don't know how to plot the shapes over my map so I am not sure if my polygons are correct but for the coordinates they appear to be so. Any ideas?
The example points you provided don't seem to fall within those buildings' footprints. I don't know what your points' coordinate reference system is, so I guessed EPSG4326. But to answer your question, here's how you would exclude them, resulting in gdf_points_not_in_bldgs:
import geopandas as gpd
import matplotlib.pyplot as plt
import osmnx as ox
import pandas as pd
# the coordinates you provided
df = pd.DataFrame({'lat': [38.897221,38.888100,38.915390,38.895100,38.895100,38.901005,38.960491,38.996342,38.915310,38.936820],
'lng': [-77.031048,-76.898480,-77.021380,-77.036700,-77.036700 ,-76.990784,-76.862907,-77.028131,-77.010403,-77.184930]})
# create GeoDataFrame of point geometries
geom = gpd.points_from_xy(df['lng'], df['lat'])
gdf_points = gpd.GeoDataFrame(geometry=geom, crs='epsg:4326')
# get building footprints
tags = {"building": True}
gdf_bldgs = ox.geometries_from_point([38.8977, -77.0365], tags, dist=1000)
gdf_bldgs.shape
# get all points that are not within a building footprint
mask = gdf_points.within(gdf_bldgs.unary_union)
gdf_points_not_in_bldgs = gdf_points[~mask]
print(gdf_points_not_in_bldgs.shape) # (10, 1)
# plot buildings and points
ax = gdf_bldgs.plot()
ax = gdf_points.plot(ax=ax, c='r')
plt.show()
# zoom in to see better
ax = gdf_bldgs.plot()
ax = gdf_points.plot(ax=ax, c='r')
ax.set_xlim(-77.04, -77.03)
ax.set_ylim(38.89, 38.90)
plt.show()
I am trying to set a different color for map objects of a concatenated set of geodataframes (instead of a single color) using GEOPANDAS PYTHON.
I've tried conventional ways to set facecolor and cmap however it did not work for concatenated geodataframes.
I want to get different color shapes for gdf and boundaries (red and blue for example) instead of a single color which is what I'm currently getting.
here is the code:
import pandas as pd
import geopandas as gpd
from geopandas import GeoDataFrame
import matplotlib.pyplot as plt
import pandas
from shapely import wkt
#Converting an excel file into a geodataframe
Shape=pd.read_excel('C:/Users/user/OneDrive/documents/Excel .xlsx')
print(Shape)
Shape['geometry'] = Shape['geometry'].apply(wkt.loads)
gdf = gpd.GeoDataFrame(Shape, geometry='geometry')
gdf.plot()
#reading another geodataframe
Boundaries=gpd.read_file('C:/Users/user/Desktop/Boundaries/eez_v10.shp')
#concatenating Boundaries and gdfgeodataframes
map=pd.concat([gdf,Boundaries], sort=False)
ax=map.plot(figsize=(20,20))
plt.xlim([47,60])
plt.ylim([22,32])
plt.show()
You don't need to do concat, just plot both df to the same axis.
gdf = gpd.GeoDataFrame(Shape, geometry='geometry')
Boundaries=gpd.read_file('C:/Users/user/Desktop/Boundaries/eez_v10.shp')
ax = gdf.plot(color='blue')
Boundaries.plot(ax=ax, color='red')
I'm trying to plot data around the Antarctica while masking the continent. While I'm using basemap and it has an option to easily mask continents using map.fillcontinents(), the continent considered by basemap includes the ice shelves, which I do not want to mask.
I tried using geopandas from a code I found on the Internet. This works, except the coastline produces an undesired line in what I assume is the beginning/end of the polygon for the Antarctica:
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
import geopandas as gpd
import shapely
from descartes import PolygonPatch
lats = np.arange(-90,-59,1)
lons = np.arange(0,361,1)
X, Y = np.meshgrid(lons, lats)
data = np.random.rand(len(lats),len(lons))
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
fig=plt.figure(dpi=150)
ax = fig.add_subplot(111)
m = Basemap(projection='spstere',boundinglat=-60,lon_0=180,resolution='i',round=True)
xi, yi = m(X,Y)
cf = m.contourf(xi,yi,data)
patches = []
selection = world[world.name == 'Antarctica']
for poly in selection.geometry:
if poly.geom_type == 'Polygon':
mpoly = shapely.ops.transform(m, poly)
patches.append(PolygonPatch(mpoly))
elif poly.geom_type == 'MultiPolygon':
for subpoly in poly:
mpoly = shapely.ops.transform(m, poly)
patches.append(PolygonPatch(mpoly))
else:
print(poly, 'blah')
ax.add_collection(PatchCollection(patches, match_original=True,color='w',edgecolor='k'))
The same line appears when I try to use other shapefiles, such as the land one that is available to download for free from Natural Earth Data. So I edited this shapefile in QGIS to remove the borders of the Antarctica. The problem now is that I don't know how to mask everything that's inside the shapefile (and couldn't find how to do it either). I also tried combining the previous code with geopandas by setting the linewidth=0, and adding on top the shapefile I created. The problem is that they are not exactly the same:
Any suggestion on how to mask using a shapefile, or with geopandas but without the line?
Edit: Using Thomas Khün's previous answer with my edited shapefile produces a well masked Antarctica/continents, but the coastline goes outside the round edges of the map:
I uploaded here the edited shapefile I used, but it's the Natural Earth Data 50m land shapefile without the line.
Here an example of how to achieve what you want. I basically followed the Basemap example how to deal with shapefiles and added a bit of shapely magic to restrict the outlines to the map boundaries. Note that I first tried to extract the map outline from ax.patches, but that somehow didn't work, so I defined a circle which has a radius of boundinglat and transformed it using the Basemap coordinate transformation functionality.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
import shapely
from shapely.geometry import Polygon as sPolygon
boundinglat = -40
lats = np.arange(-90,boundinglat+1,1)
lons = np.arange(0,361,1)
X, Y = np.meshgrid(lons, lats)
data = np.random.rand(len(lats),len(lons))
fig, ax = plt.subplots(nrows=1, ncols=1, dpi=150)
m = Basemap(
ax = ax,
projection='spstere',boundinglat=boundinglat,lon_0=180,
resolution='i',round=True
)
xi, yi = m(X,Y)
cf = m.contourf(xi,yi,data)
#adjust the path to the shapefile here:
result = m.readshapefile(
'shapefiles/AntarcticaWGS84_contorno', 'antarctica',
zorder = 10, color = 'k', drawbounds = False)
#defining the outline of the map as shapely Polygon:
rim = [np.linspace(0,360,100),np.ones(100)*boundinglat,]
outline = sPolygon(np.asarray(m(rim[0],rim[1])).T)
#following Basemap tutorial for shapefiles
patches = []
for info, shape in zip(m.antarctica_info, m.antarctica):
#instead of a matplotlib Polygon, create first a shapely Polygon
poly = sPolygon(shape)
#check if the Polygon, or parts of it are inside the map:
if poly.intersects(outline):
#if yes, cut and insert
intersect = poly.intersection(outline)
verts = np.array(intersect.exterior.coords.xy)
patches.append(Polygon(verts.T, True))
ax.add_collection(PatchCollection(
patches, facecolor= 'w', edgecolor='k', linewidths=1., zorder=2
))
plt.show()
The result looks like this:
Hope this helps.
For anyone still trying to figure out a simple way to mask a grid from a shapefile, here is a gallery example from the python package Antarctic-Plots which makes this simple.
from antarctic_plots import maps, fetch, utils
import pyogrio
# fetch a grid and shapefile
grid = fetch.bedmachine(layer='surface')
shape = fetch.groundingline()
# subset the grounding line from the coastline
gdf = pyogrio.read_dataframe(shape)
groundingline = gdf[gdf.Id_text == "Grounded ice or land"]
# plot the grid
fig = maps.plot_grd(grid)
# plot the shapefile
fig.plot(groundingline, pen='1p,red')
fig.show()
# mask the inside region
masked_inside = utils.mask_from_shp(
shapefile=groundingline, xr_grid=grid, masked=True)
masked_inside.plot()
# mask the outside region
masked_outside = utils.mask_from_shp(
shapefile=groundingline, xr_grid=grid, masked=True, invert=False)
masked_outside.plot()
I am trying to create a choropleth map using basemap and pandas, to plot the level of prescription rates across CCGs (NHS Clinical Commissioning Groups). I am downloading the shapefile from http://geoportal.statistics.gov.uk/datasets/1bc1e6a77cdd4b3a9a0458b64af1ade4_1 which provides the CCG area boundaries.. However the initial problem I am encountering is to do with the reading of the shapefile.
The following error is arising:
raise IOError('cannot locate %s.shp'%shapefile)
This is my code so far...
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm
from mpl_toolkits.basemap import Basemap
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
from matplotlib.colors import Normalize
fig, ax = plt.subplots(figsize=(10,20))
m = Basemap(resolution='c', # c, l, i, h, f or None
projection='merc',
lat_0=54.5, lon_0=-4.36,
llcrnrlon=-6., llcrnrlat= 49.5, urcrnrlon=2., urcrnrlat=55.2)
m.drawmapboundary(fill_color='#46bcec')
m.fillcontinents(color='#f2f2f2',lake_color='#46bcec')
m.drawcoastlines()
m.readshapefile('/Volumes/Clinical_Commissioning_Groups_April_2016_Full_Extent_Boundaries_in_England', 'areas', drawbounds =True)
m.areas
df_poly = pd.DataFrame({'shapes': [Polygon(np.array(shape), True) for shape in m.areas],'area': [area['ccg16cd'] for area in m.areas_info]})
rates=pd.read_csv('Volumes/TOSHIBA EXT/Basemap rates.csv', delimiter=",", usecols=[0,6])
rates.columns = ['ccg16cd','MEAN YEARLY PRESCRIPTION RATE']
frame = df_poly.merge(rates, on='ccg16cd', how='left')
cmap = plt.get_cmap('Oranges')
pc = PatchCollection(df_poly.shapes, zorder=2)
norm = Normalize()
pc.set_facecolor(cmap(norm(df_poly['count'].fillna(0).values)))
ax.add_collection(pc)
mapper = matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap)
mapper.set_array(df_poly['count'])
plt.colorbar(mapper, shrink=0.4)
m
Would appreciate any pointers as to how I can achieve this choropleth map - starting with what is going wrong in reading the shapefile.
Try using geopandas to read in the shapefile:
import geopandas as gp
shape_file = gp.read_file('FileName.shp')
Also, check that the path to the shapefile is correct.