I am using this script from here: link
I want to add new functionality to it. I want it to define starting node on the graph not only by finding the closest node (because that produces odd results like finding the closest node on an other road) but finding the closest and and the closest node along that edge.
My code is available below. I created the findnearestnodeonnearestedge function which should do the work but it doesn't work.
It finds the same node for the starting and destination point, even though they are far from each other...
I am using the newest versions of all packages so you can try the code easily.
Thank you for help
import osmnx as ox
import networkx as nx
import plotly.graph_objects as go
import numpy as np
def findnearestnodeonnearestedge(Gr, pointin):
u, v, key = ox.distance.nearest_edges(G, pointin[0], pointin[1])
n1 = Gr.nodes[u]
n2 = Gr.nodes[v]
d1 = ox.distance.euclidean_dist_vec(pointin[0], pointin[1], n1['x'], n1['y'])
d2 = ox.distance.euclidean_dist_vec(pointin[0], pointin[1], n2['x'], n2['y'])
if d1 < d2:
nodeid = u
else:
nodeid = v
return nodeid
state = ox.geocode_to_gdf('Georgia, US')
ax = ox.project_gdf(state).plot(fc='gray', ec='none')
_ = ax.axis('off')
# Defining the map boundaries
north, east, south, west = 33.798, -84.378, 33.763, -84.422
# Downloading the map as a graph object
G = ox.graph_from_bbox(north, south, east, west, network_type = 'drive')
# Plotting the map graph
ox.plot_graph(G)
# Displaying the 3rd node
list(G.nodes(data=True))[2]
# Displaying the 1st edge
list(G.edges(data=True))[1]
# Displaying the shape of edge using the geometry
list(G.edges(data=True))[1][2]['geometry']
# define origin and desination locations
origin_point = (33.787201, -84.405076)
destination_point = (33.764135, -84.394980)
# get the nearest nodes to the locations
origin_node = findnearestnodeonnearestedge(G, origin_point)
destination_node = findnearestnodeonnearestedge(G, destination_point)
# printing the closest node id to origin and destination points
origin_node, destination_node
# Finding the optimal path
route = nx.shortest_path(G, origin_node, destination_node, weight = 'length')
route
# getting coordinates of the nodes
# we will store the longitudes and latitudes in following list
long = []
lat = []
for i in route:
point = G.nodes[i]
long.append(point['x'])
lat.append(point['y'])
def plot_path(lat, long, origin_point, destination_point):
"""
Given a list of latitudes and longitudes, origin
and destination point, plots a path on a map
Parameters
----------
lat, long: list of latitudes and longitudes
origin_point, destination_point: co-ordinates of origin
and destination
Returns
-------
Nothing. Only shows the map.
"""
# adding the lines joining the nodes
fig = go.Figure(go.Scattermapbox(
name="Path",
mode="lines",
lon=long,
lat=lat,
marker={'size': 10},
line=dict(width=4.5, color='blue')))
# adding source marker
fig.add_trace(go.Scattermapbox(
name="Source",
mode="markers",
lon=[origin_point[1]],
lat=[origin_point[0]],
marker={'size': 12, 'color': "red"}))
# adding destination marker
fig.add_trace(go.Scattermapbox(
name="Destination",
mode="markers",
lon=[destination_point[1]],
lat=[destination_point[0]],
marker={'size': 12, 'color': 'green'}))
# getting center for plots:
lat_center = np.mean(lat)
long_center = np.mean(long)
# defining the layout using mapbox_style
fig.update_layout(mapbox_style="stamen-terrain", mapbox_center_lat=30, mapbox_center_lon=-80)
fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0},
mapbox={
'center': {'lat': lat_center, 'lon': long_center},
'zoom': 13})
fig.show()
plot_path(lat, long, origin_point, destination_point)
# Getting the start and end node of this part
start_node=route[-7]
end_node=route[-6]
# Getting the edge connecting these nodes and storing it as a list in z to maintain the data structure of G.edges
z = []
for i in list(G.edges(data=True)):
if (i[0]==start_node) & (i[1]==end_node):
z.append(i)
z[0][2]['geometry']
def node_list_to_path(G, node_list):
"""
Given a list of nodes, return a list of lines that together follow the path
defined by the list of nodes.
Parameters
----------
G : networkx multidigraph
route : list
the route as a list of nodes
Returns
-------
lines : list of lines given as pairs ( (x_start, y_start), (x_stop, y_stop) )
"""
edge_nodes = list(zip(node_list[:-1], node_list[1:]))
lines = []
for u, v in edge_nodes:
# if there are parallel edges, select the shortest in length
data = min(G.get_edge_data(u, v).values(), key=lambda x: x['length'])
# if it has a geometry attribute (ie, a list of line segments)
if 'geometry' in data:
# add them to the list of lines to plot
xs, ys = data['geometry'].xy
lines.append(list(zip(xs, ys)))
else:
# if it doesn't have a geometry attribute, the edge is a straight
# line from node to node
x1 = G.nodes[u]['x']
y1 = G.nodes[u]['y']
x2 = G.nodes[v]['x']
y2 = G.nodes[v]['y']
line = [(x1, y1), (x2, y2)]
lines.append(line)
return lines
# getting the list of coordinates from the path (which is a list of nodes)
lines = node_list_to_path(G, route)
long2 = []
lat2 = []
for i in range(len(lines)):
z = list(lines[i])
l1 = list(list(zip(*z))[0])
l2 = list(list(zip(*z))[1])
for j in range(len(l1)):
long2.append(l1[j])
lat2.append(l2[j])
print("Length of lat: ", len(lat))
print("Length of lat2: ", len(lat2))
plot_path(lat2, long2, origin_point, destination_point)
Problem was that in the graph coordinates are stored in reverse order. So all pointin[0] and pointin[1] in the function should be reversed and then it will work
Related
My question is similar to this one (R + ggplot) but for Python.
Question
How to generate a (2D) Voronoi diagram where cells have a maximum extend / growth limit ?
it would result in some cells with curved boundary (circle arc), and some space regions not filled by any cell.
An image processing interpretation of the desired output would be to perform some "AND" mask between the voronoi cells and circles centered on each cell with the required radius.
(For my particular problem, I am working with geolocated data, and for now I am willing to accept discrepancies from most voronoi libs that will use lat/lon as cartesian coordinates. That is another matter...)
This question is NOT about clipping or handling of "inifinite" voronoi cells (see scypi.spatial.Voronoi), so the following links are NOT related :
clipping a voronoi diagram python
How to limit Voronoi cells even when infinite with python?
Vaguely related topics:
Is there a way to vary the rate of Voronoi cell growth?
https://gis.stackexchange.com/questions/366471/weighted-voronoi-polygons-in-r
https://gis.stackexchange.com/questions/17282/create-weighted-thiessen-polygons/17284#17284
https://github.com/HichamZouarhi/Weighted-Voronoi-PyQGIS
Example from the R + ggplot answer:
sample code for tests:
from typing import Tuple, List, Union
import geovoronoi
import matplotlib.colors as clr
import matplotlib.pyplot as plt
import numpy as np
from geographiclib.geodesic import Geodesic
from shapely.geometry import Polygon, Point
from simplekml import LineStyle, Color, PolyStyle, Container
WGS84_Tool = Geodesic.WGS84
T_Color_List = List[Union[clr.Colormap, clr.LinearSegmentedColormap, clr.ListedColormap]]
def generate_n_colors(n, cmap_name='tab20') -> T_Color_List:
"""
https://github.com/WZBSocialScienceCenter/geovoronoi/blob/master/geovoronoi/plotting.py
Get a list of `n` numbers from matplotlib color map `cmap_name`. If `n` is larger than the number of colors in the
color map, the colors will be recycled, i.e. they are not unique in this case.
:param n: number of colors to generate
:param cmap_name: matplotlib color map name
:return: list of `n` colors
"""
pt_region_colormap = plt.get_cmap(cmap_name)
max_i = len(pt_region_colormap.colors)
return [pt_region_colormap(i % max_i) for i in range(n)]
def _plot_cell_and_seed(kml: Container,
name: str,
region_polygon: Polygon,
seed_coords: Tuple[float, float],
_kml_color: str):
_p = kml.newpolygon(name=f"{name} zone",
outerboundaryis=[(lon, lat)
for lat, lon
in region_polygon.exterior.coords], )
_p.style.linestyle = LineStyle(color=Color.darkgrey, width=1.)
_p.style.polystyle = PolyStyle(color=_kml_color)
p = kml.newpoint(coords=[seed_coords],
name=name)
p.style.iconstyle.icon.href = "http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png"
p.style.iconstyle.scale = 0.5
p.style.labelstyle.scale = 0.5
def plot_regions(region_polys,
region_pts,
seeds_coords_list: np.ndarray,
seeds_names: List[str],
kml: Container,
colors: T_Color_List,
):
assert (len(seeds_names) == len(seeds_coords_list))
index = 0
for region_id, region_polygon in region_polys.items():
_cell_point_indexes = region_pts[region_id]
_cell_seed_coords = seeds_coords_list[_cell_point_indexes][0]
name = seeds_names[_cell_point_indexes[0]]
_kml_airport_coords = (_cell_seed_coords[-1], _cell_seed_coords[0])
_mpl_color = colors[index]
_mpl_hexa_color = clr.to_hex(_mpl_color, keep_alpha=True)
_hexa_color_no_sharp = _mpl_hexa_color.split("#")[-1]
_kml_color = Color.hexa(_hexa_color_no_sharp)
_kml_color = Color.changealphaint(alpha=7 * 255 // 10, gehex=_kml_color)
_plot_cell_and_seed(kml=kml,
name=name,
region_polygon=region_polygon,
seed_coords=_kml_airport_coords,
_kml_color=_kml_color)
index += 1
# bounding box for geovoronoi
geo_boundaries = {"min": {"lat": +30, "lon": -12},
"max": {"lat": +75, "lon": +35}, }
# a list of [[lat,lon],[lat,lon],[lat,lon],[lat,lon],]
n = 150
seeds_coords_list = np.dstack(
[np.random.uniform(low=geo_boundaries["min"]["lat"], high=geo_boundaries["max"]["lat"], size=n),
np.random.uniform(low=geo_boundaries["min"]["lon"], high=geo_boundaries["max"]["lon"], size=n), ]).reshape((n, 2))
seeds_names = [f"{lat:+_.2f};{lon:+_.2f}" for lat, lon in seeds_coords_list]
boundary_points = geovoronoi.coords_to_points([[geo_boundaries["min"]["lat"], geo_boundaries["min"]["lon"]],
[geo_boundaries["min"]["lat"], geo_boundaries["max"]["lon"]],
[geo_boundaries["max"]["lat"], geo_boundaries["max"]["lon"]],
[geo_boundaries["max"]["lat"], geo_boundaries["min"]["lon"]],
# last necessary ?
[geo_boundaries["min"]["lat"], geo_boundaries["min"]["lon"]]])
boundary_polygon = Polygon(boundary_points)
# beware that geodesics and geovoronoi may not be accurate since it uses planar cartesian formulas...
region_polys, region_pts = geovoronoi.voronoi_regions_from_coords(seeds_coords_list, boundary_polygon)
# DO SOMETHING HERE
#...
#...
#...
kdoc = Kml()
p_kml = Path.cwd() / "voronoi_so.kml"
colors: T_Color_List = generate_n_colors(len(region_polys))
plot_regions(region_polys=region_polys,
region_pts=region_pts,
seeds_coords_list=seeds_coords_list,
seeds_names=seeds_names,
kml=kdoc.newfolder(name="raw regions"),
colors=colors)
print("save KML")
kdoc.save(p_kml.as_posix())
print(p_kml.as_uri())
After some thinking, here is an approach using Shapely and using the intersection between computed circles (360 vertices) and each voronoi cell.
Performance is not convincing since we create 360 points and a polygon + 1 intersection computation for each cell... (at least it is a bounded ...).
However, the underlying voronoi computation data such as cells adjacency is lost, and we can't know if some cells are isolated after this transformation. Maybe some ideas here: Determining and storing Voronoi Cell Adjacency
I do believe better solutions may exist.
So here is a solution, with random geographical data, and corresponding kml rendering.
EDIT: using weighted voronoi diagrams, a possible weight function could be f(d) = d <= radius ? I could not explore this for now...
Raw regions:
Modified raw regions:
from pathlib import Path
from typing import Tuple, List, Union
import geovoronoi
import matplotlib.colors as clr
import matplotlib.pyplot as plt
import numpy as np
from geographiclib.geodesic import Geodesic
from shapely.geometry import Polygon, Point
from simplekml import LineStyle, Kml, Color, PolyStyle, Container
WGS84_Tool = Geodesic.WGS84
T_Color_List = List[Union[clr.Colormap, clr.LinearSegmentedColormap, clr.ListedColormap]]
def generate_n_colors(n, cmap_name='tab20') -> T_Color_List:
"""
https://github.com/WZBSocialScienceCenter/geovoronoi/blob/master/geovoronoi/plotting.py
Get a list of `n` numbers from matplotlib color map `cmap_name`. If `n` is larger than the number of colors in the
color map, the colors will be recycled, i.e. they are not unique in this case.
:param n: number of colors to generate
:param cmap_name: matplotlib color map name
:return: list of `n` colors
"""
pt_region_colormap = plt.get_cmap(cmap_name)
max_i = len(pt_region_colormap.colors)
return [pt_region_colormap(i % max_i) for i in range(n)]
def _create_bounded_regions(region_polys,
region_pts,
distance_criteria_m: float,
cell_seed_coords_list: np.ndarray,
nb_vertices:int=36):
new_polygons = {}
for region_id, region_polygon in region_polys.items():
_cell_point_indexes = region_pts[region_id]
_cell_seed_coords = cell_seed_coords_list[_cell_point_indexes][0]
_arpt_lat = _cell_seed_coords[0]
_arpt_lon = _cell_seed_coords[-1]
cycle_vertices = []
for a in np.linspace(0,359,nb_vertices):
p = WGS84_Tool.Direct(lat1=_arpt_lat, lon1=_arpt_lon, azi1=a, s12=distance_criteria_m)
_point = Point(p["lat2"], p["lon2"])
cycle_vertices.append(_point)
circle = Polygon(cycle_vertices)
new_polygons[region_id] = region_polygon.intersection(circle)
return new_polygons
def _plot_cell_and_seed(kml: Container,
name: str,
region_polygon: Polygon,
seed_coords: Tuple[float, float],
_kml_color: str):
_p = kml.newpolygon(name=f"{name} zone",
outerboundaryis=[(lon, lat)
for lat, lon
in region_polygon.exterior.coords], )
_p.style.linestyle = LineStyle(color=Color.darkgrey, width=1.)
_p.style.polystyle = PolyStyle(color=_kml_color)
p = kml.newpoint(coords=[seed_coords],
name=name)
p.style.iconstyle.icon.href = "http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png"
p.style.iconstyle.scale = 0.5
p.style.labelstyle.scale = 0.5
def plot_regions(region_polys,
region_pts,
seeds_coords_list: np.ndarray,
seeds_names: List[str],
kml: Container,
colors: T_Color_List,
):
assert (len(seeds_names) == len(seeds_coords_list))
index = 0
for region_id, region_polygon in region_polys.items():
_cell_point_indexes = region_pts[region_id]
_cell_seed_coords = seeds_coords_list[_cell_point_indexes][0]
name = seeds_names[_cell_point_indexes[0]]
_kml_airport_coords = (_cell_seed_coords[-1], _cell_seed_coords[0])
_mpl_color = colors[index]
_mpl_hexa_color = clr.to_hex(_mpl_color, keep_alpha=True)
_hexa_color_no_sharp = _mpl_hexa_color.split("#")[-1]
_kml_color = Color.hexa(_hexa_color_no_sharp)
_kml_color = Color.changealphaint(alpha=7 * 255 // 10, gehex=_kml_color)
_plot_cell_and_seed(kml=kml,
name=name,
region_polygon=region_polygon,
seed_coords=_kml_airport_coords,
_kml_color=_kml_color)
index += 1
# bounding box for geovoronoi
geo_boundaries = {"min": {"lat": +30, "lon": -12},
"max": {"lat": +75, "lon": +35}, }
# a list of [[lat,lon],[lat,lon],[lat,lon],[lat,lon],]
n = 150
seeds_coords_list = np.dstack(
[np.random.uniform(low=geo_boundaries["min"]["lat"], high=geo_boundaries["max"]["lat"], size=n),
np.random.uniform(low=geo_boundaries["min"]["lon"], high=geo_boundaries["max"]["lon"], size=n), ]).reshape((n, 2))
seeds_names = [f"{lat:+_.2f};{lon:+_.2f}" for lat, lon in seeds_coords_list]
boundary_points = geovoronoi.coords_to_points([[geo_boundaries["min"]["lat"], geo_boundaries["min"]["lon"]],
[geo_boundaries["min"]["lat"], geo_boundaries["max"]["lon"]],
[geo_boundaries["max"]["lat"], geo_boundaries["max"]["lon"]],
[geo_boundaries["max"]["lat"], geo_boundaries["min"]["lon"]],
# last necessary ?
[geo_boundaries["min"]["lat"], geo_boundaries["min"]["lon"]]])
boundary_polygon = Polygon(boundary_points)
# beware that geodesics and geovoronoi may not be accurate since it uses planar cartesian formulas...
region_polys, region_pts = geovoronoi.voronoi_regions_from_coords(seeds_coords_list, boundary_polygon)
new_region_polys = _create_bounded_regions(region_polys=region_polys,
region_pts=region_pts,
distance_criteria_m=300_000.,
cell_seed_coords_list=seeds_coords_list, )
kdoc = Kml()
p_kml = Path.cwd() / "voronoi_so.kml"
colors: T_Color_List = generate_n_colors(len(region_polys))
plot_regions(region_polys=region_polys,
region_pts=region_pts,
seeds_coords_list=seeds_coords_list,
seeds_names=seeds_names,
kml=kdoc.newfolder(name="raw regions"),
colors=colors)
plot_regions(region_polys=new_region_polys,
region_pts=region_pts,
seeds_coords_list=seeds_coords_list,
seeds_names=seeds_names,
kml=kdoc.newfolder(name="new_regions (range)"),
colors=colors)
print("save KML")
kdoc.save(p_kml.as_posix())
print(p_kml.as_uri())
I'm trying to update graph plotting, every 5-7 second. so I tried matplotlib to refresh the plot figure. But by using this, the same graph plotted again and again.
for better understanding - I have two files one for node creation, which is changed by every 10 seconds using another program and another is edge creation, which is static. from this files trying to create one graph which is dynamic like this - https://drive.google.com/file/d/1snFITs4jvW5H8JSF-3pqFE2F1XjX88PD/view?usp=sharing
my network code is -
fig = plt.figure()
net = fig.add_subplot(111)
def update(it):
with open('node.csv', 'r') as nodecsv:
nodereader = csv.reader(nodecsv)
nodes = [n for n in nodereader][1:]
node_names = [n[0] for n in nodes]
with open('edge.csv', 'r') as edgecsv:
edgereader = csv.reader(edgecsv)
edges = [tuple(e) for e in edgereader][1:]
g = nx.Graph()
g.add_nodes_from(node_names)
g.add_edges_from(edges)
print(nx.info(g))
# * ******************** Node Color Part **************************** *
nx.draw(g,pos=pos,node_size=node_size,node_color=color, linewidths=2,**options)
ani = animation.FuncAnimation(fig, update, interval=1000)
plt.show()
and another thing is, I'm trying to apply node colour according to the node attribute that is working but also according to node degree means if node attribute colour is blue then apply degree separately in blue. If green then applies degree separately in green and so on.
My node colour code -
node_status = {}
for node in nodes:
node_status[node[0]] = node[1]
nx.set_node_attributes(g,node_status,'node_status')
color = []
for n in g.nodes():
#print(n,g.nodes[n]['node_status'])
if g.nodes[n]['node_status'] == 'A': color.append("blue")
if g.nodes[n]['node_status'] == 'B': color.append("yellow")
if g.nodes[n]['node_status'] == 'C': color.append("red")
if g.nodes[n]['node_status'] == 'D': color.append("green")
if g.nodes[n]['node_status'] == 'E': color.append("pink")
betCent = nx.betweenness_centrality(g, normalized=True, endpoints=True)
#node_color = [20000.0 * g.degree(v) for v in g]
node_size = [v * 10000 for v in betCent.values()]
Thanks in advance.
I have put together a script that creates the following; A start and end curve shape and a linear curve between.
Now what I'm wanting to do is to duplicate and transform the starting curve shape along the path (as depicted by the image), and perform a loft (preferred as would prob give the cleanest result), or alternatively, loft between the two existing curve shapes, and then deform the loft geometry to the curve. For the latter I have tried;
pm.deformer((loftShape, path), type='curveWarp', name='curveWarp#')
without success. The locators are points calculated to generate the correct
bezier curve given different distances/ starting angles. I would have thought the hard work was done, but I'm having trouble with this seemingly simple last step.
Below is a method I put together to query curve info:
def getClosestCV(x, curves, tolerance=0.0):
'''Find the closest control vertex between the given vertices, CVs, or objects and each of the given curves.
:Parameters:
x (str)(obj)(list) = Polygon vertices, control vertices, objects, or points given as (x,y,z) tuples.
curves (str)(obj)(list) = The reference object in which to find the closest CV for each vertex in the list of given vertices.
tolerance (int)(float) = Maximum search distance. Default is 0.0, which turns off the tolerance flag.
:Return:
(dict) closest vertex/cv pairs (one pair for each given curve) ex. {<vertex from set1>:<vertex from set2>}.
ex. vertices = Init.getComponents(objects, 'vertices')
closestVerts = getClosestCV(curve0, curves)
'''
pm.undoInfo(openChunk=True)
x = pm.ls(x, flatten=1) #assure x arg is a list (if given as str or single object).
npcNode = pm.ls(pm.createNode('nearestPointOnCurve'))[0] #create a nearestPointOnCurve node.
result={}
for curve in pm.ls(curves):
pm.connectAttr(curve.worldSpace, npcNode.inputCurve, force=1) #Connect the curve's worldSpace geometry to the npc node.
for i in x:
if not isinstance(i, (tuple, list, set)):
pos = pm.pointPosition(i)
else:
pos = i
pm.setAttr(npcNode.inPosition, pos)
distance = Init.getDistanceBetweenTwoPoints(pos, pm.getAttr(npcNode.position))
p = pm.getAttr(npcNode.parameter)
if not tolerance:
result[i] = p
elif distance < tolerance:
result[i] = p
pm.delete(npcNode)
pm.undoInfo(closeChunk=True)
return result
def getCvInfo(c, returnType='cv', filter_=[]):
'''Get a dict containing CV's of the given curve(s) and their corresponding point positions (based on Maya's pointOnCurve command).
:Parameters:
- c (str)(obj)(list) = Curves or CVs to get CV info from.
- returnType (str) = The desired returned values. Default is 'cv'.
valid values are:
'cv' = Return a list of all CV's for the given curves.
'count' = Return an integer representing the total number of cvs for each of the curves given.
'parameter', 'position', 'index', 'localPosition', 'tangent', 'normalizedTangent', 'normal', 'normalizedNormal', 'curvatureRadius', 'curvatureCenter'
= Return a dict with CV's as keys and the returnType as their corresponding values.
ex. {NurbsCurveCV(u'polyToCurveShape7.cv[5]'): [-12.186520865542082, 15.260936896515751, -369.6159740743584]}
- filter_ (str)(obj)(list) = Value(s) to filter for in the returned results.
:Return:
(dict)(list)(int) dependant on returnType.
ex. cv_tan = getCvInfo(curve.cv[0:2],'tangent') #get CV tangents for cvs 0-2.
ex. cvParam = getCvInfo(curve, 'parameters') #get the curves CVs and their corresponding U parameter values.
ex. filtered = getCvInfo(<curve>, 'normal', <normal>) #filter results for those that match the given value.
'''
result={}
for curve in pm.ls(c):
if '.cv' in str(curve): #if CV given.
cvs = curve
curve = pm.listRelatives(cvs, parent=1)
else: #if curve(s) given
cvs = curve.cv
parameters = Init.getClosestCV(cvs, curve) #use getClosestCV to get the parameter location for each of the curves CVs.
for cv, p in parameters.items():
if returnType is 'position': # Get cv position
v = pm.pointOnCurve(curve, parameter=p, position=True)
elif returnType is 'localPosition':
v = pm.getAttr(cv) # local cv position
elif returnType is 'tangent': # Get cv tangent
v = pm.pointOnCurve(curve, parameter=p, tangent=True)
elif returnType is 'normalizedTangent':
v = pm.pointOnCurve(curve, parameter=p, normalizedTangent=True)
elif returnType is 'normal': # Get cv normal
v = pm.pointOnCurve(curve, parameter=p, normal=True)
elif returnType is 'normalizedNormal':
v = pm.pointOnCurve(curve, parameter=p, normalizedNormal=True) #Returns the (x,y,z) normalized normal of curve1 at parameter 0.5.
elif returnType is 'curvatureRadius': # Get cv curvature
v = pm.pointOnCurve(curve, parameter=p, curvatureRadius=True) #Returns the curvature radius of curve1 at parameter 0.5.
elif returnType is 'curvatureCenter':
v = pm.pointOnCurve(curve, parameter=p, curvatureCenter=True)
elif returnType is 'parameter': # Return the CVs parameter.
v = p
elif returnType is 'count': # total number of cv's for the curve.
result[curve] = len(Init.getCvInfo(curve))
break
elif returnType is 'index': # index of the cv
s = str(cv)
v = int(s[s.index('[')+1:s.index(']')])
else:
v = None
result[cv] = v
if returnType is 'cv':
result = result.keys()
if filter_:
if not isinstance(filter_, (tuple, set, list)):
filter_ = list(filter_)
try:
result = {k:v for k,v in result.items() if any((v in filter_, v==filter_))}
except AttributeError:
result = [i for i in result if any((i in filter_, i==filter_))]
if len(result) is 1:
try:
result = result.values()[0]
except AttributeError, TypeError:
result = result[0]
return result
I ultimately decided to use the built-in MASH plugin for this. Perhaps this will be of help to someone in the future.
def duplicateAlongCurve(path, start, count=6, geometry='Instancer'):
'''Duplicate objects along a given curve using MASH.
:Parameters:
path (obj) = The curve to use as a path.
start () = Starting object.
count (int) = The number of duplicated objects. (point count on the MASH network)
geometry (str) = Particle instancer or mesh instancer (Repro node). (valid: 'Mesh' (default), 'Instancer')
:Return:
(list) The duplicated objects in order of start to end.
'''
pm.undoInfo(openChunk=1)
#create a MASH network
import MASH.api as mapi
mashNW = mapi.Network()
mashNW.MTcreateNetwork(start, geometry=geometry, hideOnCreate=False) #MASH_tools module (derived from 'createNetwork')
curveNode = pm.ls(mashNW.addNode('MASH_Curve').name)[0]
pm.connectAttr(path.worldSpace[0], curveNode.inCurves[0], force=1)
pm.setAttr(curveNode.stopAtEnd, 1) #0=off, 1=on
pm.setAttr(curveNode.clipStart, 0)
pm.setAttr(curveNode.clipEnd, 1)
pm.setAttr(curveNode.timeStep, 1)
pm.setAttr(curveNode.curveLengthAffectsSpeed, 1)
distNode = pm.ls(mashNW.distribute)[0]
pm.setAttr(distNode.pointCount, count)
pm.setAttr(distNode.amplitudeX, 0)
instNode = pm.ls(mashNW.instancer)[0]
baked_curves = mashNW.MTbakeInstancer(instNode) #MASH_tools module (derived from 'MASHbakeInstancer')
result=[start]
for curve in reversed(baked_curves):
result.append(curve)
pm.delete(mashNW.waiter.name()) #delete the MASH network.
pm.undoInfo(closeChunk=1)
return result
I am a newbie in Python. I have a map like this map, and I want to create the shortest paths from each node to every other nodes using network x. I've tried to write a simple code like this:
shp = nx.read_shp("../Shapefiles/Shapefiles/Station_in_Corridors/Group_1.shp")
G = nx.DiGraph()
for data in shp.edges(data = True):
G.add_edge(data[0],data[1],weight = data[2]["Length_Km"])
nx.floyd_warshall(G)
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G, pos = pos, node_size=100)
nx.draw_networkx_edges(G, pos = pos)
plt.show()
Prior to calling the result of floyd warshall, I'd like to see the graph first. Turns out the graph return like this:result. I don't think that graph is similar to the input (or is it?).
Anyhow, I've also tried to manually append the points with this code:
cor1 = driver.Open(cor1Data)
cor2 = driver.Open(cor2Data)
ly1 = cor1.GetLayer()
ly2 = cor2.GetLayer()
allpoints = {}
kreuz = []
arcs = {}
for i in range(ly1.GetFeatureCount()):
for j in range(ly2.GetFeatureCount()): #Create road
feat1 = ly1.GetFeature(i)
geom1 = feat1.GetGeometryRef()
points1 = geom1.GetPoints()
feat2 = ly2.GetFeature(j)
geom2 = feat2.GetGeometryRef()
points2 = geom2.GetPoints()
arcs[i] = [(points1[0],points1[1],geom1.Length()),feat1]
arcs[len(ly1)+j] = [(points2[0],points2[1],geom2.Length()),feat2]
#Create OD trips
if not points1[0] in allpoints.values():
allpoints[i] = [points1[0],geom1.Length(),feat1]
else:
allpoints[i] = [points1[1],geom1.Length(),feat1]
if not points2[0] in allpoints.values():
allpoints[len(ly1)+j] = [points2[0],geom1.Length(),feat1]
else:
allpoints[len(ly1)+j] = [points2[1],geom1.Length(),feat1]
#append kreuz
if points1[0] == points2[0] or points1[0] == points2[1]:
kreuz.append(points1[0])
elif points1[1] == points2[0] or points1[1] == points2[1]:
kreuz.append(points1[1])
G = nx.DiGraph() #Set a directed graph
for k,v in arcs.items():
G.add_edge(v[0][0],v[0][1], weight = v[0][2])
G.add_nodes_from(allpoints.values())
nx.floyd_warshall(G)
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G, pos = pos, node_size=100)
nx.draw_networkx_edges(G, pos = pos)
plt.show()
and the result:
Result of second code
Is it a normal graph? And can anybody give some insights on how to calculate the shortest path right?
The networkx floyd_warshall calculates the shortest path for all pair of node in a graph and returns a dictionary as per the documentation.
distance (dict) – A dictionary, keyed by source and target, of shortest paths distances between nodes.
The algorithm does not change the graph in any way so by not storing the returned dictionary in a variable will do nothing.
To your question, you've already calculated the shortest paths, you simple doesn't do anything with them. If you wish to position the nodes in the plot according to some path length I don't think you're using an appropriate algorithm.
I would like to find the node degree with edges of certain labels, when I use the the degree() method of networkx it gives me a dic with {:} but how to get the labels of those edges?. Any help including the info on what other graph analysis packages has this provision, is appreciated.
In igraph, you want g.es.select(_source=i). This gets all of the edges whose source vertex is i, at which point you can ask for the attributes of those edges:
>>> g = igraph.Graph.Full(3) #complete graph on three vertices
>>> g.es['label'] = ['a','b','c'] #sets the first edge to have 'label' value 'a', etc.
>>> g.es.select(_source=0)['label']
['a', 'b']
Nodes' degree by certain edges labels
Random graph functions
def rand_gen(m):
yield random.randint(0,m)
def get_edges(n):
tpl = []
for _ in range(n):
for x,y in zip(rand_gen(n), rand_gen(n)):
tpl.append((x,y, {random.choice(['a','b','c']): random.randint(0,10)}))
return tpl
Create graph
g = nx.Graph()
e = get_edges(10)
g.add_edges_from(e)
pos = nx.spring_layout(g)
nx.draw_networkx_nodes(g,pos)
nx.draw_networkx_labels(g,pos, font_color='w')
nx.draw_networkx_edges(g,pos)
nx.draw_networkx_edge_labels(g,pos, edge_labels={(x,y):l.keys()[0] for x,y,l in g.edges(data=True)})
plt.axis('off')
plt.show()
Select by label
nds = []
nds.extend([n1, n2] for n1,n2,l in g.edges(data=True) if l.keys()[0] == 'a')
nds = [x for y in nds for x in y]
Get the degree of unique labels
[nx.degree(g,x) for x in set(nds)]
[out]
[2, 3, 2, 2, 5]