Metadata-Version: 2.4
Name: scivianna-graph
Version: 0.1.3
Summary: Build interactive ReactFlow graphs (rotatable nodes, drag-select, 4-side plugs) from a Python model.
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: panel>=1.5.0
Provides-Extra: plot
Requires-Dist: playwright; extra == "plot"
Requires-Dist: matplotlib; extra == "plot"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: playwright; extra == "test"
Requires-Dist: pillow; extra == "test"
Requires-Dist: matplotlib; extra == "test"

# scivianna-graph

Build interactive **ReactFlow** graphs from a plain-Python model. Each node is an
embedded Panel/Bokeh figure on a draggable, zoomable canvas - ideal for visualizing
the topology of coupled simulations or 1D pipe networks where the plots need to be
rotated, plugged on any side and rearranged by hand.

```python
from scivianna_graph import GraphModel, GraphNode, GraphEdge, SciviannaGraph

model = GraphModel()
model.add_node(GraphNode(id="core", position=(0, 0), label="Core", rotation=15))
model.add_node(GraphNode(id="assembly", position=(420, 0), label="Assembly"))
model.add_edge(
    GraphEdge(source="core", target="assembly",
              source_direction="right", target_direction="left")
)

SciviannaGraph(model).make_panel().servable()
```

## Features

- **Plugs on every side** - each node exposes handles on all four sides
  (`top`/`bottom`/`left`/`right`). An edge declares which side it attaches to on
  each endpoint, and directions are expressed in the node's own frame, so a pipe
  flows `right-out -> left-in` whatever its rotation.
- **Rotatable nodes** - rotate any node (border, handles and figure together) by an
  angle in degrees. An optional fixed pivot (`rotation_origin`) keeps a point in
  place while the node rotates - e.g. rotate a pipe about its inlet so pipes fan out
  radially.
- **Group drag-select** - drag an empty area of the canvas to marquee-select several
  nodes and move them together; drag a single node to reposition it.
- **Embedded figures** - each node renders any Panel viewable (typically a Bokeh
  figure). Give the viewable explicit `width`/`height` so the node is sized correctly.
- **Zoom, pan, minimap, controls** - standard ReactFlow navigation, all optional.

## Install

```bash
pip install scivianna-graph
```

The frontend bundle ships with the package, so no build step or network access is
needed at runtime.

## Usage

`GraphModel` is plain Python (no frontend required) and can be built, inspected and
serialized on its own:

```python
from scivianna_graph import GraphModel, GraphNode, GraphEdge

model = GraphModel()
model.add_node(GraphNode(id="a", position=(0, 0), label="Inlet",
                         view=bokeh_pane_a))          # optional embedded figure
model.add_node(GraphNode(id="b", position=(300, 0), label="Core",
                         rotation=90,                  # rotate about the centre ...
                         data={"rotation_origin": (0.5, 1.0)}))  # ... or about a pivot
model.add_edge(GraphEdge(source="a", target="b",
                         source_direction="right", target_direction="left"))

graph = SciviannaGraph(model)
graph.make_panel().servable()
```

Nodes may carry an embedded Panel viewable (e.g. a Bokeh figure wrapped in
`pn.pane.Bokeh`) via `GraphNode(view=...)`.

Display options are passed as `SciviannaGraph(...)` kwargs: `min_zoom`, `max_zoom`,
`show_controls`, `show_minimap`, `enable_multiselect`, `show_unconnected_ports`
(default false: only plugs used by an edge are drawn) and `rotation_origin` (default
pivot for every node).

## API

| Name | Purpose |
|------|---------|
| `GraphModel` | Container of nodes and edges; `add_node`, `add_edge`, `get_node`, `validate`, `to_dict`. |
| `GraphNode` | A node: `id`, `position`, optional `label`, `view`, `rotation`, `data`. |
| `GraphEdge` | A directed edge: `source`, `target`, `source_direction`, `target_direction`, optional `label`. |
| `SciviannaGraph` | Builds the canvas from a `GraphModel`; `set_model`, `make_panel`, and in-place `set_node_*` / `set_edge_*` helpers. |

## Development

The frontend is a standalone React app (`src/scivianna_graph/dist/app.jsx`) compiled
to `SciviannaGraphCanvas.bundle.js` (+ `.bundle.css`). To rebuild it after editing the
JSX, run from the repository root:

```bash
./build.sh            # or: npm run build
```

`build.sh` runs `npm install` (local esbuild) and then `panel compile`. It needs node,
npm, network access for the first run, and `pip install panel`. Rebuild after every
change to `app.jsx`. Without a bundle, Panel compiles the JSX in the browser and fetches
`@xyflow/react` from esm.sh (needs network). See `AGENTS.md` for build notes and gotchas.
