def find_subgraph_similar_direction(G, source=None, direction_eps_radians=None, already_done=None): """ originally from networkx/search.py added traverse_node_callback() stuff. """ neighbors = G.neighbors seen = {} # nodes seen succ = {} queue = [source] # use as LIFO queue direction_radians = None already_did_first_edge = False debug = False while queue: v = queue[-1] if v not in seen: seen[v] = True succ[v] = [] done = 1 for w in neighbors(v): if w not in seen: this_direction_radians = w.get_direction_from(v) if direction_radians is None: # testing first edge for test_graph in already_done: # check already done graphs to see if we have this edge already_did_first_edge = test_graph.has_edge(v, w) if already_did_first_edge: break # first edge if not already_did_first_edge: direction_radians = this_direction_radians if (not already_did_first_edge) and angles_near( this_direction_radians, direction_radians, direction_eps_radians, mod_pi=True ): queue.append(w) succ[v].append(w) done = 0 break else: seen[w] = True if done == 1: queue.pop() result = None if len(succ) > 1: result = NX.Graph(succ) if 0: print "source", source print succ print return result
def points2graph( x, y, distance_thresh=1.5, angle_thresh=30 * D2R, show_clusters=False, show_clusters_frame=None, aspect_ratio=1.0 ): x = numpy.array(x) y = numpy.array(y) tri = delaunay.Triangulation(x, y) nodes = [CornerNode(xi, yi, i, aspect_ratio=aspect_ratio) for i, (xi, yi) in enumerate(zip(x, y))] segx = [] segy = [] vert_inds = [] for node in tri.triangle_nodes: for i in range(3): segx.append((x[node[i]], x[node[(i + 1) % 3]])) segy.append((y[node[i]], y[node[(i + 1) % 3]])) vert_inds.append((node[i], node[(i + 1) % 3])) if 0: # find and remove hypotenuse dist2 = [(segx[i][0] - segx[i][1]) ** 2 + (segy[i][0] - segy[i][1]) ** 2 for i in range(-3, 0)] longest_ind = -3 + numpy.argmax(dist2) del segx[longest_ind] del segy[longest_ind] del vert_inds[longest_ind] # Discard duplicates. (This could be acheived by more careful # attention at the triangulation stage.) idx = 0 while idx < len(vert_inds): test = vert_inds[idx] idx += 1 remove = [] for cmpi in range(idx, len(vert_inds)): if test == vert_inds[cmpi]: remove.append(cmpi) remove.reverse() for i in remove: del vert_inds[i] del segx[i] del segy[i] adjacency = numpy.zeros((len(x), len(x)), dtype=numpy.uint32) graph = NX.Graph() for test_seg in vert_inds: i, j = test_seg graph.add_edge(nodes[i], nodes[j]) # The graph is not directed, so we don't need to add (j,i). if 1: # remove edges not belonging to 2 shortest distance clusters edges = graph.edges() directions = [edge[0].get_direction_from(edge[1]) for edge in edges] directions = numpy.array(directions) % numpy.pi distance = [edge[0].get_distance_from(edge[1]) for edge in edges] obs = numpy.array([directions, distance]).T distance_max = obs[:, 1].max() scale = [[1, numpy.pi / distance_max]] scaled_obs = obs * scale if 1: # do clustering on Cartesian grid. r = obs[:, 1] median_r = numpy.median(r) x = r * numpy.cos(obs[:, 0] * 2) # double angle to go around full circle y = r * numpy.sin(obs[:, 0] * 2) # double angle to go around full circle if 0 and show_clusters: pylab.figure() pylab.plot(x, y, ".") ax = pylab.gca() ax.set_aspect("equal") print "median_r", median_r print "%d cut" % len(numpy.nonzero(r > median_r * distance_thresh)[0]) # threshold large distances to origin good_cond = r <= median_r * distance_thresh good_idx = numpy.nonzero(good_cond)[0] cartesian_obs = numpy.array([x, y]).T # filter data cartesian_obs_use = cartesian_obs[good_idx] # 4 clusters: 2 for each main direction, 2 for diagonals # cartesian_clusters, labels = scipy.cluster.vq.kmeans2( cartesian_obs, 4) # 5 clusters: same as above, plus trash if 0: cartesian_clusters, labels = scipy.cluster.vq.kmeans2(cartesian_obs, 5, iter=100, minit="points") else: # initial guesses cluster_guesses = numpy.array([[median_r, 0], [0, median_r], [-median_r, 0], [0, -median_r]]) cartesian_clusters_use, labels_use = scipy.cluster.vq.kmeans2( cartesian_obs_use, cluster_guesses, iter=100, minit="matrix" ) # add new cluster with filtered data new_label = numpy.max(labels_use) + 1 cartesian_clusters = numpy.zeros((5, 2)) cartesian_clusters[:-1, :] = cartesian_clusters_use labels = new_label * numpy.ones((cartesian_obs.shape[0],), dtype=labels_use.dtype) labels[good_idx] = labels_use cartesian_clusters_center = numpy.array(cartesian_clusters, copy=True) ## print 'cartesian_clusters' ## print cartesian_clusters ## print x = numpy.array(cartesian_clusters[:, 0], copy=True) y = numpy.array(cartesian_clusters[:, 1], copy=True) r = numpy.sqrt(x ** 2 + y ** 2) theta = numpy.arccos(y / r, x / r) theta[r == 0] = 0 # eliminate nan theta = theta / 2 # get back to mod pi angles clusters = numpy.array([theta, r]).T if show_clusters: n_clusters = len(clusters) pylab.figure() ax = pylab.subplot(2, 1, 1) for i in range(n_clusters): cluster_cond = labels == i this_obs = obs[cluster_cond] color = get_color(i) pylab.plot(this_obs[:, 0] / 2.0, this_obs[:, 1], ".", mec=color, mfc=color) # pylab.plot([clusters[i][0]],[clusters[i][1]],'ko') print "label", i, [clusters[i][0]], [clusters[i][1]] if show_clusters_frame is not None: pylab.title("frame %d" % show_clusters_frame) ax = pylab.subplot(2, 1, 2) for i in range(n_clusters): cluster_cond = labels == i this_obs = obs[cluster_cond] color = get_color(i) pylab.plot(cartesian_obs[cluster_cond, 0], cartesian_obs[cluster_cond, 1], ".", mec=color, mfc=color) # print i,[cartesian_clusters_center[i][0]],[cartesian_clusters_center[i][1]] pylab.plot([cartesian_clusters_center[i][0]], [cartesian_clusters_center[i][1]], "ko") ax.set_aspect("equal") pylab.show() # sys.exit() cluster_distances = clusters[:, 1] if show_clusters: print "cluster_distances", cluster_distances cluster_idxs = numpy.argsort(cluster_distances) shortest_idxs = cluster_idxs[1:3] # shortest is trash at 0, ignore it and take 2 near shortest graph = NX.Graph() # new graph for i in shortest_idxs: take_edges = numpy.nonzero(labels == i)[0] this_cluster_directions = obs[take_edges][:, 0] this_cluster_distances = obs[take_edges][:, 1] median_cluster_direction = numpy.median(this_cluster_directions) median_cluster_distance = numpy.median(this_cluster_distances) ## print 'mean',numpy.mean(this_cluster_distances) ## print 'median',numpy.median(this_cluster_distances) ## print 'std',numpy.std(this_cluster_distances) ## print for j in take_edges: this_distance = obs[j, 1] this_direction = obs[j, 0] if this_distance >= distance_thresh * median_cluster_distance: # too long - ignore continue if not angles_near(this_direction, median_cluster_direction, angle_thresh, mod_pi=True): # angle is too different continue graph.add_edge(edges[j]) return graph, nodes