Interactive graph visualization for Python notebooks.
Works with Marimo, Jupyter, VS Code, Colab, anywhere anywidget runs.
- 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
uv add anywidget-graphOptional 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 supportfrom 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"},
]
})
graphgraph = Graph.from_dict({
"nodes": [{"id": "a"}, {"id": "b"}],
"edges": [{"source": "a", "target": "b"}]
})graph = Graph(
nodes=[{"id": "a", "label": "Alice"}, {"id": "b", "label": "Bob"}],
edges=[{"source": "a", "target": "b", "label": "KNOWS"}],
)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)graph = Graph.from_gql(result)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)graph = Graph.from_gremlin(result)graph = Graph.from_graphql(
response.json(),
nodes_path="data.characters.results",
id_field="id",
label_field="name",
)import networkx as nx
G = nx.karate_club_graph()
graph = Graph.from_networkx(G)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)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}")graph.selected_nodes # Current selection (list of IDs)
graph.selection_mode = "box" # Switch to box-select modegraph.expand_node("alice") # Fetch and merge neighbors (requires backend)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 everythinggraph.clear() # Remove all nodes, edges, pins, and selectiongraph = 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
)graph.edge_color_field = "type"
graph.edge_color_scale = "plasma"
graph.edge_size_field = "weight"
graph.edge_size_range = [1, 8]Graph.from_dict(data, layout="force") # ForceAtlas2 (default)
Graph.from_dict(data, layout="circular")
Graph.from_dict(data, layout="random")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
)import grafeo
db = grafeo.GrafeoDB()
graph = Graph(database_backend="grafeo", grafeo_db=db)graph = Graph(
database_backend="neo4j",
connection_uri="neo4j+s://demo.neo4jlabs.com",
connection_username="neo4j",
connection_password="password",
)graph = Graph(backend=my_backend) # Any object implementing DatabaseBackend protocolgraph.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 | Supported |
|---|---|
| Marimo | Yes |
| JupyterLab | Yes |
| Jupyter Notebook | Yes |
| VS Code | Yes |
| Google Colab | Yes |
| Databricks | Yes |
- anywidget, custom Jupyter widgets made easy
- Grafeo, embeddable graph database
- grafeo-web, Grafeo in the browser
Apache-2.0