Loading autocnet/graph/network.py +59 −150 Original line number Diff line number Diff line Loading @@ -236,175 +236,84 @@ class CandidateGraph(nx.Graph): matches.append(match) return matches '''def add_image(self, image_name, adjacency=None, basepath=None, apply_func=None): def add_node(self, n=None, **attr): """ Adds an image node to the graph. Parameters ---------- image_name : str The file name of or path to the image to add adjacency : string or Node list The list of adjacent Nodes or image files for this image The file name of the node adjacency : str list List of files names of adjacent images that correspond to names in CandidateGraph.graph["node_name_map"] basepath : str The directory path for the image apply_func : function A static function that takes an Edge as its parameter Function will be applied to all Edges generated when adding the image The base path to the node image file """ image_name = attr.pop("image_name", None) adj = attr.pop("adjacency", None) new_node = None # Check if image is already in the graph if image_name in self.nodes: warnings.warn("{} is already in the graph".format(image_name)) return # Basepath resolution if basepath: image_path = os.path.join(basepath, image_name) # If image name is provided, build the node from the image before # calling nx.add_node() if image_name is not None: if "basepath" in attr.keys(): image_path = os.path.join(attr.pop("basepath"), image_name) else: image_path = image_name image_name = os.path.basename(image_path) # Create new node within graph new_node = Node(image_name, image_path) new_node = self.add_node(image_name, data=new_node) # If adjacency supplied make sure it's the right type if adjacency: # Type check try: assert type(adjacency) is list except AssertionError: raise TypeError("Named parameter 'adjacency' must be a list of" "adjacent Node objects or list of adjacent " "images; Could not add {} to " "CandidateGraph".format(image_name)) # If adjacency not supplied, figure it out from footprints else: # Create empty adjacency list adjacency = list() # Make sure new node has valid footprint; If not, it will be a # disconnected node on the graph if not new_node.geodata.footprint or not \ new_node.geodata.footprint.IsValid(): warnings.warn('Missing or invalid geospatial data for ' '{0}; {0} will be added to the CandidateGraph' 'as a disconnected Node'.format(image_name)) if not os.path.exists(image_path): warnings.warn("Cannot find {}".format(image_path)) return # Detect adjacency between our new node and the CG's nodes target_nodes = [self.node[idx] for idx in self.nodes()] # This is broken too valid_datasets = list() datasets = [node.geodata for node in target_nodes] # Make sure target nodes have valid footprints for ds in datasets: # Skip the source node if it's in the list of target nodes if ds.file_name == new_node['image_path']: n = self.graph["node_counter"] self.graph["node_counter"] += 1 new_node = Node(image_name=image_name, image_path=image_path, node_id=n) self.graph["node_name_map"][new_node["image_name"]] = new_node["node_id"] attr["data"] = new_node # Add the new node to the graph using networkx super(CandidateGraph, self).add_node(n, **attr) # Populate adjacency, if provided if new_node is not None and adj is not None: for adj_img in adj: if adj_img not in self.graph["node_name_map"].keys(): warnings.warn("{} not found in the graph".format(adj_img)) continue # Grab footprints from nodes that have them fp = ds.footprint if fp and fp.IsValid(): valid_datasets.append(ds) else: warnings.warn('Missing or invalid geospatial data for ' '{}'.format(os.path.basename(ds.file_name))) new_idx = new_node["node_id"] adj_idx = self.graph["node_name_map"][adj_img] self.add_edge(adj_img, new_node["image_name"]) # Grab the footprints and test for intersection for ds in valid_datasets: ds_file_name = os.path.basename(ds.file_name) try: if new_node.geodata.footprint.Intersects(ds.footprint): adjacency.append(ds_file_name) except: warnings.warn('Failed to calculate intersection between {} ' 'and {}'.format(image_name, ds_file_name)) # Build new edge(s) from adjacency for a_img in adjacency: # If string (image name) if isinstance(a_img, str): if a_img > new_node['image_name']: a = new_node['image_name'] b = a_img else: a = a_img b = new_node['image_name'] edge = Edge(source=a, destination=b) self.add_edge() # If adjacent img is already in the graph if a_img in self.graph['node_name_map'].keys(): # Set the nodes for the new edge a_node_idx = self.graph['node_name_map'][a_img] s = self.node[a_node_idx] d = new_node # If adjacent img isnt already in graph, add it else: # Set the nodes for the new graph s = new_node d = add_node(os.path.join(basepath, a_img)) # If Node elif isinstance(a_img, Node): # If it's already in the graph, it'll be the source node, # since its idx is lower than our new node if a_img['image_name'] in [self.node[idx]['image_name'] for idx in self.nodes()]: s = a_img d = new_node # Otherwise, can't create edge else: warnings.warn("{0} is not in the graph; No Edge between" "{0} and {1} can be " "created".format(a_img['image_name'], image_name)) continue else: raise TypeError("Adjacency list contains Node objects or image " "names; Could not add {} to " "CandidateGraph".format(image_name)) # Create the new edge new_edge = Edge(s, d) # If there's a clean func for the new edge, apply it if apply_func: ERR = "Named parameter 'apply_func' must be a static " \ "function or list of static functions; These " \ "function(s) are applied to all new edges generated " \ "when adding {0}; Could not add {0} to " \ "CandidateGraph".format(image_name) # Type Check try: assert callable(apply_func) or type(apply_func) is list # If it's a function, apply it if callable(apply_func): apply_func(new_edge) # If it's a list of functions, apply all of them else: [func(new_edge) for func in apply_func] except AssertionError: raise TypeError(ERR) # Grab node ids s_id = s['node_id'] d_id = d['node_id'] def add_edge(self, u, v, **attr): """ Adds an edge with the given src and dst nodes to the graph # Make sure source node is a key in the edge lookup if s_id not in self.edge.keys(): self.edge[s_id] = dict() Parameters ---------- u : str The filename of the source image for the edge v : Node The filename of the destination image for the edge """ if ("node_name_map" in self.graph.keys() and u in self.graph["node_name_map"].keys() and v in self.graph["node_name_map"].keys()): # Grab node ids & create edge obj s_id = self.graph["node_name_map"][u] d_id = self.graph["node_name_map"][v] new_edge = Edge(self.node[s_id]["data"], self.node[d_id]["data"]) # Prepare data for networkx u = s_id v = d_id attr["data"] = new_edge # Add the new edge to the graph using networkx super(CandidateGraph, self).add_edge(u, v, **attr) # Add the new edge to the graph self.edge[s_id][d_id] = new_edge ''' def extract_features(self, band=1, *args, **kwargs): # pragma: no cover """ Extracts features from each image in the graph and uses the result to assign the Loading autocnet/graph/tests/test_network.py +47 −104 Original line number Diff line number Diff line Loading @@ -133,118 +133,61 @@ def test_from_adjacency(): for s, d, e in g.edges.data('data'): assert isinstance(e, edge.Edge) assert isinstance(g.nodes[s]['data'], node.Node) """ def test_add_image(graph): # apply_func def extract_and_match(edge): for n in [edge.source, edge.destination]: n.extract_features(n.get_array(band=1), extractor_parameters={'nfeatures': 800}) edge.match() def test_add_node(): basepath = get_path('Apollo15') cube_adjacency = {"AS15-M-0297_crop.cub": ["AS15-M-0298_crop.cub"], "AS15-M-0298_crop.cub": ["AS15-M-0297_crop.cub"]} cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) # Test with all optional args cub_img = "AS15-M-0299_crop.cub" png_img = "AS15-M-0299_SML.png" cub_adj = ["AS15-M-0298_crop.cub", "AS15-M-0297_crop.cub"] png_adj = ["AS15-M-0298_crop.cub", "AS15-M-0297_crop.cub"] cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=extract_and_match) # Assert everything worked properly assert cub_img in cang.graph['node_name_map'].keys() new_node_idx = cang.graph['node_name_map'][cub_img] assert new_node_idx in cang.node.keys() assert cang.node[new_node_idx]['image_name'] == cub_img assert sorted(cang.nodes()) == [0, 1, 2] assert sorted(cang.edges()) == [(0, 1), (0, 2), (1, 2)] assert cang[0][2].destination['image_name'] == cang.edge[0][2].destination['image_name'] == cub_img assert cang[1][2].destination['image_name'] == cang.edge[1][2].destination['image_name'] == cub_img # Test when img is already in graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_adj[0], basepath=basepath) # Test for file not found with pytest.raises(FileNotFoundError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, basepath=None) # Test with auto-detect adjacency cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, basepath=basepath) a = 'AS15-M-0297_crop.cub' b = 'AS15-M-0298_crop.cub' c = 'AS15-M-0299_crop.cub' adjacency = {a:[b], b:[a]} g = network.CandidateGraph.from_adjacency(adjacency, basepath=basepath) # Test auto-detect when there are nodes w/ invalid geospacial data cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=png_adj, basepath=basepath) # Invalid cang.add_image(cub_img, basepath=basepath) # Autodetect # Test without "image_name" arg (networkx parent method) g.add_node(2, data=node.Node(image_name=c, image_path=os.path.join(basepath, c), node_id=2)) assert len(g.nodes) == 3 assert g.node[2]["data"]["image_name"] == c # Test auto-detect when new node does not intersect # Need a non-intersecting cube file # Test with "image_name" (cg method) g = network.CandidateGraph.from_adjacency(adjacency, basepath=basepath) g.add_node(image_name=c, basepath=basepath) assert len(g.nodes) == 3 assert g.node[2]["data"]["image_name"] == c assert g.node[0].keys() == g.node[1].keys() == g.node[2].keys() # Test when adjacency is list of nodes cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cub_adj2 = [cang.node[0], cang.node[1]] cang.add_image(cub_img, adjacency=cub_adj2, basepath=basepath) # Test when "image_name" not found node_len = len(g.nodes) g.add_node(image_name="nonexistent.jpg") assert len(g.nodes) == node_len # Test when an adjacency node is not in graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cub_adj2 = [cang.node[0], cang.node[1]] not_there = node.Node("_" + cub_img, os.path.join(basepath, cub_img), 15) adj = [not_there] edges_bf = cang.edges() cang.add_image(cub_img, adjacency=adj, basepath=basepath) assert cang.edges() == edges_bf # Should be no change in edges # Test when adjacency is of wrong type with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=1, basepath=basepath) # Invalid with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=[1], basepath=basepath) # Invalid def test_add_edge(): basepath = get_path('Apollo15') a = 'AS15-M-0297_crop.cub' b = 'AS15-M-0298_crop.cub' c = 'AS15-M-0299_crop.cub' adjacency = {a:[b], b:[a]} c_adj = ['AS15-M-0297_crop.cub', 'AS15-M-0298_crop.cub'] g = network.CandidateGraph.from_adjacency(adjacency, basepath=basepath) g.add_node(image_name=c, basepath=basepath, adjacency=c_adj) # Test when no adjacency supplied, but image doesn't have footprint; # This results in a disconnected node added to the graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) edges_bf = cang.edges() cang.add_image(png_img, basepath=basepath) assert cang.edges() == edges_bf # Assert no change in edges # Test when adjacency includes a node not already in the graph adj = cub_adj adj.append("AS15-M-0300_crop.cub") cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=adj, basepath=basepath) assert len(g.edges) == 3 assert g.edges[0, 1]["data"].source == g.node[0]["data"] assert g.edges[0, 1]["data"].destination == g.node[1]["data"] assert g.edges[0, 2]["data"].source == g.node[0]["data"] assert g.edges[0, 2]["data"].destination == g.node[2]["data"] assert g.edges[1, 2]["data"].source == g.node[1]["data"] assert g.edges[1, 2]["data"].destination == g.node[2]["data"] assert g.edges[0, 1].keys() == g.edges[0, 2].keys() == g.edges[1, 2].keys() # Test when adj img not found g = network.CandidateGraph.from_adjacency(adjacency, basepath=basepath) edge_len = len(g.edges) g.add_node(image_name=c, basepath=basepath, adjacency=["nonexistent.jpg"]) assert len(g.edges) == edge_len # Test when apply_func is not a function / list of functions with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=1) with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=[extract_and_match, 1]) """ def test_equal(candidategraph): cg = copy.deepcopy(candidategraph) assert candidategraph == cg Loading Loading
autocnet/graph/network.py +59 −150 Original line number Diff line number Diff line Loading @@ -236,175 +236,84 @@ class CandidateGraph(nx.Graph): matches.append(match) return matches '''def add_image(self, image_name, adjacency=None, basepath=None, apply_func=None): def add_node(self, n=None, **attr): """ Adds an image node to the graph. Parameters ---------- image_name : str The file name of or path to the image to add adjacency : string or Node list The list of adjacent Nodes or image files for this image The file name of the node adjacency : str list List of files names of adjacent images that correspond to names in CandidateGraph.graph["node_name_map"] basepath : str The directory path for the image apply_func : function A static function that takes an Edge as its parameter Function will be applied to all Edges generated when adding the image The base path to the node image file """ image_name = attr.pop("image_name", None) adj = attr.pop("adjacency", None) new_node = None # Check if image is already in the graph if image_name in self.nodes: warnings.warn("{} is already in the graph".format(image_name)) return # Basepath resolution if basepath: image_path = os.path.join(basepath, image_name) # If image name is provided, build the node from the image before # calling nx.add_node() if image_name is not None: if "basepath" in attr.keys(): image_path = os.path.join(attr.pop("basepath"), image_name) else: image_path = image_name image_name = os.path.basename(image_path) # Create new node within graph new_node = Node(image_name, image_path) new_node = self.add_node(image_name, data=new_node) # If adjacency supplied make sure it's the right type if adjacency: # Type check try: assert type(adjacency) is list except AssertionError: raise TypeError("Named parameter 'adjacency' must be a list of" "adjacent Node objects or list of adjacent " "images; Could not add {} to " "CandidateGraph".format(image_name)) # If adjacency not supplied, figure it out from footprints else: # Create empty adjacency list adjacency = list() # Make sure new node has valid footprint; If not, it will be a # disconnected node on the graph if not new_node.geodata.footprint or not \ new_node.geodata.footprint.IsValid(): warnings.warn('Missing or invalid geospatial data for ' '{0}; {0} will be added to the CandidateGraph' 'as a disconnected Node'.format(image_name)) if not os.path.exists(image_path): warnings.warn("Cannot find {}".format(image_path)) return # Detect adjacency between our new node and the CG's nodes target_nodes = [self.node[idx] for idx in self.nodes()] # This is broken too valid_datasets = list() datasets = [node.geodata for node in target_nodes] # Make sure target nodes have valid footprints for ds in datasets: # Skip the source node if it's in the list of target nodes if ds.file_name == new_node['image_path']: n = self.graph["node_counter"] self.graph["node_counter"] += 1 new_node = Node(image_name=image_name, image_path=image_path, node_id=n) self.graph["node_name_map"][new_node["image_name"]] = new_node["node_id"] attr["data"] = new_node # Add the new node to the graph using networkx super(CandidateGraph, self).add_node(n, **attr) # Populate adjacency, if provided if new_node is not None and adj is not None: for adj_img in adj: if adj_img not in self.graph["node_name_map"].keys(): warnings.warn("{} not found in the graph".format(adj_img)) continue # Grab footprints from nodes that have them fp = ds.footprint if fp and fp.IsValid(): valid_datasets.append(ds) else: warnings.warn('Missing or invalid geospatial data for ' '{}'.format(os.path.basename(ds.file_name))) new_idx = new_node["node_id"] adj_idx = self.graph["node_name_map"][adj_img] self.add_edge(adj_img, new_node["image_name"]) # Grab the footprints and test for intersection for ds in valid_datasets: ds_file_name = os.path.basename(ds.file_name) try: if new_node.geodata.footprint.Intersects(ds.footprint): adjacency.append(ds_file_name) except: warnings.warn('Failed to calculate intersection between {} ' 'and {}'.format(image_name, ds_file_name)) # Build new edge(s) from adjacency for a_img in adjacency: # If string (image name) if isinstance(a_img, str): if a_img > new_node['image_name']: a = new_node['image_name'] b = a_img else: a = a_img b = new_node['image_name'] edge = Edge(source=a, destination=b) self.add_edge() # If adjacent img is already in the graph if a_img in self.graph['node_name_map'].keys(): # Set the nodes for the new edge a_node_idx = self.graph['node_name_map'][a_img] s = self.node[a_node_idx] d = new_node # If adjacent img isnt already in graph, add it else: # Set the nodes for the new graph s = new_node d = add_node(os.path.join(basepath, a_img)) # If Node elif isinstance(a_img, Node): # If it's already in the graph, it'll be the source node, # since its idx is lower than our new node if a_img['image_name'] in [self.node[idx]['image_name'] for idx in self.nodes()]: s = a_img d = new_node # Otherwise, can't create edge else: warnings.warn("{0} is not in the graph; No Edge between" "{0} and {1} can be " "created".format(a_img['image_name'], image_name)) continue else: raise TypeError("Adjacency list contains Node objects or image " "names; Could not add {} to " "CandidateGraph".format(image_name)) # Create the new edge new_edge = Edge(s, d) # If there's a clean func for the new edge, apply it if apply_func: ERR = "Named parameter 'apply_func' must be a static " \ "function or list of static functions; These " \ "function(s) are applied to all new edges generated " \ "when adding {0}; Could not add {0} to " \ "CandidateGraph".format(image_name) # Type Check try: assert callable(apply_func) or type(apply_func) is list # If it's a function, apply it if callable(apply_func): apply_func(new_edge) # If it's a list of functions, apply all of them else: [func(new_edge) for func in apply_func] except AssertionError: raise TypeError(ERR) # Grab node ids s_id = s['node_id'] d_id = d['node_id'] def add_edge(self, u, v, **attr): """ Adds an edge with the given src and dst nodes to the graph # Make sure source node is a key in the edge lookup if s_id not in self.edge.keys(): self.edge[s_id] = dict() Parameters ---------- u : str The filename of the source image for the edge v : Node The filename of the destination image for the edge """ if ("node_name_map" in self.graph.keys() and u in self.graph["node_name_map"].keys() and v in self.graph["node_name_map"].keys()): # Grab node ids & create edge obj s_id = self.graph["node_name_map"][u] d_id = self.graph["node_name_map"][v] new_edge = Edge(self.node[s_id]["data"], self.node[d_id]["data"]) # Prepare data for networkx u = s_id v = d_id attr["data"] = new_edge # Add the new edge to the graph using networkx super(CandidateGraph, self).add_edge(u, v, **attr) # Add the new edge to the graph self.edge[s_id][d_id] = new_edge ''' def extract_features(self, band=1, *args, **kwargs): # pragma: no cover """ Extracts features from each image in the graph and uses the result to assign the Loading
autocnet/graph/tests/test_network.py +47 −104 Original line number Diff line number Diff line Loading @@ -133,118 +133,61 @@ def test_from_adjacency(): for s, d, e in g.edges.data('data'): assert isinstance(e, edge.Edge) assert isinstance(g.nodes[s]['data'], node.Node) """ def test_add_image(graph): # apply_func def extract_and_match(edge): for n in [edge.source, edge.destination]: n.extract_features(n.get_array(band=1), extractor_parameters={'nfeatures': 800}) edge.match() def test_add_node(): basepath = get_path('Apollo15') cube_adjacency = {"AS15-M-0297_crop.cub": ["AS15-M-0298_crop.cub"], "AS15-M-0298_crop.cub": ["AS15-M-0297_crop.cub"]} cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) # Test with all optional args cub_img = "AS15-M-0299_crop.cub" png_img = "AS15-M-0299_SML.png" cub_adj = ["AS15-M-0298_crop.cub", "AS15-M-0297_crop.cub"] png_adj = ["AS15-M-0298_crop.cub", "AS15-M-0297_crop.cub"] cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=extract_and_match) # Assert everything worked properly assert cub_img in cang.graph['node_name_map'].keys() new_node_idx = cang.graph['node_name_map'][cub_img] assert new_node_idx in cang.node.keys() assert cang.node[new_node_idx]['image_name'] == cub_img assert sorted(cang.nodes()) == [0, 1, 2] assert sorted(cang.edges()) == [(0, 1), (0, 2), (1, 2)] assert cang[0][2].destination['image_name'] == cang.edge[0][2].destination['image_name'] == cub_img assert cang[1][2].destination['image_name'] == cang.edge[1][2].destination['image_name'] == cub_img # Test when img is already in graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_adj[0], basepath=basepath) # Test for file not found with pytest.raises(FileNotFoundError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, basepath=None) # Test with auto-detect adjacency cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, basepath=basepath) a = 'AS15-M-0297_crop.cub' b = 'AS15-M-0298_crop.cub' c = 'AS15-M-0299_crop.cub' adjacency = {a:[b], b:[a]} g = network.CandidateGraph.from_adjacency(adjacency, basepath=basepath) # Test auto-detect when there are nodes w/ invalid geospacial data cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=png_adj, basepath=basepath) # Invalid cang.add_image(cub_img, basepath=basepath) # Autodetect # Test without "image_name" arg (networkx parent method) g.add_node(2, data=node.Node(image_name=c, image_path=os.path.join(basepath, c), node_id=2)) assert len(g.nodes) == 3 assert g.node[2]["data"]["image_name"] == c # Test auto-detect when new node does not intersect # Need a non-intersecting cube file # Test with "image_name" (cg method) g = network.CandidateGraph.from_adjacency(adjacency, basepath=basepath) g.add_node(image_name=c, basepath=basepath) assert len(g.nodes) == 3 assert g.node[2]["data"]["image_name"] == c assert g.node[0].keys() == g.node[1].keys() == g.node[2].keys() # Test when adjacency is list of nodes cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cub_adj2 = [cang.node[0], cang.node[1]] cang.add_image(cub_img, adjacency=cub_adj2, basepath=basepath) # Test when "image_name" not found node_len = len(g.nodes) g.add_node(image_name="nonexistent.jpg") assert len(g.nodes) == node_len # Test when an adjacency node is not in graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cub_adj2 = [cang.node[0], cang.node[1]] not_there = node.Node("_" + cub_img, os.path.join(basepath, cub_img), 15) adj = [not_there] edges_bf = cang.edges() cang.add_image(cub_img, adjacency=adj, basepath=basepath) assert cang.edges() == edges_bf # Should be no change in edges # Test when adjacency is of wrong type with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=1, basepath=basepath) # Invalid with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=[1], basepath=basepath) # Invalid def test_add_edge(): basepath = get_path('Apollo15') a = 'AS15-M-0297_crop.cub' b = 'AS15-M-0298_crop.cub' c = 'AS15-M-0299_crop.cub' adjacency = {a:[b], b:[a]} c_adj = ['AS15-M-0297_crop.cub', 'AS15-M-0298_crop.cub'] g = network.CandidateGraph.from_adjacency(adjacency, basepath=basepath) g.add_node(image_name=c, basepath=basepath, adjacency=c_adj) # Test when no adjacency supplied, but image doesn't have footprint; # This results in a disconnected node added to the graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) edges_bf = cang.edges() cang.add_image(png_img, basepath=basepath) assert cang.edges() == edges_bf # Assert no change in edges # Test when adjacency includes a node not already in the graph adj = cub_adj adj.append("AS15-M-0300_crop.cub") cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=adj, basepath=basepath) assert len(g.edges) == 3 assert g.edges[0, 1]["data"].source == g.node[0]["data"] assert g.edges[0, 1]["data"].destination == g.node[1]["data"] assert g.edges[0, 2]["data"].source == g.node[0]["data"] assert g.edges[0, 2]["data"].destination == g.node[2]["data"] assert g.edges[1, 2]["data"].source == g.node[1]["data"] assert g.edges[1, 2]["data"].destination == g.node[2]["data"] assert g.edges[0, 1].keys() == g.edges[0, 2].keys() == g.edges[1, 2].keys() # Test when adj img not found g = network.CandidateGraph.from_adjacency(adjacency, basepath=basepath) edge_len = len(g.edges) g.add_node(image_name=c, basepath=basepath, adjacency=["nonexistent.jpg"]) assert len(g.edges) == edge_len # Test when apply_func is not a function / list of functions with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=1) with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=[extract_and_match, 1]) """ def test_equal(candidategraph): cg = copy.deepcopy(candidategraph) assert candidategraph == cg Loading