def delete_layer(self, layer_name): """ Remove a GIS map Layer. .. note :: There is no Resource for this action so in the meantime we use the core py2neo cypher api. This will remove a representation of a GIS map Layer from the Neo4j data store - it will not remove any nodes you may have added to it. The operation removes the layer data from the internal GIS R-tree model and removes the layer's label from all nodes that exist on it. It does not destroy any Nodes on the DB - use the standard py2neo library for these actions. :Raises: LayerNotFoundError if the index does not exist. """ if not self._layer_exists(layer_name): raise LayerNotFoundError( 'Layer Not Found: "{}"'.format(layer_name)) graph = self.graph # remove labels and properties on Nodes relating to this layer query = ("MATCH (n:{layer_name}) " "REMOVE n:{default_label} " "REMOVE n:{layer_name} " "REMOVE n:{point_label} " "REMOVE n:{multipolygon_label} " "REMOVE n.{internal_name}".format( layer_name=layer_name, default_label=DEFAULT_LABEL, point_label=POINT, multipolygon_label=MULTIPOLYGON, internal_name=NAME_PROPERTY)) graph.cypher.execute(query) # remove the bounding box, metadata and root from the rtree index query = ( "MATCH (l { layer:{layer_name} })-[r_layer:LAYER]-(), " "(metadata)<-[r_meta:RTREE_METADATA]-(l), " "()-[locate_rel:LOCATES]-(geometry_node)-[r_ref:RTREE_REFERENCE]-" "(bounding_box)-[r_root:RTREE_ROOT]-(l) " "DELETE locate_rel, r_meta, r_layer, r_ref, r_root, " "metadata, geometry_node, bounding_box, l") params = {'layer_name': layer_name} graph.cypher.execute(query, params)
def delete_geometry(self, geometry_name, wkt_string, layer_name): """ Remove a geometry node from a GIS map layer. .. note :: There is no Resource for this action so in the meantime we use the core py2neo cypher api. :Params: geometry_name : str The unique name of the geometry to delete. wkt_string : str A Well Known Text string of any geometry layer_name : str The name of the layer/index to remove the geometry from. :Raises: LayerNotFoundError if the index does not exist. InvalidWKTError if the WKT cannot be read. """ if not self._layer_exists(layer_name): raise LayerNotFoundError( 'Layer Not Found: "{}"'.format(layer_name)) graph = self.graph shape = self._get_shape_from_wkt(wkt_string) # remove the node from the graph match = "MATCH (n:{label}".format(label=shape.type) query = match + ("{ _py2neo_geometry_name:{geometry_name} }) " "OPTIONAL MATCH n<-[r]-() " "DELETE r, n") params = { 'label': shape.type, 'geometry_name': geometry_name, } graph.cypher.execute(query, params) # tidy up the index. This will remove the node, # it's bounding box node, and the relationship between them. query = ("MATCH (l { layer:{layer_name} }), " "(n { wkt:{wkt} })-[ref:RTREE_REFERENCE]-() " "DELETE ref, n") params = { 'layer_name': layer_name, 'wkt': shape.wkt, } graph.cypher.execute(query, params)
def find_within_distance(self, layer_name, coords, distance): """ Find all points of interest (poi) within a given distance from a lat-lon location coord. :Params: layer_name : str The name of the layer/index to remove the geometry from. coords : tuple WGS84 (EPSG 4326) lat, lon pair Latitude is a decimal number between -90.0 and 90.0 Longitude is a decimal number between -180.0 and 180.0 distance : int The radius of the search area in Kilometres (km) :Raises: LayerNotFoundError if the index does not exist. :Returns: a list of all matched nodes """ if not self._layer_exists(layer_name): raise LayerNotFoundError( 'Layer Not Found: "{}"'.format(layer_name)) resource = self.resources['findGeometriesWithinDistance'] shape = parse_lat_long(coords) spatial_data = { 'pointX': shape.x, 'pointY': shape.y, 'layer': layer_name, 'distanceInKm': distance, } nodes = self._execute_spatial_request(resource, spatial_data) return nodes
def create_geometry(self, geometry_name, wkt_string, layer_name, labels=None, node_id=None, spatial_id=None): """ Create a geometry of type Well Known Text (WKT). Internally this creates a node in your graph with a wkt property and also adds it to a GIS map layer (an index). Optionaly add Labels to the Node. :Params: geometry_name : str A unique name for the geometry. wkt_string : str A Well Known Text string of any geometry layer_name : str The name of the layer to add the geometry to. labels : list Optional list of Label names to apply to the geometry Node. node_id : int Optional - the internal ID used by neo4j to uniquely identify a Node. When provided, an update operation in the application graph will be carried out instead of the usual create, making this Node spatially aware by adding a 'wkt' property to it. It is then added to the Layer (indexed) as normal. :Raises: LayerNotFoundError if the index does not exist. InvalidWKTError if the WKT cannot be read. """ if not self._layer_exists(layer_name): raise LayerNotFoundError( 'Layer Not Found: "{0}".', 'Use ``create_layer(layer_name="{0}"")`` first.'.format( layer_name)) shape = self._get_shape_from_wkt(wkt_string) if self._geometry_exists(shape, geometry_name): raise GeometryExistsError( 'geometry already exists. ignoring request.') graph = self.graph resource = self.resources['addGeometryWKTToLayer'] labels = labels or [] labels.extend([DEFAULT_LABEL, layer_name, shape.type]) wkt = self._get_wkt_from_shape(shape) params = { NAME_PROPERTY: geometry_name, } if node_id: query = 'MATCH (n) WHERE id(n) = {node_id} RETURN n' params = {'node_id': node_id} results = graph.cypher.execute(query, params) if not results: raise NodeNotFoundError('Node not found: "{}"'.format(node_id)) record = results[0] node = record[0] node[NAME_PROPERTY] = geometry_name node.add_labels(*tuple(labels)) node.push() else: node = Node(*labels, **params) graph.create(node) spatial_data = { 'geometry': wkt, 'layer': layer_name, } resource.post(spatial_data) # now relate the geometry to our application node query = ( "MATCH (l { layer:{layer_name} })<-[r_layer:LAYER]-" "(root { name:'spatial_root' }), " "(bbox)-[r_root:RTREE_ROOT]-(l), " "(geometry_node)-[r_ref:RTREE_REFERENCE]-(bbox), " "(application_node { _py2neo_geometry_name:{geometry_name} }) " "WHERE geometry_node.wkt = {wkt} " "CREATE UNIQUE (geometry_node)-[:LOCATES]->(application_node)") params = { 'wkt': wkt, 'layer_name': layer_name, 'geometry_name': geometry_name, } graph.cypher.execute(query, params)