DSL Reference
Complete reference for the py3plex DSL (Domain-Specific Language) for querying multilayer networks.
Note
For task-oriented usage, see How to Query Multilayer Graphs with the SQL-like DSL. This page is a complete reference with all syntax and operators.
Overview
The py3plex DSL provides two interfaces:
String syntax: SQL-like queries for quick exploration
Builder API: Type-safe Python interface for production code
String Syntax Reference
Basic Structure
SELECT <target> [FROM <layers>] [WHERE <conditions>] [COMPUTE <metrics>] [ORDER BY <field>] [LIMIT <n>]
Targets
nodes— Select nodesedges— Select edges (experimental)
Layer Selection
FROM layer="layer_name"
FROM layers IN ("layer1", "layer2")
Conditions
Operators:
=— Equal>— Greater than<— Less than>=— Greater than or equal<=— Less than or equal!=— Not equal
Logical operators:
AND— Both conditions must be trueOR— Either condition must be true
Examples:
WHERE degree > 5
WHERE layer="friends" AND degree > 3
WHERE degree > 5 OR betweenness_centrality > 0.1
Compute Clause
Calculate metrics for selected nodes:
COMPUTE degree
COMPUTE degree COMPUTE betweenness_centrality
COMPUTE clustering
Available metrics:
degree— Node degreebetweenness_centrality— Betweenness centralitycloseness_centrality— Closeness centralityclustering— Clustering coefficientpagerank— PageRank scorelayer_count— Number of layers node appears in
See Algorithm Roadmap for complete metric list.
Order By
ORDER BY degree
ORDER BY -degree # Descending (prefix with -)
ORDER BY betweenness_centrality
Limit
LIMIT 10
LIMIT 100
Complete Examples
from py3plex.dsl import execute_query
# Get high-degree nodes
result = execute_query(
network,
'SELECT nodes WHERE degree > 5'
)
# Get nodes from specific layer
result = execute_query(
network,
'SELECT nodes FROM layer="friends" '
'WHERE degree > 3 '
'COMPUTE betweenness_centrality '
'ORDER BY -betweenness_centrality '
'LIMIT 10'
)
Builder API Reference
Import
from py3plex.dsl import Q, L
Query Construction
Start a query:
Q.nodes() # Select nodes
Q.edges() # Select edges (experimental)
Layer Selection
Single layer:
Q.nodes().from_layers(L["friends"])
Multiple layers (union):
Q.nodes().from_layers(L["friends"] + L["work"])
# Or use the new LayerSet algebra:
Q.nodes().from_layers(L["friends | work"])
Layer intersection:
Q.nodes().from_layers(L["friends"] & L["work"])
Advanced Layer Set Algebra:
# All layers except coupling
Q.nodes().from_layers(L["* - coupling"])
# Complex expressions with set operations
Q.nodes().from_layers(L["(social | work) & ~bots"])
# Named groups for reuse
from py3plex.dsl import LayerSet
LayerSet.define_group("bio", LayerSet("ppi") | LayerSet("gene"))
Q.nodes().from_layers(LayerSet("bio"))
See also
For complete documentation on layer set algebra including all operators, string parsing, named groups, and real-world examples, see: Layer Set Algebra
Filtering
Comparison operators:
Q.nodes().where(degree__gt=5) # Greater than
Q.nodes().where(degree__gte=5) # Greater than or equal
Q.nodes().where(degree__lt=5) # Less than
Q.nodes().where(degree__lte=5) # Less than or equal
Q.nodes().where(degree__eq=5) # Equal
Q.nodes().where(degree__ne=5) # Not equal
Multiple conditions:
Q.nodes().where(
degree__gt=5,
layer_count__gte=2
)
Computing Metrics
Q.nodes().compute("degree")
Q.nodes().compute("degree", "betweenness_centrality")
Sorting
Q.nodes().order_by("degree") # Ascending
Q.nodes().order_by("-degree") # Descending
Limiting
Q.nodes().limit(10)
Execution
result = Q.nodes().execute(network)
Chaining
All methods can be chained:
result = (
Q.nodes()
.from_layers(L["friends"])
.where(degree__gt=5)
.compute("betweenness_centrality")
.order_by("-betweenness_centrality")
.limit(10)
.execute(network)
)
Temporal Queries
Filter by Time Point
# String syntax
result = execute_query(
network,
'SELECT nodes AT "2024-01-15T10:00:00"'
)
# Builder API
result = (
Q.nodes()
.at("2024-01-15T10:00:00")
.execute(network)
)
Filter by Time Range
# String syntax
result = execute_query(
network,
'SELECT nodes DURING "2024-01-01" TO "2024-01-31"'
)
# Builder API
result = (
Q.nodes()
.during("2024-01-01", "2024-01-31")
.execute(network)
)
Temporal Edge Attributes
Edges can have temporal attributes:
t— Point in time (ISO 8601 timestamp)t_startandt_end— Time range
See Working with Networks for creating temporal networks.
Grouping and Coverage Queries
Per-Layer Grouping
Group results by layer and apply per-group operations:
# Group by layer
result = (
Q.nodes()
.from_layers(L["*"])
.compute("degree")
.per_layer() # Sugar for .group_by("layer")
.top_k(5, "degree") # Top 5 per layer
.end_grouping()
.execute(network)
)
Top-K Per Group
Select top-k items per group (requires prior grouping):
# Top 10 highest-degree nodes per layer
result = (
Q.nodes()
.from_layers(L["*"])
.compute("degree", "betweenness_centrality")
.per_layer()
.top_k(10, "degree")
.end_grouping()
.execute(network)
)
Coverage Filtering
Filter based on presence across groups:
Mode: “all” — Keep items appearing in ALL groups (intersection)
# Nodes that are top-5 hubs in ALL layers
multi_hubs = (
Q.nodes()
.from_layers(L["*"])
.compute("betweenness_centrality")
.per_layer()
.top_k(5, "betweenness_centrality")
.end_grouping()
.coverage(mode="all")
.execute(network)
)
Mode: “any” — Keep items appearing in AT LEAST ONE group (union)
# Nodes that are top-5 in any layer
any_hubs = (
Q.nodes()
.from_layers(L["*"])
.compute("degree")
.per_layer()
.top_k(5, "degree")
.end_grouping()
.coverage(mode="any")
.execute(network)
)
Mode: “at_least” — Keep items appearing in at least K groups
# Nodes in top-10 of at least 2 layers
two_layer_hubs = (
Q.nodes()
.from_layers(L["*"])
.compute("degree")
.per_layer()
.top_k(10, "degree")
.end_grouping()
.coverage(mode="at_least", k=2)
.execute(network)
)
Mode: “exact” — Keep items appearing in exactly K groups
# Layer specialists: top-5 in exactly 1 layer
specialists = (
Q.nodes()
.from_layers(L["*"])
.compute("betweenness_centrality")
.per_layer()
.top_k(5, "betweenness_centrality")
.end_grouping()
.coverage(mode="exact", k=1)
.execute(network)
)
Wildcard Layer Selection
Use L["*"] to select all layers:
# All layers
Q.nodes().from_layers(L["*"])
# All layers except "bots"
Q.nodes().from_layers(L["*"] - L["bots"])
# Layer algebra still works
Q.nodes().from_layers((L["*"] - L["spam"]) & L["verified"])
General Grouping
Group by arbitrary attributes (not just layer):
# Group by multiple attributes
result = (
Q.nodes()
.compute("degree", "community")
.group_by("layer", "community")
.top_k(3, "degree")
.end_grouping()
.execute(network)
)
Limitations
Coverage filtering is currently supported only for node queries
Edge queries with coverage will raise a clear
DslExecutionErrorGrouping requires computed attributes or inherent node properties (like layer)
Working with Results
Result Object
Query results are dictionaries mapping nodes to their computed attributes:
result = Q.nodes().compute("degree").execute(network)
# Access individual node
node = ('Alice', 'friends')
degree = result[node]['degree']
# Iterate
for node, data in result.items():
print(f"{node}: {data}")
Convert to Pandas
df = result.to_pandas()
print(df.head())
Extensibility
Custom Operators
Register custom DSL operators:
from py3plex.dsl import register_operator
@register_operator('my_metric')
def my_custom_metric(context, node):
"""Compute custom metric for a node."""
# Your implementation
return value
See Architecture and Design for plugin development.
Performance Considerations
Compute metrics once: Don’t recompute in multiple queries
Filter early: Use WHERE before COMPUTE
Limit results: Use LIMIT for large networks
Layer-specific: Query single layers when possible
Next Steps
Learn by doing: How to Query Multilayer Graphs with the SQL-like DSL
See examples: Examples & Recipes
Understand implementation: Architecture and Design