Interactive graph visualization for Python notebooks using anywidget
Project description
anywidget-graph
Interactive graph visualization for Python notebooks.
Works with Marimo, Jupyter, VS Code, Colab, anywhere anywidget runs.
Features
- Universal: One widget, every notebook environment
- Backend-agnostic: Grafeo, Neo4j, NetworkX, pandas, or raw dicts
- Interactive: Pan, zoom, click, drag, pin, expand neighbors, box select
- Customizable: Colors, sizes, layouts, dark mode
- Exportable: HTML, JSON
Installation
uv add anywidget-graph
Optional extras:
uv add "anywidget-graph[networkx]" # NetworkX support
uv add "anywidget-graph[pandas]" # pandas support
uv add "anywidget-graph[grafeo]" # Grafeo backend
uv add "anywidget-graph[cosmosdb]" # CosmosDB / Gremlin support
Quick Start
from anywidget_graph import Graph
graph = Graph.from_dict({
"nodes": [
{"id": "alice", "label": "Alice", "group": "person"},
{"id": "bob", "label": "Bob", "group": "person"},
{"id": "paper", "label": "Graph Theory", "group": "document"},
],
"edges": [
{"source": "alice", "target": "bob", "label": "knows"},
{"source": "alice", "target": "paper", "label": "authored"},
]
})
graph
Data Sources
Dictionary
graph = Graph.from_dict({
"nodes": [{"id": "a"}, {"id": "b"}],
"edges": [{"source": "a", "target": "b"}]
})
Direct initialization
graph = Graph(
nodes=[{"id": "a", "label": "Alice"}, {"id": "b", "label": "Bob"}],
edges=[{"source": "a", "target": "b", "label": "KNOWS"}],
)
Cypher results (Neo4j)
from neo4j import GraphDatabase
driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))
with driver.session() as session:
result = session.run("MATCH (a)-[r]->(b) RETURN a, r, b LIMIT 100")
graph = Graph.from_cypher(result)
GQL results
graph = Graph.from_gql(result)
SPARQL results
from rdflib import Graph as RDFGraph
g = RDFGraph()
g.parse("data.ttl")
result = g.query("SELECT ?s ?p ?o WHERE { ?s ?p ?o }")
graph = Graph.from_sparql(result)
Gremlin results (CosmosDB, TinkerPop)
graph = Graph.from_gremlin(result)
GraphQL results
graph = Graph.from_graphql(
response.json(),
nodes_path="data.characters.results",
id_field="id",
label_field="name",
)
NetworkX
import networkx as nx
G = nx.karate_club_graph()
graph = Graph.from_networkx(G)
pandas DataFrames
import pandas as pd
nodes_df = pd.DataFrame({"id": ["alice", "bob"], "group": ["person", "person"]})
edges_df = pd.DataFrame({"source": ["alice"], "target": ["bob"], "weight": [1.0]})
graph = Graph.from_dataframe(nodes_df, edges_df)
Interactivity
Events
graph = Graph.from_dict(data)
@graph.on_node_click
def handle_node(node_id, node_data):
print(f"Clicked: {node_id}")
@graph.on_edge_click
def handle_edge(edge_data):
print(f"Edge: {edge_data['label']}")
@graph.on_selection
def handle_selection(node_ids):
print(f"Selected: {node_ids}")
Selection
graph.selected_nodes # Current selection (list of IDs)
graph.selection_mode = "box" # Switch to box-select mode
Node expansion
graph.expand_node("alice") # Fetch and merge neighbors (requires backend)
Node pinning
graph.pin_nodes(["alice", "bob"]) # Pin at current positions
graph.unpin_nodes(["alice"]) # Release back to layout
graph.toggle_pin("bob") # Toggle pin state
graph.unpin_all() # Unpin everything
Clear
graph.clear() # Remove all nodes, edges, pins, and selection
Styling
Property-based coloring
graph = Graph.from_dict(
data,
color_field="group", # Color nodes by field
color_scale="viridis", # Scale: viridis, plasma, inferno, magma, cividis, turbo
size_field="score", # Size nodes by field
size_range=[5, 30], # Min/max node size
)
Edge styling
graph.edge_color_field = "type"
graph.edge_color_scale = "plasma"
graph.edge_size_field = "weight"
graph.edge_size_range = [1, 8]
Layouts
Graph.from_dict(data, layout="force") # ForceAtlas2 (default)
Graph.from_dict(data, layout="circular")
Graph.from_dict(data, layout="random")
Options
graph = Graph(
nodes=nodes,
edges=edges,
width=800, # Widget width (px)
height=600, # Widget height (px)
background="#fafafa", # Background color
show_labels=True, # Node labels
show_edge_labels=False, # Edge labels
show_toolbar=True, # Toolbar visibility
show_settings=True, # Settings panel
show_query_input=True, # Query input box
dark_mode=True, # Dark theme
show_tooltip=True, # Hover tooltips
tooltip_fields=["label", "id"],
max_nodes=300, # Limit for node expansion
)
Database Backends
Grafeo (default)
import grafeo
db = grafeo.GrafeoDB()
graph = Graph(database_backend="grafeo", grafeo_db=db)
Neo4j (browser-side)
graph = Graph(
database_backend="neo4j",
connection_uri="neo4j+s://demo.neo4jlabs.com",
connection_username="neo4j",
connection_password="password",
)
Generic backend
graph = Graph(backend=my_backend) # Any object implementing DatabaseBackend protocol
Export
graph.to_json() # JSON string with nodes and edges
graph.to_html() # Self-contained HTML string
graph.to_html(title="My Graph") # Custom title
graph.save_html("graph.html") # Write HTML to file
Environment Support
| Environment | Supported |
|---|---|
| Marimo | Yes |
| JupyterLab | Yes |
| Jupyter Notebook | Yes |
| VS Code | Yes |
| Google Colab | Yes |
| Databricks | Yes |
Related
- anywidget, custom Jupyter widgets made easy
- Grafeo, embeddable graph database
- grafeo-web, Grafeo in the browser
- Playground, interactive browser playground for Grafeo
License
Apache-2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file anywidget_graph-0.2.9.tar.gz.
File metadata
- Download URL: anywidget_graph-0.2.9.tar.gz
- Upload date:
- Size: 153.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57cc2e55d4071bf4c33b723943d4d43b94fbf4b7f7586c347dfcc3d397b5f5fa
|
|
| MD5 |
3cb012ebc50e014829c7697cd847e840
|
|
| BLAKE2b-256 |
bd4a7befcfca43e7a8920f07e4401d4e7fe5e0220e87ee02ae61924d39b63d8a
|
Provenance
The following attestation bundles were made for anywidget_graph-0.2.9.tar.gz:
Publisher:
pypi.yml on GrafeoDB/anywidget-graph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
anywidget_graph-0.2.9.tar.gz -
Subject digest:
57cc2e55d4071bf4c33b723943d4d43b94fbf4b7f7586c347dfcc3d397b5f5fa - Sigstore transparency entry: 1107809965
- Sigstore integration time:
-
Permalink:
GrafeoDB/anywidget-graph@b9d3cefa1065704044ebd3d8f27a21da5ba3cba8 -
Branch / Tag:
refs/tags/v0.2.9 - Owner: https://github.com/GrafeoDB
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@b9d3cefa1065704044ebd3d8f27a21da5ba3cba8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file anywidget_graph-0.2.9-py3-none-any.whl.
File metadata
- Download URL: anywidget_graph-0.2.9-py3-none-any.whl
- Upload date:
- Size: 73.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c08ad712b0af2ee8f8c9ccf965ecdd15c6b6363104c8ff5b9d8ffc7a508fadc6
|
|
| MD5 |
45b66d98bd45deed656a604dfba34e90
|
|
| BLAKE2b-256 |
31fbf70b59fcd3f7ea673e57cf45c619c16ccea10e88a8b148037995fd87554c
|
Provenance
The following attestation bundles were made for anywidget_graph-0.2.9-py3-none-any.whl:
Publisher:
pypi.yml on GrafeoDB/anywidget-graph
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
anywidget_graph-0.2.9-py3-none-any.whl -
Subject digest:
c08ad712b0af2ee8f8c9ccf965ecdd15c6b6363104c8ff5b9d8ffc7a508fadc6 - Sigstore transparency entry: 1107809967
- Sigstore integration time:
-
Permalink:
GrafeoDB/anywidget-graph@b9d3cefa1065704044ebd3d8f27a21da5ba3cba8 -
Branch / Tag:
refs/tags/v0.2.9 - Owner: https://github.com/GrafeoDB
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@b9d3cefa1065704044ebd3d8f27a21da5ba3cba8 -
Trigger Event:
release
-
Statement type: