'Polygon' object is not iterable- iPython Cookbook - python

I am learning visualization of data in python using Cartopy
I have this code for plotting Africa's population and GDP.
def choropleth(ax, attr, cmap_name):
# We need to normalize the values before we can
# use the colormap.
values = [c.attributes[attr] for c in africa]
norm = Normalize(
vmin=min(values), vmax=max(values))
cmap = plt.cm.get_cmap(cmap_name)
for c in africa:
v = c.attributes[attr]
sp = ShapelyFeature(c.geometry, crs,
edgecolor='k',
facecolor=cmap(norm(v)))
ax.add_feature(sp)
fig, (ax1, ax2) = plt.subplots(
1, 2, figsize=(10, 16),
subplot_kw=dict(projection=crs))
draw_africa(ax1)
choropleth(ax1, 'POP_EST', 'Reds')
ax1.set_title('Population')
draw_africa(ax2)
choropleth(ax2, 'GDP_MD_EST', 'Blues')
ax2.set_title('GDP')
And the expected output should be-
But I am getting an error as such -
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-41-b443c58ecbd5> in <module>
3 subplot_kw=dict(projection=crs))
4 draw_africa(ax1)
----> 5 choropleth(ax1, 'POP_EST', 'Reds')
6 ax1.set_title('Population')
7
<ipython-input-40-161126226479> in choropleth(ax, attr, cmap_name)
8 for c in africa:
9 v = c.attributes[attr]
---> 10 sp = ShapelyFeature(c.geometry, crs,
11 edgecolor='k',
12 facecolor=cmap(norm(v)))
~/anaconda3/lib/python3.8/site-packages/cartopy/feature/__init__.py in __init__(self, geometries, crs, **kwargs)
219 """
220 super(ShapelyFeature, self).__init__(crs, **kwargs)
--> 221 self._geoms = tuple(geometries)
222
223 def geometries(self):
TypeError: 'Polygon' object is not iterable
I tried searching for this issue on github but no to avail. Can anyone please help me out how can I correct this ?
Here is the site for reference .

The issue is that the code tries to pass a shapely Polygon to a function that expects MultiPolygon. The elegant solution by swatchai here https://stackoverflow.com/a/63812490/13208790 is to catch Polygons and put them in a list so they can be treated as MultiPolygons.
Here's the code adapted to your case:
for i, c in enumerate(africa):
v = c.attributes[attr]
print(i)
# swatchai's Polygon catch logic
if c.geometry.geom_type=='MultiPolygon':
# this is a list of geometries
sp = ShapelyFeature(c.geometry, crs,
edgecolor='k',
facecolor=cmap(norm(v)))
elif c.geometry.geom_type=='Polygon':
# this is a single geometry
sp = ShapelyFeature([c.geometry], crs,
edgecolor='k',
facecolor=cmap(norm(v)))
else:
pass #do not plot the geometry

Related

Add interactive Folium Background to osmnx maps

I'm using osmnx map plots to find the shortest path and the 3 shortest paths between 2 points as in the below code:
location = (18.5204,73.8567)
mode = "drive"
ox.config(log_console=True, use_cache=True)
G = ox.graph_from_point(location, dist=2000, simplify=True, network_type=mode)
nodes_proj, edges_proj = ox.graph_to_gdfs(G, nodes=True, edges=True)
ox.plot_graph(G,node_color='r')
origin_point = (18.515802, 73.846754)
destination_point =(18.519423, 73.852966)
origin_node = ox.distance.nearest_nodes(G, origin_point[1], origin_point[0])
print('origin_node',origin_node)
destination_node = ox.distance.nearest_nodes(G, destination_point[1], destination_point[0])
print('destination_node',destination_node)
bgcolor = "#061529"
route = ox.distance.shortest_path(G, origin_node,destination_node)
route
bbox = ox.utils_geo.bbox_from_point(point=(18.515802, 73.846754), dist=700)
fig, ax = ox.plot_graph_route(G, route, bbox = bbox, route_linewidth=6, node_size=0, bgcolor=bgcolor,dpi = 300)
routes = ox.k_shortest_paths(G, origin_node, destination_node, k=3, weight='length')
bbox = ox.utils_geo.bbox_from_point(point=(18.515802, 73.846754), dist=700)
fig, ax = ox.plot_graph_routes(G, list(routes), bbox = bbox, route_colors=['r','b','g'], route_linewidth=2, node_size=0, bgcolor=bgcolor,dpi = 300)
The above code runs fine. However the background is black and very basic. I want the background to be interactive colored map, something like folium:
I tried this for the shortest path using ox.plot_route_folium, and it worked fine
ox.plot_route_folium(G, route, popup_attribute='length')
For the shortest 3 paths "routes", I tried the below and it gave me the below error:
ox.plot_route_folium(G, routes, popup_attribute='length')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-135-2d9737bbef6b> in <module>
----> 1 ox.plot_route_folium(G, routes, popup_attribute='length')
2
3
/opt/anaconda3/lib/python3.8/site-packages/osmnx/folium.py in plot_route_folium(G, route, route_map, popup_attribute, tiles, zoom, fit_bounds, **kwargs)
92 """
93 # create gdf of the route edges in order
---> 94 node_pairs = zip(route[:-1], route[1:])
95 uvk = ((u, v, min(G[u][v], key=lambda k: G[u][v][k]["length"])) for u, v in node_pairs)
96 gdf_edges = utils_graph.graph_to_gdfs(G.subgraph(route), nodes=False).loc[uvk]
TypeError: 'generator' object is not subscriptable
Edit: I've already tried this converting generator to list: routes=list(routes). However, it gives empty list: [] after conversion.
Any advice, please?
Thanks,
You are trying to pass it routes (plural), as a generator of lists. You must pass it a single list representing a single route, as stated in its documentation.

Get results with undirected graph but not with multidigraph

Dear people of stackoverflow,
I made a routeplanner based on length and elevation. With both costfactors I get only results with an undirected graph. So the code is good for an undirect graph but doesn't work with a MultiDiGraph as input, which I want because it is necessary with elevation.
The errors I get:
number 1:
~\anaconda3\envs\environmentwithhighestversion\lib\site-
packages\osmnx\plot.py in
plot_graph_route(G, route, route_color, route_linewidth, route_alpha,
orig_dest_size, ax,
**pg_kwargs)
292
293 # scatterplot origin and destination points (first/last nodes in
route)
--> 294 x = (G.nodes[route[0]]["x"], G.nodes[route[-1]]["x"])
295 y = (G.nodes[route[0]]["y"], G.nodes[route[-1]]["y"])
296 ax.scatter(x, y, s=orig_dest_size, c=route_color,
alpha=route_alpha, edgecolor="none")
TypeError: 'NoneType' object is not subscriptable
Number 2:
~\anaconda3\envs\environmentwithhighestversion\lib\site-
packages\osmnx\utils_graph.py in get_route_edge_attributes(G, route,
attribute, minimize_key, retrieve_default)
263 """
264 attribute_values = []
--> 265 for u, v in zip(route[:-1], route[1:]):
266 # if there are parallel edges between two nodes, select the
one with the
267 # lowest value of minimize_key
TypeError: 'NoneType' object is not subscriptable
The code is partly altered, the original code is of G. Boeing (2021):
https://github.com/gboeing/osmnx-examples/blob/main/notebooks/12-node-elevations-edge-grades.ipynb
Here is also a reproducible example possible.
The code for the first error:
TypeError Traceback (most recent call
last)
<ipython-input-3-86e03594e5bd> in <module>
7 route_by_impedance = ox.shortest_path(G7, source, target,
weight="impedance")
8 print('Route Impedance:')
----> 9 fig, ax = ox.plot_graph_route(G7, route_by_impedance,
node_size=3)
10 def print_route_stats(route):
11 route_grades = ox.utils_graph.get_route_edge_attributes(G7,
route, "grade_abs")
The code for the second error:
ipython-input-4-4eb87f73e021> in print_route_stats(route)
9 #fig, ax = ox.plot_graph_route(G7, route_by_impedance, node_size=3)
10 def print_route_stats(route):
---> 11 route_grades = ox.utils_graph.get_route_edge_attributes(G7,
route, "grade_abs")
12 msg = "The average grade is {:.1f}% and the max is {:.1f}%"
13 print(msg.format(np.mean(route_grades) * 100,
np.max(route_grades) * 100))
Does anybody know why I get this problem?
Kind regards,
Damiaan

Changing back to CPU with Google Colab

I am running a model on Google Colab. The final step I would like to do is print an image, and show the top 5 classification predictions of the model. Here is the code:
image = process_image(imgpath)
index = 17
plot = imshow(image, ax = plt)
plot.axis('off')
plot.title(cat_to_name[str(index)])
plot.show()
axes = predict(image, model)
yaxis = [cat_to_name[str(i)] for i in np.array(axes[1][0])]
y_pos = np.arange(len(yaxis))
xaxis = np.array(axes[0][0])
plt.barh(y_pos, xaxis)
plt.xlabel('probability')
plt.yticks(y_pos, yaxis)
plt.title('probability of flower classification')
plt.show()
I am getting this error when I run this cell:
TypeError Traceback (most recent call last)
<ipython-input-19-d0bb6f461eec> in <module>()
11 axes = predict(image, model)
12
---> 13 yaxis = [cat_to_name[str(i)] for i in np.array(axes[1][0])]
14 y_pos = np.arange(len(yaxis))
15 xaxis = np.array(axes[0][0])
/usr/local/lib/python3.6/dist-packages/torch/tensor.py in __array__(self, dtype)
447 def __array__(self, dtype=None):
448 if dtype is None:
--> 449 return self.numpy()
450 else:
451 return self.numpy().astype(dtype, copy=False)
TypeError: can't convert CUDA tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.
Is there a way to temporarily use CPU on Google Colab and in this particular step? I don't really need to switch back to GPU because this is the final step in my code.
Try the following:
yaxis = [cat_to_name[str(i)] for i in axes[1][0].cpu()]
xaxis = axes[0][0].cpu().numpy()
I think you just need to change
axes = predict(image, model)
to
axes = predict(image, model).cpu()

Networkx Graph edge drawing error

I have the following code which works for a random graph as can be shown. However when I try to use other graph types I get an error in the edge drawing function. In particular the edge positions.
If you comment
G = nw.random_geometric_graph(200, 0.125)
and un-comment
G = nw.barabasi_albert_graph(200, 2)
Error messages appear. I am new to python and NetworkX in particular so any help is appreciated!
import matplotlib.pyplot as plt
import networkx as nw
G = nw.random_geometric_graph(200, 0.125)
#G = nw.watts_strogatz_graph(200, 3, 0.125, seed=None)
#G = nw.barabasi_albert_graph(200, 2)
# position is stored as node attribute data for random_geometric_graph
pos = nw.get_node_attributes(G, 'pos')
# find node near center (0.5, 0.5)
dmin = 1
ncenter = 0
for n in pos:
x, y = pos[n]
d = (x - 0.5) ** 2 + (y - 0.5) ** 2
if d < dmin:
ncenter = n
dmin = d
# color by path length from node near center
p = nw.single_source_shortest_path_length(G, ncenter)
plt.figure(figsize=(8, 8))
nw.draw_networkx_edges(G, pos, nodelist=[ncenter], alpha=0.4)
nw.draw_networkx_nodes(G, pos, nodelist=list(p.keys()), node_size=80, node_color=list(p.values()), cmap=plt.cm.Reds_r)
plt.xlim(-0.05, 1.05)
plt.ylim(-0.05, 1.05)
plt.axis('off')
plt.savefig('random_geometric_graph.png')
plt.show()
The error message given is;
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-11-> in <module>()
22 plt.figure(figsize=(8,8))
23
---> 24 nw.draw_networkx_edges(G, pos, nodelist=[ncenter], alpha=0.4)
25 nw.draw_networkx_nodes(G, pos, nodelist=list(p.keys()), node_size=80, node_color=list(p.values()), cmap=plt.cm.Reds_r)
26
/Users//anaconda/lib/python3.6/site-packages/networkx/drawing/nx_pylab.py in draw_networkx_edges(G, pos, edgelist, width, edge_color, style, alpha, edge_cmap, edge_vmin, edge_vmax, ax, arrows, label, **kwds)
513
514 # set edge positions
--> 515 edge_pos = numpy.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])
516
517 if not cb.iterable(width):
/Users//anaconda/lib/python3.6/site-packages/networkx/drawing/nx_pylab.py in <listcomp>(.0)
513
514 # set edge positions
--> 515 edge_pos = numpy.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])
516
517 if not cb.iterable(width):
KeyError: 0
I don't think any other graph initialisation methods apart from random_geometric_graph sets the node position automatically (as the connectivity in this graph depends on the node positions, it makes sense to set one by default). If you check your example with the watts_strogatz_graph, the dictionary that is returned is actually empty (although it arguably should throw a KeyError).
You need to determine the layout explicitly, e.g. using
pos = nw.spring_layout(G)
or any of the other layout algorithms.
You can see that the problem (from stack trace) is in this line:
nw.draw_networkx_edges(G, pos, nodelist=[ncenter], alpha=0.4)
And the error is KeyError, so something cannot be found. Probably, you need to draw edges here, but you do provide the nodelist. According official docs, method to drawing the edges should accept edgelist, not a nodelist.
So you need to do this:
nw.draw_networkx_edges(G, pos, edgelist=[SOME_EDGES_HERE], alpha=0.4)
Note that this should be edges, not nodes, so you need to find them from the center node.

python matplotlib : assign cmap to make multiple color scattering plot

I am trying to use matplotlib and seaborn to create a scatter plot. It works fine if the entire plot is only one color like below:
sns.regplot(x = pair[0], y = pair[1], data = d, fit_reg = False, ax = ax, x_jitter = True, scatter_kws = {'linewidths':0, 's':2, 'color':'r'})
However, if I need the color of each data point depends on the value in col like:
col = pandas_df.prediction.map({0: [1,0,0], 1:[0,1,0]})
sns.regplot(x = pair[0], y = pair[1], data = d, fit_reg = False, ax = ax, x_jitter = True, scatter_kws = {'linewidths':0, 's':2, 'cmap':"RGB", 'color':col})
where pandas_df is a pandas dataframe, so col is a series of RGB point like:
[1,0,0]
[0,1,0]
[1,0,0]
[0,1,0]
:
:
Then I got the errors:
IndexErrorTraceback (most recent call last)
<ipython-input-12-e17a2dbdd639> in <module>()
15 #print dtype(col)
16 d.plot.scatter(*pair, ax=ax, c=col, linewidths=0, s=2, alpha = 0.7)
---> 17 sns.regplot(x = pair[0], y = pair[1], data = d, fit_reg = False, ax = ax, x_jitter = True, scatter_kws = {'linewidths':0, 's':2, 'cmap':"RGB", 'color':col})
18
19 fig.tight_layout()
/usr/local/lib/python2.7/dist-packages/seaborn/linearmodels.pyc in regplot(x, y, data, x_estimator, x_bins, x_ci, scatter, fit_reg, ci, n_boot, units, order, logistic, lowess, robust, logx, x_partial, y_partial, truncate, dropna, x_jitter, y_jitter, label, color, marker, scatter_kws, line_kws, ax)
777 scatter_kws["marker"] = marker
778 line_kws = {} if line_kws is None else copy.copy(line_kws)
--> 779 plotter.plot(ax, scatter_kws, line_kws)
780 return ax
781
/usr/local/lib/python2.7/dist-packages/seaborn/linearmodels.pyc in plot(self, ax, scatter_kws, line_kws)
328 # Draw the constituent plots
329 if self.scatter:
--> 330 self.scatterplot(ax, scatter_kws)
331 if self.fit_reg:
332 self.lineplot(ax, line_kws)
/usr/local/lib/python2.7/dist-packages/seaborn/linearmodels.pyc in scatterplot(self, ax, kws)
353 kws.setdefault("linewidths", lw)
354
--> 355 if not hasattr(kws['color'], 'shape') or kws['color'].shape[1] < 4:
356 kws.setdefault("alpha", .8)
357
IndexError: tuple index out of range
What did I do wrong in assigning color and cmap in this case? Thanks!
I just came across this problem myself, with code that worked a year ago. (I might have switched from Python 2 to Python 3, which might explain the error.)
Reiteration
I dug into the code a bit, and as you noted, the error is at
--> 355 if not hasattr(kws['color'], 'shape') or kws['color'].shape[1] < 4:
356 kws.setdefault("alpha", .8)
357
IndexError: tuple index out of range
If you look at what is happening here, whatever you pass into the 'color' keyword (specifically 'color':col in your case) needs both of the following features:
It needs to not have a shape attribute
But if I does have a shape attribute, that attribute must have at least 2 dimensions.
The Root Problem
Well, there is the problem: a pandas Series or a numpy ndarray (or several other data structures, I'm guessing), have a shape attribute that can have only 1 dimension.
E.g., when I ran across the problem, I had something like the following:
col.shape
(2506,)
This means that my col variable (in my case, a pandas Series object), both has a shape and the shape has only 1 dimension.
It was not obvious to me how to fix this. I tried to just force my pandas Series into a list, but that didn't fix things. I tried to just pass a 2D pandas DataFrame, where each column was identical, but that didn't fix it.
Potential Fix (for those who cannot be deterred)
In looking through the source code, it was not obvious to me how I could fix things. The right fix, it would seem, might be to add another check in line 355 that looked something like this:
355 if not hasattr(kws['color'], 'shape') or len(kws['color'].shape) < 2 or kws['color'].shape[1] < 4:
But I didn't have the energy (or time) to go through the hassle of forking the source and submitting the fix. :(

Categories