Python with Neo4j
NOTE: The official Neo4j documentation and the Python library neo4j-driver offer detailed resources to explore further. You can use this GitHub Codespaces to practice with Neo4j https://github.com/voirinprof/gis_starter_neo4j_geolab. For setting up a Codespaces environment, see Getting Started with GitHub Codespaces.
Introduction to Neo4j
Neo4j is a graph-based database. It stores data as nodes (entities) and relationships (links), which is perfect for:
- Modeling networks (roads, rivers, infrastructure)
- Analyzing proximity and optimal paths
- Representing spatial information or mobility flows
In geomatics, Neo4j can be used for:
- Analyzing transport networks (buses, trains, bicycles)
- Managing flow graphs (e.g., hydrographic networks)
- Optimizing routes and exploring spatial connections
Installing the Python Driver
Install Neo4j Desktop or use Neo4j Aura (cloud service).
Installation of the Python neo4j
library:
pip install neo4j
Connecting to Neo4j in Python
from neo4j import GraphDatabase
# Connect to local Neo4j server
uri = "bolt://localhost:7687"
driver = GraphDatabase.driver(uri, auth=("neo4j", "your_password"))
# Simple function to test the connection
def test_connection(tx):
result = tx.run("RETURN 'Connection successful' AS message")
for record in result:
print(record["message"])
with driver.session() as session:
session.read_transaction(test_connection)
Tip: Protect your password with environment variables.
Modeling Geospatial Entities
Neo4j allows storing geographic coordinates directly in the properties of nodes.
Example: Adding cities with their positions
def add_city(tx, name, lon, lat):
tx.run(
"CREATE (v:City {name: $name, location: point({longitude: $lon, latitude: $lat})})",
name=name, lon=lon, lat=lat
)
with driver.session() as session:
session.write_transaction(add_city, "Paris", 2.3522, 48.8566)
session.write_transaction(add_city, "Lyon", 4.8357, 45.7640)
Creating Spatial Links Between Objects
You can link two cities with a “CONNECTED” relationship:
def link_cities(tx, city1, city2):
tx.run(
"""
MATCH (a:City {name: $city1}), (b:City {name: $city2})
CREATE (a)-[:CONNECTED]->(b)
""",
city1=city1, city2=city2
)
with driver.session() as session:
session.write_transaction(link_cities, "Paris", "Lyon")
In geomatics, this could model a road segment, railway line, or a hydrological link.
Searching for Nearby Entities
Neo4j allows spatial queries on the point
properties.
Example: Find all cities within 300 km of Paris:
def nearby_cities(tx, lon, lat, distance):
result = tx.run(
"""
MATCH (v:City)
WHERE distance(v.location, point({longitude: $lon, latitude: $lat})) < $distance
RETURN v.name AS name
""",
lon=lon, lat=lat, distance=distance
)
return [record["name"] for record in result]
with driver.session() as session:
cities = session.read_transaction(nearby_cities, 2.3522, 48.8566, 300000)
print(cities)
distance()
returns a distance in meters.
Use Cases in Geomatics
1. Transport Network Optimization
- Model stops as nodes.
- Link neighboring stops with relationships with a distance or time.
- Use shortest path algorithms (
shortestPath
) to find the optimal route.
2. Spatial Accessibility Analysis
- Define influence zones around specific points.
- Explore relationships between places based on spatial distances.
3. Representing Natural Networks
- Rivers, water flows, or drainage networks as directed graphs.
4. Flask Web Service with Neo4j
By combining Flask and Neo4j, you can set up a web service that leverages the graph database. Neo4j is very useful when you have a network with nodes and links.
You can add nodes to the graph.
@app.route('/locations/add', methods=['POST'])
def add_location():
data = request.get_json()
name = data.get('name')
lon = float(data.get('longitude'))
lat = float(data.get('latitude'))
if not all([name, lon, lat]):
return jsonify({"error": "Missing name, longitude, or latitude"}), 400
with driver.session() as session:
session.run(
"CREATE (p:Place {name: $name, longitude: $lon, latitude: $lat})",
name=name, lon=lon, lat=lat
)
return jsonify({"message": f"Added {name}"}), 201
See the example of a Flask web service combined with Neo4j https://github.com/voirinprof/neo4j_docker/
Best Practices
- Normalize your units: longitude/latitude in WGS84, distances in meters.
- Use explicit relationship types (
CONNECTED
,FLOW_TO
, etc.). - Index your properties if you have many nodes (
CREATE INDEX ON :City(name)
). - Use native spatial capabilities (e.g.,
point()
,distance()
) to optimize your queries.