Commit bb4728df authored by Adam Paquette's avatar Adam Paquette
Browse files

Clean up and additions to the code base for voronoi.

parent 24989545
Loading
Loading
Loading
Loading
+20 −1
Changes for autocnet/cg/cg.py: 20 added lines, 1 removed line.
Original line number Diff line number Diff line
import warnings

import pandas as pd
import numpy as np
import networkx as nx
@@ -150,7 +152,7 @@ def vor(graph, clean_keys, s=30):
        """
        neighbors_dict = nx.degree(graph)
        if not all(value == len(graph.neighbors(graph.nodes()[0])) for value in neighbors_dict.values()):
                raise AssertionError('The graph is not complete')
            warnings.warn('The given graph is not complete and may yield garbage.')

        intersection, proj_gdf, source_gdf = compute_intersection(graph.nodes()[0], graph, clean_keys)

@@ -202,6 +204,23 @@ def vor(graph, clean_keys, s=30):


def compute_intersection(source, graph, clean_keys=[]):
    """

    Parameters
    ----------
    source : int or object
             Node id or Node object to use as the initial reprojection space

    graph : object
            a networkx graph object

    clean_keys : list
                 Of strings used to apply masks to omit correspondences

    Returns
    -------
    intersection :
    """
    if type(source) is int:
        source = graph.node[source]

+14 −4
Changes for autocnet/graph/edge.py: 14 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ from collections import MutableMapping

import numpy as np
import pandas as pd
import networkx as nx

from scipy.spatial.distance import cdist

@@ -456,22 +457,31 @@ class Edge(dict, MutableMapping):
        """
        if self.matches is None:
            raise AttributeError('Matches have not been computed for this edge')
        voronoi = cg.vor(self, clean_keys, **kwargs)
        self.matches = pd.concat([self.matches, voronoi[1]['vor_weights']], axis=1)

        cg.vor(self, clean_keys, **kwargs)

    def get_keypoints(self, node, clean_keys, **kwargs):

        matches, _ = self.clean(clean_keys=clean_keys)

        if type(node) is str:
            node = node.lower()

        if type(node) is Node:
        elif type(node) is Node:
            node = node['node_id']

        else:
            AssertionError('Node parameter is not a string or node object.')

        if node == "source" or node == "s" or node == self.source['node_id']:
            return self.source.get_keypoint_coordinates(index=matches['source_idx'], **kwargs)
        if node == "destination" or node == "d" or node == self.destination['node_id']:

        elif node == "destination" or node == "d" or node == self.destination['node_id']:
            return self.destination.get_keypoint_coordinates(index=matches['destination_idx'], **kwargs)

        else:
            AssertionError('Could not obtain the correct keypoints based on the given parameters.')

    def decompose(self, maxiterations=3):
        """
        Apply coupled decomposition to the images and
+30 −11
Changes for autocnet/graph/network.py: 30 added lines, 11 removed lines.
Original line number Diff line number Diff line
@@ -685,19 +685,38 @@ class CandidateGraph(nx.Graph):
        edges = [(u, v) for u, v, edge in self.edges_iter(data=True) if func(edge, *args, **kwargs)]
        return self.create_edge_subgraph(edges)

    def compute_cliques(self, node_id):
    def compute_cliques(self, node_id=None):
        """
        Computes all maximum complete subgraphs for the given graph.
        If a node_id is given, method will return only the complete subgraphs that
        contain that node

        Parameters
        ----------
        node_id : int
                  Arbitrary integer value for a given node

        Returns
        -------
        : list
          A list of lists of node ids that make up maximum complete subgraphs of the given graph
        """

        if node_id is not None:
            return list(nx.cliques_containing_node(self, nodes=node_id))
        else:
            return list(nx.find_cliques(self))

    def compute_vor_weight(self, clean_keys, node_id=None, clique=False):
        if clique:
            cliques = self.compute_cliques(node_id)
            for g in cliques:
                subgraph = self.create_node_subgraph(g)
                vor(subgraph, clean_keys)
        else:
            for e in self.edges_iter():
                subgraph = self.create_node_subgraph(e)
                vor(subgraph, clean_keys)
    def compute_vor_weight(self, clean_keys):
        """
        Computes a voronoi weight for each edge in a given graph.
        Can function as is, but is slightly optimized for complete subgraphs.

        Parameters
        ----------
        clean_keys : list
                     Strings used to apply masks to omit correspondences

        """

        vor(self, clean_keys)
+108 −81
Changes for notebooks/Testing_geopandas.ipynb: 108 added lines, 81 removed lines.
Original line number Diff line number Diff line
%% Cell type:code id: tags:

``` python
import os
import sys
import warnings

sys.path.insert(0, os.path.abspath('..'))

import cv2
import numpy as np
import geopandas as gpd
import pandas as pd
import networkx as nx
from shapely.geometry import Polygon as Poly, Point
from shapely.affinity import scale
from shapely.ops import unary_union
import ogr
import time
from scipy.spatial import Voronoi

from autocnet.examples import get_path
from autocnet.graph.network import CandidateGraph
from autocnet.cg import cg

from unittest.mock import Mock
from unittest.mock import MagicMock
from autocnet.graph import edge
from autocnet.graph import node
from autocnet.graph.node import Node
from plio.io import io_gdal

from autocnet.utils.utils import array_to_poly

from IPython.display import display

%pylab inline
figsize(20, 20)
```

%% Output

    Populating the interactive namespace from numpy and matplotlib

%% Cell type:code id: tags:

``` python
def scale_point(point, centroid, scalar):
    point = np.asarray(point)
    centroid = centroid[:2]
    vector = ((point - centroid)*scalar) + centroid
    return (vector)
```

%% Cell type:code id: tags:

``` python
def reproj_point(H, point):
    """
    Reproject a pixel in one image into another image

    Parameters
    ----------
    H : object
        (3,3) ndarray or Homography object

    corner : iterable
             A 2 element iterable in the form x, y
    """
    if len(point) == 2:
        coords = np.array([point[0],point[1],1])
    elif len(point) == 3:
        coords = np.asarray(point)
        coords *= coords[-1]  # Homogenize

    return H.dot(coords)
```

%% Cell type:code id: tags:

``` python
def compute_intersection(source, graph, clean_keys=[]):
    if type(source) is int:
        source = graph.node[source]

    source_corners = source.geodata.xy_corners
    source_poly = Poly(source_corners)

    source_gdf = gpd.GeoDataFrame({'source_geom': [source_poly], 'source_node': [source['node_id']]}).set_geometry('source_geom')

    proj_list = []
    proj_nodes = []
    # Begin iterating through the nodes in the graph excluding the source node
    for n in graph.nodes_iter():
        if n == source['node_id']:
            continue

        # Define the edge, matches, and destination based on the zero node and the nth node
        destination = graph.node[n]
        destination_corners = destination.geodata.xy_corners
        try:
            edge = graph.edge[source['node_id']][destination['node_id']]

        edge = graph.edge[source['node_id']][destination['node_id']]
            # If the source image has coordinate transformation data
            if (source.geodata.coordinate_transformation.this != None) and \
            (destination.geodata.coordinate_transformation.this != None):
                proj_poly = Poly(destination.geodata.xy_corners)

            # Else, use the homography transform to get an intersection of the two images
            else:
                if source['node_id'] > destination['node_id']:
                    kp2 = edge.get_keypoints('source', clean_keys = clean_keys, homogeneous = True)
                    kp1 = edge.get_keypoints('destination', clean_keys = clean_keys, homogeneous = True)
                else:
                    kp2 = edge.get_keypoints('destination', clean_keys = clean_keys, homogeneous = True)
                    kp1 = edge.get_keypoints('source', clean_keys = clean_keys, homogeneous = True)

                H, mask = cv2.findHomography(kp2.values, kp1.values, cv2.RANSAC, 2.0)
                proj_corners = []
                for c in destination_corners:
                    x, y, h = reproj_point(H, c)
                    x /= h
                    y /= h
                    h /= h
                    proj_corners.append((x, y))

        # Will still need the check but the helper function will make these calls much easier to understand
        if source['node_id'] > destination['node_id']:
            kp2 = edge.get_keypoints('source', clean_keys = clean_keys, homogeneous = True)
            kp1 = edge.get_keypoints('destination', clean_keys = clean_keys, homogeneous = True)
        else:
            kp2 = edge.get_keypoints('destination', clean_keys = clean_keys, homogeneous = True)
            kp1 = edge.get_keypoints('source', clean_keys = clean_keys, homogeneous = True)

        # If the source image has coordinate transformation data
        if (source.geodata.coordinate_transformation.this != None) and \
        (destination.geodata.coordinate_transformation.this != None):
            proj_poly = Poly(destination.geodata.xy_corners)

        # Else, use the homography transform to get an intersection of the two images
        else:
            H, mask = cv2.findHomography(kp2.values, kp1.values, cv2.RANSAC, 2.0)
            proj_corners = []
            for c in destination_corners:
                x, y, h = reproj_point(H, c)
                x /= h
                y /= h
                h /= h
                proj_corners.append((x, y))

            proj_poly = Poly(proj_corners)
                proj_poly = Poly(proj_corners)
        except:
            continue

        proj_list.append(proj_poly)
        proj_nodes.append(n)

    proj_gdf = gpd.GeoDataFrame({'proj_geom': proj_list, 'proj_node': proj_nodes}).set_geometry('proj_geom')

    intersect_gdf = gpd.overlay(source_gdf, proj_gdf, how='intersection')
    intersect_gdf = intersect_gdf.rename(columns = {'geometry':'intersect_geom'}).set_geometry('intersect_geom')
#     intersect_gdf = intersect_gdf.rename(columns = {'geometry':'intersect_geom'}).set_geometry('intersect_geom')
    intersect_gdf['overlaps_all'] = intersect_gdf.geometry.apply(lambda x:proj_gdf.geometry.contains(scale(x, .9, .9)).all())
    intersection = intersect_gdf.query('overlaps_all == True').set_geometry('intersect_geom')
    intersection = intersect_gdf.query('overlaps_all == True')

    if len(intersection) == 0:
        new_poly = unary_union(intersect_gdf.geometry)
        intersection = gpd.GeoDataFrame({'source_node': source['node_id'], 'geometry': new_poly, 'overlaps_all': True})

    return intersection, proj_gdf, source_gdf
```

%% Cell type:code id: tags:

``` python
def vor(graph, clean_keys=[], verbose=False, s = 30):

    neighbors_dict = nx.degree(graph)
    if not all(value == len(graph.neighbors(graph.nodes()[0])) for value in neighbors_dict.values()):
        raise AssertionError('The graph is not complete')
    if False in list(all(value == len(graph.neighbors(graph.nodes()[0])) for value in neighbors_dict.values())):
        warnings.warn('The given graph is not complete and may yield garbage.')

    # Have compute_intersection get the intersections of the subgraph, the projected nodes in the
    # subgraph, and the source image all in there own geopandas dataframes
    intersection, proj_gdf, source_gdf = compute_intersection(graph.nodes()[0], graph, clean_keys)

    # Get the intersection for the given subgrpah
    intersection_ind = intersection.query('overlaps_all == True').index.values[0]

    source_node = graph.nodes()[0]
    # Set the source, destination, edge, matches, and keypoints(kps) based on the first edge in the subgraph
    # which should be the smallest node in the graph

    for e in graph.edges():
        # Recompute the intersection if the source node of the n + 1 edge is different from the n edge
        if e[0] != source_node:
            source_node = e[0]
            intersection, proj_gdf, source_gdf = compute_intersection(source_node, graph, clean_keys)
            intersection_ind = intersection.query('overlaps_all == True').index.values[0]


        edge = graph.edge[e[0]][e[1]]
        matches, mask = edge.clean(clean_keys = clean_keys)
        kps = edge.get_keypoints('source', clean_keys = clean_keys, homogeneous = True)


        # Get all of the keypoints that are inside of the intersection then mask out the points
        # in kps that lie outside of the intersection
        # All of these operations on kps are extremely expensive
        kps['geometry'] = kps.apply(lambda x: Point(x['x'], x['y']), axis = 1)
        kps.mask = kps['geometry'].apply(lambda x: intersection.geometry.contains(x).all())
        kps.mask = kps['geometry'].apply(lambda x: intersection.geometry.contains(x).any())

        # Creates a mask for displaying the voronoi points
        # Currently erronious and produces NaN values
        # mask[mask] = kps.mask
        # edge.masks = ('voronoi', mask)

        keypoints = []
        kps[kps.mask].apply(lambda x: keypoints.append((x['x'], x['y'])), axis = 1)
        coords = source_gdf.geometry.apply(lambda x:scale(x, s, s).exterior.coords)

        for point in coords:
            keypoints = np.vstack((keypoints, point))
        scaled_coords = np.array(scale(source_gdf.geometry[0], s, s).exterior.coords)
        keypoints = np.vstack((keypoints, scaled_coords))

        vor = Voronoi(keypoints)

        # For weight computation
        # Should move to its own method
        voronoi_df = pd.DataFrame(data = kps, columns = ['x', 'y', 'weight'])

        i = 0
        vor_points = np.asarray(vor.points)
        for region in vor.regions:
            region_point = vor_points[np.argwhere(vor.point_region==i)]
            if not -1 in region:
                polygon_points = [vor.vertices[i] for i in region]
                if len(polygon_points) != 0:
                    polygon = Poly(polygon_points)
                    poly_area = polygon.intersection(intersection.geometry[intersection_ind]).area
                    voronoi_df.loc[(voronoi_df["x"] == region_point[0][0][0]) &
                                   (voronoi_df["y"] == region_point[0][0][1]),
                                   'weight'] = poly_area
            i+=1

        edge['weights']['vor_weight'] = voronoi_df['weight']
```

%% Cell type:code id: tags:

``` python
#Point to the adjacency Graph
adjacency = get_path('vor_adjacency1.json')
basepath = get_path('Apollo15')
cang = CandidateGraph.from_adjacency(adjacency, basepath=basepath)

#Apply SIFT to extract f"eatures
cang.extract_features(method='sift', extractor_parameters={'nfeatures':1500})

#Match
cang.match()

#Apply outlier detection
# cg.apply_func_to_edges(Edge.symmetry_check)
cang.symmetry_checks()
# cg.apply_func_to_edges(Edge.ratio_check)
cang.ratio_checks()


#Compute a homography and apply RANSAC
cang.apply_func_to_edges("compute_fundamental_matrix", clean_keys=['ratio', 'symmetry'])
```

%% Output

    /home/acpaquette/autocnet/autocnet/transformation/fundamental_matrix.py:252: UserWarning: Unable to apply MLE.  Not enough correspondences.  Returning with a RANSAC computed F matrix.
      warnings.warn("Unable to apply MLE.  Not enough correspondences.  Returning with a RANSAC computed F matrix.")

%% Cell type:code id: tags:

``` python
def compute_weights(cang, clean_keys = [], node_id=None, clique = False,):
    if clique:
        cliques = compute_cliques(cang, node_id)
        for g in cliques:
            subgraph = cang.create_node_subgraph(g)
            cg.vor(subgraph, clean_keys)
    else:
        for e in cang.edges_iter():
            subgraph = cang.create_node_subgraph(e)
            cg.vor(subgraph, clean_keys)
def compute_weights(graph, clean_keys = [], node_id=None, clique = False,):
    vor(graph, clean_keys)
```

%% Cell type:code id: tags:

``` python
def compute_cliques(graph, node_id):
def compute_cliques(graph, node_id=None):
    if node_id is not None:
        return list(nx.cliques_containing_node(graph, nodes=node_id))
    else:
        return list(nx.find_cliques(graph))
```

%% Cell type:code id: tags:

``` python
start = time.clock()
compute_weights(cang, clique = True, clean_keys = ['fundamental'])
print(time.clock() - start)

start = time.clock()
compute_weights(cang, clique = False, clean_keys = ['fundamental'])
print(time.clock() - start)
cliques = compute_cliques(cang)
print(cliques)
```

%% Output

    3.1514979999999966
    2.8140520000000038
    [[3, 0, 2, 4], [3, 1], [3, 5], [6, 5, 7]]

%% Cell type:code id: tags:

``` python
start = time.clock()
cang.compute_vor_weight(clean_keys = ['fundamental'], clique = True)
cliques = compute_cliques(cang, node_id = None)
for g in cliques:
    subgraph = cang.create_node_subgraph(g)
    compute_weights(subgraph, clean_keys = ['fundamental'])
print(time.clock() - start)

start = time.clock()
compute_weights(cang, clean_keys = ['fundamental'])
print(time.clock() - start)

start = time.clock()
cang.compute_vor_weight(clean_keys = ['fundamental'], clique = False)
for e in cang.edges_iter():
    subgraph = cang.create_node_subgraph(e)
    compute_weights(subgraph, clean_keys = ['fundamental'])
print(time.clock() - start)
```

%% Output

    3.1148349999999994
    2.8084049999999934
    Getting CT
    CT <osgeo.osr.CoordinateTransformation; proxy of None >
    Getting CT
    CT <osgeo.osr.CoordinateTransformation; proxy of None >
    Getting CT
    CT <osgeo.osr.CoordinateTransformation; proxy of None >
    Getting CT
    CT <osgeo.osr.CoordinateTransformation; proxy of None >
    Getting CT
    CT <osgeo.osr.CoordinateTransformation; proxy of None >
    Getting CT
    CT <osgeo.osr.CoordinateTransformation; proxy of None >
    2.9781629999999986

    /scratch/anaconda3/envs/auto_c/lib/python3.5/site-packages/ipykernel/__main__.py:5: UserWarning: The given graph is not complete and may yield garbage.

    3.131468999999999
    3.0031290000000013
    <generator object <genexpr> at 0x7f5b138f4150>

%% Cell type:code id: tags:

``` python
# for e in cang.edges_iter():
#     print(e)

graph = nx.Graph()
graph.add_edge(cang.edge[0][2].source, cang.edge[0][2].destination)
cg.vor(graph, clean_keys, **kwargs)
```

%% Output

    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-19-c32bf03f050a> in <module>()
          3
          4 graph = nx.Graph()
    ----> 5 graph.add_edge(cang.edge[0][2].source, cang.edge[0][2].destination)
          6 cg.vor(graph, clean_keys, **kwargs)
    /scratch/anaconda3/envs/auto_c/lib/python3.5/site-packages/networkx/classes/graph.py in add_edge(self, u, v, attr_dict, **attr)
        789                     "The attr_dict argument must be a dictionary.")
        790         # add nodes
    --> 791         if u not in self.node:
        792             self.adj[u] = self.adjlist_dict_factory()
        793             self.node[u] = {}
    TypeError: unhashable type: 'Node'

%% Cell type:code id: tags:

``` python
source_keypoint_df = pd.DataFrame({'x': (15, 18, 18, 12, 12), 'y': (6, 10, 15, 15, 10)})
destination_keypoint_df = pd.DataFrame({'x': (5, 8, 8, 2, 2), 'y': (1, 5, 10, 10, 5)})
keypoint_matches = [[0, 0, 1, 0],
                    [0, 1, 1, 1],
                    [0, 2, 1, 2],
                    [0, 3, 1, 3],
                    [0, 4, 1, 4]]

matches_df = pd.DataFrame(data = keypoint_matches, columns = ['source_image', 'source_idx',
                                                                  'destination_image', 'destination_idx'])
# Source and Destination Node Setup
source_node = MagicMock(spec = Node())
destination_node = MagicMock(spec = Node())

source_node.get_keypoint_coordinates = MagicMock(return_value=source_keypoint_df)
destination_node.get_keypoint_coordinates = MagicMock(return_value=destination_keypoint_df)

source_geodata = Mock(spec = io_gdal.GeoDataset)
destination_geodata = Mock(spec = io_gdal.GeoDataset)

source_node.geodata = source_geodata
destination_node.geodata = destination_geodata

source_node.geodata.coordinate_transformation.this = None
destination_node.geodata.coordinate_transformation.this = None

source_corners = [(0, 0),
                  (20, 0),
                  (20, 20),
                  (0, 20)]

destination_corners = [(0, 0),
                       (20, 0),
                       (20, 20),
                       (0, 20)]

source_node.geodata.xy_corners = source_corners
destination_node.geodata.xy_corners = destination_corners

# Edge Setup
e = edge.Edge(source = source_node, destination = destination_node)

e.clean = MagicMock(return_value=(matches_df, None))
e.matches = matches_df

def side_effect(node, clean_keys, **kwargs):
    if type(node) is str:
        node = node.lower()

    if isinstance(node, Node):
        node = node['node_id']

    if node == "source" or node == "s" or node == source_node['node_id']:
        return e.source.get_keypoint_coordinates().copy(deep=True)
    if node == "destination" or node == "d" or node == destination_node['node_id']:
        return e.destination.get_keypoint_coordinates().copy(deep=True)

my_dict_source = {'node_id':0}

def getitem_source(name):
    return my_dict_source[name]

my_dict_destination = {'node_id':1}

def getitem_destination(name):
    return my_dict_destination[name]

source_node.__getitem__.side_effect = getitem_source
destination_node.__getitem__.side_effect = getitem_destination

e.get_keypoints = MagicMock(side_effect = side_effect)

cang = MagicMock(spec = CandidateGraph())

cang.nodes = MagicMock(return_value=([0, 1]))
cang.node = [source_node, destination_node]
cang.nodes_iter = MagicMock(return_value=([0, 1]))
cang.neighbors = MagicMock(return_value = [1])
cang.edges = MagicMock(return_value=([(0, 1)]))
cang.edge = {0:{1:e}, 1:{0:e}}
```

%% Cell type:code id: tags:

``` python
start = time.clock()
vor(cang, clean_keys = ['fundamental'])
compute_weights(cang, clean_keys = ['fundamental'])
print(time.clock() - start)
print(e['weights'])
```

%% Output

    0.031369000000001535
    {'vor_weight': 0    22.50
    1    26.25
    2    37.50
    3    37.50
    4    26.25
    Name: weight, dtype: float64}

%% Cell type:code id: tags:

``` python
# adjacency = get_path('two_image_adjacency.json')
# basepath = get_path('Apollo15')
# cg = CandidateGraph.from_adjacency(adjacency, basepath=basepath)
keypoint_df = pd.DataFrame({'x': (15, 18, 18, 12, 12), 'y': (6, 10, 15, 15, 10)})
keypoint_matches = [[0, 0, 1, 0],
                    [0, 1, 1, 1],
                    [0, 2, 1, 2],
                    [0, 3, 1, 3],
                    [0, 4, 1, 4]]

matches_df = pd.DataFrame(data = keypoint_matches, columns = ['source_image', 'source_idx',
                                                                  'destination_image', 'destination_idx'])
e = edge.Edge(source = source_node, destination = destination_node)

e.clean = MagicMock(return_value=(matches_df, None))
e.matches = matches_df

source_node = MagicMock(spec = node.Node())
destination_node = MagicMock(spec = node.Node())

cang = MagicMock(spec = CandidateGraph())

cang.nodes = MagicMock(return_value=([0, 1]))
cang.node = [source_node, destination_node]
cang.nodes_iter = MagicMock(return_value=([0, 1]))
cang.neighbors = MagicMock(return_value=([0]))
cang.edges = MagicMock(return_value=([(0, 1)]))
cang.edge = {0:{1:e}, 1:{0:e}}

source_node.get_keypoint_coordinates = MagicMock(return_value=keypoint_df)
destination_node.get_keypoint_coordinates = MagicMock(return_value=keypoint_df)
source_node['node_id'] = 0
destination_node['node_id'] = 1

def side_effect(node, clean_keys, **kwargs):
    if type(node) is str:
        node = node.lower()

    if isinstance(node, Node):
        node = node['node_id']

    if node == "source" or node == "s" or node == source_node['node_id']:
        return e.source.get_keypoint_coordinates()
    if node == "destination" or node == "d" or node == destination_node['node_id']:
        return e.destination.get_keypoint_coordinates()

e.get_keypoints = MagicMock(side_effect = side_effect)

e.source = source_node
e.destination = destination_node

source_geodata = Mock(spec = io_gdal.GeoDataset)
destination_geodata = Mock(spec = io_gdal.GeoDataset)

e.source.geodata = source_geodata
e.destination.geodata = destination_geodata

source_corners = [(0, 0),
                  (20, 0),
                  (20, 20),
                  (0, 20)]

destination_corners = [(10, 5),
                       (30, 5),
                       (30, 25),
                       (10, 25)]

source_xy_extent = [(0, 20), (0, 20)]

destination_xy_extent = [(10, 30), (5, 25)]

source_poly = array_to_poly(source_corners)
destination_poly = array_to_poly(destination_corners)

vals = {(10, 5):(10, 5), (20, 5):(20, 5), (20, 20):(20, 20), (10, 20):(10, 20)}

def latlon_to_pixel(i, j):
    return vals[(i, j)]

my_dict_source = {'node_id':0}

def getitem_source(name):
    return my_dict_source[name]

my_dict_destination = {'node_id':1}

def getitem_destination(name):
    return my_dict_destination[name]

source_node.__getitem__.side_effect = getitem_source
destination_node.__getitem__.side_effect = getitem_destination

e.source.geodata.latlon_to_pixel = MagicMock(side_effect = latlon_to_pixel)
e.destination.geodata.latlon_to_pixel = MagicMock(side_effect = latlon_to_pixel)

e.source.geodata.footprint = source_poly
e.source.geodata.xy_corners = source_corners
e.source.geodata.xy_extent = source_xy_extent
e.destination.geodata.footprint = destination_poly
e.destination.geodata.xy_corners = destination_corners
e.destination.geodata.xy_extent = destination_xy_extent
```

%% Cell type:code id: tags:

``` python
start = time.clock()
vor(cang, clean_keys = ['fundamental'])
print(time.clock() - start)
print(e['weights'])
```

%% Output

    0.03340599999999938
    {'vor_weight': 0    22.50
    1    26.25
    2    37.50
    3    37.50
    4    26.25
    Name: weight, dtype: float64}

%% Cell type:code id: tags:

``` python
```

%% Cell type:code id: tags:

``` python
def vor_plot(graph, clean_keys = []):

    num_neighbors = len(graph.nodes()) - 1
    for n in graph.nodes():
        neighbors = len(graph.neighbors(n))
        if neighbors != num_neighbors:
            raise AssertionError('The graph is not complete')

    intersection, proj_gdf, source_gdf = compute_intersection(graph.nodes()[0], graph, clean_keys)

    source_node = graph.nodes()[0]

    for e in graph.edges():
        if e[0] != source_node:
            source_node = e[0]
            start_inter = time.clock()
            intersection, proj_gdf, source_gdf = compute_intersection(source_node, graph, clean_keys)

        edge = graph.edge[e[0]][e[1]]
        kps = edge.get_keypoints('source', clean_keys = clean_keys, homogeneous = True)
        kps = kps[edge.vor_mask]

        vor = edge.voronoi

        i = 0
        poly_array = []
        vor_points = np.asarray(vor.points)
        for region in vor.regions:
            region_point = vor_points[np.argwhere(vor.point_region==i)]
            if not -1 in region:
                polygon_points = [vor.vertices[i] for i in region]
                if len(polygon_points) != 0:
                    polygon = Poly(polygon_points)
                    poly_array.append(polygon)
            i+=1

        poly_gdf = gpd.GeoDataFrame(data = poly_array, columns = ['geometry'])
        vor_poly_gdf = gpd.overlay(poly_gdf, intersection, how='intersection')

        ax = proj_gdf.query('proj_node != ' + str(n)).plot(color='#388aff', alpha=0.1)
        proj_gdf.query('proj_node == ' + str(n)).plot(color = 'g', alpha=0.1, ax = ax)
        source_gdf.plot(color='r', alpha=0.1, ax=ax)
        vor_poly_gdf.plot(cmap='Set1', alpha=.5, ax=ax)
#             graph.edge[0][3].plot(clean_keys = ['fundamental'], ax = ax)
        edge.source.plot(index_mask = edge.matches['destination_idx'], alpha = 0)
        matplotlib.pyplot.scatter(kps['x'], kps['y'], color = 'black', alpha = 1)
```
+7 −7

File changed.

Contains only whitespace changes.