matplotlib — are there actual PyPlot objects that interact with Basemap objects? - matplotlib-basemap

Looking at the Basemap docs, I can see how a Basemap object is instantiated and overlaid with content:
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
map = Basemap(projection='ortho',lat_0=45,lon_0=-100,resolution='l')
map.drawcoastlines(linewidth=0.25)
...
The object is named map and various Basemap methods act on it. But I can't understand how, later in the same code, PyPlot (imported as plt) behaves. There seems to be no distinct PyPlot object, and the calls to the PyPlot module never mention map:
# make up some data on a regular lat/lon grid.
nlats = 73; nlons = 145; delta = 2.*np.pi/(nlons-1)
lats = (0.5*np.pi-delta*np.indices((nlats,nlons))[0,:,:])
lons = (delta*np.indices((nlats,nlons))[1,:,:])
wave = 0.75*(np.sin(2.*lats)**8*np.cos(4.*lons))
mean = 0.5*np.cos(2.*lats)*((np.sin(2.*lats))**2 + 2.)
# compute native map projection coordinates of lat/lon grid.
x, y = map(lons*180./np.pi, lats*180./np.pi)
# contour data over the map.
cs = map.contour(x,y,wave+mean,15,linewidths=1.5)
plt.title('contour lines over filled continent background')
plt.show()
How and where does PyPlot interact with the map object?
Also, in the third line of code from the bottom, why is variable cs being assigned, since it isn't actually used elsewhere in the code? I see no difference in the output with cs = removed.

pyplot is just an interface to various matplotlib modules. For example, plt.plot() finds the current Axes object (let's call it ax) and the uses the ax.plot() method to do the drawing.
In general, operating on the Axes, or in this case Basemap objects directly is the greatly preferred style.

Related

Intersection of points and polygons using geopandas

I am using the Australian Bureau of Statistics data (ABS) to visualize meshblocks and boundaries of buffer data from a centre of location with certain radius.
I want to create the following plot:
intersection plot
So far, I am able to create a function which can give me a circle with certain radius depending on the initial coordinates (lon, lat) I have provided.
I have used the following function to plot the circle around the required location on the map:
import geopandas as gpd
import pandas as pd
import leaflet
from osgeo import gdal
import shapefile as shp
def func_radius_around_point(point_list,m_list,crs_from,crs_to):
points_df = pd.DataFrame(point_list).reset_index()
points_df = points_df.rename(columns={0:'geometry'})
points_gpd = gpd.GeoDataFrame(points_df,geometry='geometry',crs=crs_from)
for m in m_list:
buffered= points_gpd.to_crs(epsg=crs_to).buffer(m).to_crs(epsg=crs_from)
col_name = 'buffered_{m}'.format(m=m)
points_gpd[col_name] = buffered
return points_gpd
I have the data for mesh block and statistical area 1. All I want to create is the intersection of points and polygon. How do I create this intersection using geopandas?
With R, it seems so much easier using the simple features library. Is there a simple features package in geopandas that I have missed out on?

OSMnx finding the shortest path of a directed graph using networkx

In OSMnx the streets are directed in order to preserve one-way directionality and therefore, when I try to find the shortest path using Networkx I get NetworkXNoPath: No path to (osmid). How do I fix this issue? I need to find the shortest path in a network with one-way streets.
See code below:
import osmnx as ox
import networkx as nx
# define place
centreLat=40.771687
centreLon=-73.957233
# download osm data
G= ox.graph_from_point((centreLat,centreLon), distance=1000, network_type='drive',simplify = True)
# plot the graph
fig,ax = ox.plot_graph(G)
# Get origin x and y coordinates
orig_xy = 40.7647425, -73.9683181
# Get target x and y coordinates
target_xy =40.7804348, -73.9498809
# Find the node in the graph that is closest to the origin point (here, we want to get the node id)
orig_node = ox.get_nearest_node(G, orig_xy, method='euclidean')
# Find the node in the graph that is closest to the target point (here, we want to get the node id)
target_node = ox.get_nearest_node(G, target_xy, method='euclidean')
# Get shortest path
route = nx.shortest_path(G, source=orig_node, target=target_node, weight='length')
# Plot the shortest path
fig, ax = ox.plot_graph_route(G, route, origin_point=orig_xy, destination_point=target_xy)
This issue was fixed by creating the strongly connected components of the directed graph in order to make sure that every vertex is accessible from every other vertex.
G=ox.geo_utils.get_largest_component(G,strongly=True)

How do I get the "boundary" of a Delaunay triangulation?

Visually, it is clear to me that given a Delaunay triangulation, there are some points which form its "boundary". This boundary is different from a convex hull, since it is not minimal in the number of points, and it is not necessarily convex.
What is it called? Is there a way to get it from a scipy Delaunay triangulation?
(Note: I am not looking for an algorithm on how to determine this boundary, but rather a pre-baked scipy function. I already have an idea for how I can get the boundary of a Delaunay triangulation, but prefer to not re-invent the wheel.)
This is actually quite simple, there is no need for convex/concave hulls.
Assuming you have triangulated a closed surface, the key observation is to note that an edge of the triangulation belongs to the boundary if it's not shared by two different triangles.
From the scipy.spatial.Delaunay documentation, If P is a set of points and you have computed T = Delaunay(P), then T.neighbors equals -1 in it's kth coordinate if the edge opposite to the kth vertex belongs to the boundary.
Example code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Delaunay
# Create triangulation of a rectangle
x = np.linspace(0,1,9)
y = np.linspace(0,1,9)
X,Y = np.meshgrid(x,y)
P = np.array([X.flatten(),Y.flatten()]).T
T = Delaunay(P)
# Find edges at the boundary
boundary = set()
for i in range(len(T.neighbors)):
for k in range(3):
if (T.neighbors[i][k] == -1):
nk1,nk2 = (k+1)%3, (k+2)%3
boundary.add(T.simplices[i][nk1])
boundary.add(T.simplices[i][nk2])
# Plot result
plt.triplot(P[:,0], P[:,1], T.simplices)
plt.plot(P[:,0], P[:,1], 'o')
plt.plot(P[list(boundary),0], P[list(boundary),1], 'or')
plt.show()
I'm pretty sure this is not recently present in scipy, it would make no sense to place it somewhere else than among the scipy.spatial.Delaunay object methods, and list of the methods is pretty short and doesn't contain anything that specific.
The method find_simplex might help you find the convex hull (assuming this means the smallest convex superset), but the engagement of the circumscribed circle (if I understood well the Delaunay triangulation definition) seemms like a completely new kind of obstacle.
Assuming that the simplex is a word for a "side" of this "triangle" , you would need to find union of all such simplexes to find the convex hull, so for the boundary you don't want all simplexex, only some of them, and here my imagination ends.

Extract constrained polygon using OSMnx

I'm playing around with OSMnx package in order to solve the following task:
- there is a point X on the map defined by latitude and longitude
- we need to detect a polygon that contains that point X and is constrained by the neighboring roads
- so basically the point X is inside the polygon and the neighboring roads will be borders of that polygon.
So far I've managed only to plot the visualization of the graph on the map and find the closest edge/node to point X.
In the attached image I've highlighted the area I want to extract in red.
As you are trying to find a polygon containing your point, you first need to generate polygons out of multilinestring geometry. As you did not provide your data I am downloading a sample from OSM using OSMnx.
import osmnx as ox
import geopandas as gpd
import shapely
point = (40.742623, -73.977857)
streets_graph = ox.graph_from_point(point, distance=500, network_type='drive')
streets_graph = ox.project_graph(streets_graph)
I have reprojected it as it is way more convenient than working with degrees, especially if you want to measure anything.
You then have to convert OSMnx graph to geopandas GeoDataFrame.
streets = ox.save_load.graph_to_gdfs(streets_graph, nodes=False, edges=True,
node_geometry=False, fill_edge_geometry=True)
To get some point I can work with, I'll just use the one in the centre of this geodataframe.
point = streets.unary_union.centroid
This is what it looks like.
Next you need to get polygons of your blocks defined by streets, using shapely.ops.polygonize as I suggested in the comment above and store them as GeoSeries.
polygons = shapely.ops.polygonize(streets.geometry)
polygons = gpd.GeoSeries(polygons)
The only thing you have to do next is to find which polygon contains your point.
target = polygons.loc[polygons.contains(point)]
Plotting it again:
ax = target.plot()
gpd.GeoSeries([point]).plot(ax=ax, color='r')
If you want to know which streets are forming the boundary of this polygon, just intersect it with the original network. I am filtering for MultiLineString to exclude streets which intersects the polygon only in one point.
target_streets = streets.loc[streets.intersection(target.iloc[0]).type == 'MultiLineString']
This is how the result of that looks like.
ax = target_streets2.plot()
gpd.GeoSeries([point]).plot(ax=ax, color='r')
Hope it helps.

How to plot multiple (x,y) series on the same axes with Chaco?

I have several sets of (x,y) data that I'd like to plot as line plots on the same figure. I have no trouble with matplotlib doing this, but I cannot get the same results with Chaco. Code and output are shown below.
My matplotlib-based code looks like this:
for track in tracks:
xw = np.array(track['xw'])
yw = np.array(track['yw'])
plt.plot(xw, yw, 'b-')
if not plt.gca().yaxis_inverted():
plt.gca().invert_yaxis()
My Chaco-based code looks like this:
for track in tracks:
x = np.array(track['xw'])
y = np.array(track['yw'])
plot = create_line_plot((x,y), color='blue', width=1.0)
plot.origin = 'top left'
container.add(plot)
if track == tracks[0]:
add_default_grids(plot)
add_default_axes(plot)
My matplotlib-based output looks like this:
My chaco-based output looks like this:
The problem with my Chaco-based code above was that I was using an OverlayPlotContainer (container). Because of this, each plot (from create_line_plot) was being drawn with its own axes rather than each plot being drawn on the same set of axes. The following works:
pd = ArrayPlotData()
plot = Plot(pd)
for ii, track in enumerate(tracks):
x = np.array(track['xw'])
y = np.array(track['yw'])
x_key = 'x'+str(ii)
y_key = 'y'+str(ii)
pd.set_data(x_key, x)
pd.set_data(y_key, y)
plot.plot((x_key, y_key), color='blue', origin='top left')
Chaco and Matplotlib are not really trying to address the same types of problems. Matplotlib is better for bringing up a quick plot in a script and is very easy to use. Chaco is a plotting framework that allows:
a stronger architecture for dealing with larger datasets more smoothly
a frameworks that makes it easy to build a GUI around the plot (Traits)
the creation of custom interactive tools on top of plots
Leveraging that framework however requires more code, and the recommeded way to build plots in Chaco is to use its Object Oriented syntax. The simplest but realistic Chaco plot would be something like this. It requires an ArrayPlotData to hold the data and a Plot object to create a plotting area and hold different ways to render that data.
You want to have many line plots instead of just one. You can simply add a for loop inside the __init__ method to add every relevant numpy array inside the ArrayPlotData and for each pair of arrays, to call the plot method of the Plot object (but only 1 Plot object is needed). Something similar is done a little further down in the page.
Good luck,