From Cypher to Native Projection

Introduction

You’ve been using Cypher projections throughout this course.

cypher
Cypher projection
MATCH (source:Movie)-[r:IN_GENRE]->(target:Genre)
WITH gds.graph.project('movies-genres', source, target) AS g
RETURN g.graphName, g.nodeCount

Introduction

The Python client offers the same capabilities through gds.graph.project()—using Python dictionaries instead of Cypher syntax.

This lesson shows how to translate your Cypher projection knowledge into Python.

What You’ll Learn

By the end of this lesson, you’ll be able to:

  • Translate Cypher projections to Python syntax

  • Configure node and relationship properties in projections

  • Set relationship orientation (undirected, reverse)

  • Handle missing properties with default values

  • Choose between gds.graph.project() and gds.graph.cypher.project()

The Same Concepts, Different Syntax

Both approaches do the same thing:

  • Select nodes by label

  • Select relationships by type

  • Configure properties and orientation

  • Create an in-memory projection

The Python client translates your dictionary configuration into the equivalent Cypher projection.

Basic Projection: Cypher

cypher
Cypher projection
MATCH (source:Movie)-[r:IN_GENRE]->(target:Genre)
WITH gds.graph.project('movies-genres', source, target) AS g
RETURN g.graphName, g.nodeCount

Basic Projection: Python

python
Python equivalent
G, result = gds.graph.project( # (1)
    "movies-genres",      # Graph name
    ["Movie", "Genre"],   # Node labels  # (2)
    "IN_GENRE"            # Relationship type
)
  1. Returns a Graph object (G) and metadata (result) — use G for all subsequent operations

  2. Labels from the MATCH pattern become a list; the relationship type becomes a string argument

Basic Projection: The Pattern

The MATCH pattern (source:Movie)-[r:IN_GENRE]→(target:Genre) becomes two arguments:

  • The labels ["Movie", "Genre"]

  • The type "IN_GENRE"

What gds.graph.project() Returns

The method returns two values: a Graph object and projection metadata.

python
Unpacking the return values
G, result = gds.graph.project(
    "movies-genres",
    ["Movie", "Genre"],
    "IN_GENRE"
)

The Result Metadata

python
Accessing metadata
print(result["graphName"])           # 'movies-genres'
print(result["nodeCount"])           # Number of nodes
print(result["relationshipCount"])   # Number of relationships

Discarding Metadata

If you only need the Graph object use _ to discard the results metadata:

python
Discarding metadata
G, _ = gds.graph.project(
    "movies-genres",
    ["Movie", "Genre"],
    "IN_GENRE"
)

Multiple Labels and Types: Cypher

cypher
Multiple labels and types in Cypher
MATCH (source)-[r:ACTED_IN|RATED]->(target:Movie)
WHERE source:Actor OR source:User
WITH gds.graph.project('movie-interactions', source, target) AS g
RETURN g

Multiple Labels and Types: Python

python
Multiple labels and types in Python
G, _ = gds.graph.project(
    "movie-interactions",
    ["Actor", "User", "Movie"], # (1)
    ["ACTED_IN", "RATED"] # (2)
)
  1. All node labels from the Cypher WHERE source:Actor OR source:User pattern become a simple list

  2. Multiple relationship types from r:ACTED_IN|RATED also become a list

Adding Node Properties: Cypher

cypher
Node properties in Cypher
MATCH (source:Actor)-[r:ACTED_IN]->(target:Movie)
WITH gds.graph.project(
  'actors-movies-props',
  source, target,
  { sourceNodeProperties: source { .born },
    targetNodeProperties: target { .year, .imdbRating } }
) AS g
RETURN g

Adding Node Properties: Python

python
Node properties in Python
G, _ = gds.graph.project(
    "actors-movies-props",
    {
        "Actor": {}, # (1)
        "Movie": {"properties": ["year"]} # (2)
    },
    "ACTED_IN"
)
  1. Labels without properties use an empty dict {} — the label is still included in the projection

  2. When you need properties, the label becomes a dict key with a properties list

When you need properties, labels become dictionary keys with a properties list.

Relationship Properties: Cypher

cypher
Relationship properties in Cypher
MATCH (source:User)-[r:RATED]->(target:Movie)
WITH gds.graph.project(
  'user-ratings', source, target,
  { relationshipProperties: r { .rating } }
) AS g
RETURN g

Relationship Properties: Python

python
Relationship properties in Python
G, _ = gds.graph.project(
    "user-ratings",
    ["User", "Movie"],
    {"RATED": {"properties": ["rating"]}} # (1)
)
  1. Same pattern as nodes: when you need properties or configuration, the type string becomes a dictionary key with a properties list

Same pattern: when you need configuration, the type becomes a dictionary key.

Undirected Relationships: Cypher

cypher
Undirected in Cypher
MATCH (source:Actor)-[r:ACTED_IN]->(target:Movie)
WITH gds.graph.project(
  'actors-movies-undirected',
  source, target, {},
  { undirectedRelationshipTypes: ['ACTED_IN'] }
) AS g
RETURN g

Undirected Relationships: Python

python
Undirected in Python
G, _ = gds.graph.project(
    "actors-movies-undirected",
    ["Actor", "Movie"],
    {"ACTED_IN": {"orientation": "UNDIRECTED"}} # (1)
)
  1. orientation replaces the Cypher undirectedRelationshipTypes config — options are NATURAL, REVERSE, or UNDIRECTED

Orientation Options

  • NATURAL — Keep original direction (default)

  • REVERSE — Flip all directions

  • UNDIRECTED — Treat as bidirectional

Default Values for Missing Properties

Some nodes might be missing properties. Use defaultValue to handle nulls:

python
Handling missing properties
G, _ = gds.graph.project(
    "with-defaults",
    {
        "Actor": {
            "properties": {
                "born": {
                    "property": "born", # (1)
                    "defaultValue": 1900
                }
            }
        },
        "Movie": {
            "properties": {
                "year": {"defaultValue": 1900}, # (2)
                "imdbRating": {"defaultValue": 0.0},
                "runtime": {"defaultValue": 90}
            }
        }
    },
    {"ACTED_IN": {"orientation": "UNDIRECTED"}}
)
  1. Long form: property specifies the source property name, defaultValue provides a fallback for nulls

  2. Short form: when the projected property name matches the source, you can omit the property key

Default Values

Nodes missing the property use the default value instead of causing an error.

This mirrors the coalesce() function you used in Cypher projections.

Monopartite Transformations: Cypher

Creating an Actor-to-Actor network through shared Movies requires a complex MATCH pattern.

cypher
Monopartite in Cypher
MATCH (source:Actor)-[:ACTED_IN]->(:Movie)<-[:ACTED_IN]-(target:Actor)
WITH gds.graph.project('actor-collab', source, target) AS g
RETURN g

Monopartite Transformations: Python

The gds.graph.project() method only handles direct label/type projections.

For pattern-based transformations, use gds.graph.cypher.project():

python
Monopartite in Python
G, result = gds.graph.cypher.project( # (1)
    """
    MATCH (source:Actor)-[:ACTED_IN]->(:Movie)<-[:ACTED_IN]-(target:Actor)
    RETURN gds.graph.project($graph_name, source, target) # (2)
    """,
    graph_name='actor-collab'
)
  1. gds.graph.cypher.project() accepts a Cypher query string — use this when native projection can’t express your pattern

  2. $graph_name is a parameterized variable passed as a keyword argument — avoids string injection

Alternative: run_cypher + graph.get()

You can also run Cypher projection directly and retrieve the Graph object afterwards:

python
Running raw Cypher
result = gds.run_cypher(""" # (1)
    MATCH (source:Actor)-[:ACTED_IN]->(:Movie)<-[:ACTED_IN]-(target:Actor)
    WITH gds.graph.project('actor-collab-v2', source, target) AS g
    RETURN g.graphName, g.nodeCount, g.relationshipCount
""")
  1. Uses the exact same Cypher syntax from Module 2 — useful if you already have working Cypher projections you want to reuse

Retrieving the Graph Object

python
Retrieving an existing projection
G = gds.graph.get("actor-collab-v2")

print(f"Retrieved graph: {G.name()}")
print(f"Node count: {G.node_count()}")

This approach uses the exact Cypher syntax you already know.

Full Movies Graph Projection

python
Complete projection with all labels and types
G, result = gds.graph.project(
    "movies-full",
    {
        "Actor": {"properties": {"born": {"defaultValue": 1900}}},
        "User": {},
        "Movie": {"properties": {
            "imdbRating": {"defaultValue": 0.0},
            "year": {"defaultValue": 1900}
        }},
        "Genre": {} # (1)
    },
    {
        "ACTED_IN": {},
        "RATED": {"properties": {"rating": {"defaultValue": 0.0}}}, # (2)
        "IN_GENRE": {} # (3)
    }
)
  1. Labels without properties still need an entry — {} means "include all nodes with this label, no properties"

  2. Relationship properties follow the same defaultValue pattern as node properties

  3. Relationship types without special config use an empty dict — same pattern as labels

When to Use Each Method

Method Use when

gds.graph.project()

Projecting by labels and types directly

gds.graph.cypher.project()

Complex patterns, aggregation, filtering

run_cypher() + graph.get()

You prefer writing raw Cypher

When to Use Each Method

Most projections work with gds.graph.project().

Use the Cypher-based methods when you need pattern transformations like monopartite projections.

Translation Reference

Cypher Python

MATCH (source:Label)

"Label" or {"Label": {}}

sourceNodeProperties: source { .prop }

{"Label": {"properties": ["prop"]}}

relationshipProperties: r { .weight }

{"TYPE": {"properties": ["weight"]}}

undirectedRelationshipTypes: ['TYPE']

{"TYPE": {"orientation": "UNDIRECTED"}}

Complex MATCH patterns

gds.graph.cypher.project()

Summary

Translating Cypher projections to Python:

  • Labels and types become strings or lists for simple cases

  • Use dictionaries when you need properties or configuration

  • gds.graph.project() handles direct label/type projections

  • gds.graph.cypher.project() handles complex MATCH patterns

  • Use defaultValue to handle missing properties

Next: Running algorithms with the Python client.

Chatbot

How can I help you today?