streamlit-node-editor 0.3.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. streamlit_node_editor-0.3.2/PKG-INFO +395 -0
  2. streamlit_node_editor-0.3.2/README.md +369 -0
  3. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/setup.py +1 -1
  4. streamlit_node_editor-0.3.2/streamlit_node_editor.egg-info/PKG-INFO +395 -0
  5. streamlit_node_editor-0.3.0/PKG-INFO +0 -219
  6. streamlit_node_editor-0.3.0/README.md +0 -192
  7. streamlit_node_editor-0.3.0/streamlit_node_editor.egg-info/PKG-INFO +0 -219
  8. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/LICENSE +0 -0
  9. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/MANIFEST.in +0 -0
  10. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/setup.cfg +0 -0
  11. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor/__init__.py +0 -0
  12. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor/frontend/build/asset-manifest.json +0 -0
  13. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor/frontend/build/index.html +0 -0
  14. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor/frontend/build/static/js/main.766c23d5.js +0 -0
  15. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor/frontend/build/static/js/main.766c23d5.js.LICENSE.txt +0 -0
  16. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor/frontend/build/static/js/main.766c23d5.js.map +0 -0
  17. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor.egg-info/SOURCES.txt +0 -0
  18. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor.egg-info/dependency_links.txt +0 -0
  19. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor.egg-info/requires.txt +0 -0
  20. {streamlit_node_editor-0.3.0 → streamlit_node_editor-0.3.2}/streamlit_node_editor.egg-info/top_level.txt +0 -0
@@ -0,0 +1,395 @@
1
+ Metadata-Version: 2.2
2
+ Name: streamlit-node-editor
3
+ Version: 0.3.2
4
+ Summary: A ComfyUI/Blueprints-style node graph editor for Streamlit — typed ports, drag-to-connect, inline params
5
+ Home-page: https://github.com/RhythrosaLabs/streamlit-node-editor
6
+ Author: Dan Sheils
7
+ Author-email:
8
+ Project-URL: Bug Tracker, https://github.com/RhythrosaLabs/streamlit-node-editor/issues
9
+ Project-URL: Changelog, https://github.com/RhythrosaLabs/streamlit-node-editor/blob/main/CHANGELOG.md
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: streamlit>=1.28.0
17
+ Dynamic: author
18
+ Dynamic: classifier
19
+ Dynamic: description
20
+ Dynamic: description-content-type
21
+ Dynamic: home-page
22
+ Dynamic: project-url
23
+ Dynamic: requires-dist
24
+ Dynamic: requires-python
25
+ Dynamic: summary
26
+
27
+ <p align="center">
28
+ <img src="https://raw.githubusercontent.com/RhythrosaLabs/streamlit-node-editor/main/assets/screenshot.svg" width="800" alt="streamlit-node-editor screenshot" />
29
+ </p>
30
+
31
+ <h1 align="center">streamlit-node-editor</h1>
32
+
33
+ <p align="center">
34
+ <strong>A ComfyUI / Unreal Blueprints-style node graph editor for <a href="https://streamlit.io">Streamlit</a></strong>
35
+ </p>
36
+
37
+ <p align="center">
38
+ <a href="https://pypi.org/project/streamlit-node-editor/"><img src="https://img.shields.io/pypi/v/streamlit-node-editor.svg?style=flat-square&color=818cf8" alt="PyPI version" /></a>
39
+ <a href="https://pypi.org/project/streamlit-node-editor/"><img src="https://img.shields.io/pypi/pyversions/streamlit-node-editor.svg?style=flat-square" alt="Python versions" /></a>
40
+ <a href="https://github.com/RhythrosaLabs/streamlit-node-editor/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat-square" alt="License" /></a>
41
+ <a href="https://pypi.org/project/streamlit-node-editor/"><img src="https://img.shields.io/pypi/dm/streamlit-node-editor.svg?style=flat-square&color=34d399" alt="Downloads" /></a>
42
+ </p>
43
+
44
+ ---
45
+
46
+ **streamlit-node-editor** is a fully interactive node graph editor that runs inside any Streamlit application. Define typed node types in Python, let users build graphs by dragging ports and connecting wires, and get the full graph state back as structured JSON — all with zero runtime dependencies beyond Streamlit (no React Flow, no external graph library).
47
+
48
+ ## Features
49
+
50
+ ### Node Graph
51
+ - **Typed ports** — color-coded input/output ports with data type labels; only compatible types can connect
52
+ - **Drag-to-wire** — click an output port, drag, and drop on a compatible input to create a connection
53
+ - **Type validation** — incompatible connections are silently rejected, preventing invalid graphs
54
+ - **Animated wires** — smooth bezier curves with flowing-dot animation connect ports visually
55
+
56
+ ### Node Interaction
57
+ - **Inline parameters** — select dropdowns, number inputs, text inputs, and textareas rendered inside each node body
58
+ - **Drag to move** — reposition nodes freely on the canvas
59
+ - **Collapse nodes** — minimize nodes to save canvas space while preserving connections
60
+ - **Delete / Backspace** — removes the selected node and all its connections
61
+ - **Click wire to delete** — remove connections without any menu
62
+
63
+ ### Canvas
64
+ - **Pan + scroll-to-zoom** — navigate large graphs with proper SVG coordinate transforms
65
+ - **Animated dot-grid background** — subtle grid for spatial reference
66
+ - **Configurable height** — set canvas height in pixels via the `height` parameter
67
+
68
+ ### Node Palette
69
+ - **Searchable palette** — filterable list of all registered node types grouped by category
70
+ - **Right-click or toolbar** — open the palette from the canvas context menu or the toolbar button
71
+ - **Category grouping** — nodes organized by their `category` field
72
+
73
+ ### Dark Theme
74
+ - Consistent dark UI with color-coded node headers
75
+ - Glass-morphism panels with subtle borders
76
+ - Designed to match Streamlit's dark mode
77
+
78
+ ---
79
+
80
+ ## Installation
81
+
82
+ ```bash
83
+ pip install streamlit-node-editor
84
+ ```
85
+
86
+ ## Quick Start — Data Pipeline Builder
87
+
88
+ ```python
89
+ import streamlit as st
90
+ from streamlit_node_editor import st_node_editor
91
+
92
+ NODE_DEFS = {
93
+ "CSV Source": {
94
+ "category": "Sources",
95
+ "headerColor": "#4ade80",
96
+ "inputs": [],
97
+ "outputs": [{"name": "dataframe", "type": "DATAFRAME"}],
98
+ "params": [
99
+ {"key": "path", "label": "File path", "type": "string", "default": "data.csv"},
100
+ {"key": "sep", "label": "Separator", "type": "string", "default": ","},
101
+ ],
102
+ },
103
+ "Filter Rows": {
104
+ "category": "Transform",
105
+ "headerColor": "#38bdf8",
106
+ "inputs": [{"name": "df_in", "type": "DATAFRAME"}],
107
+ "outputs": [{"name": "df_out", "type": "DATAFRAME"}],
108
+ "params": [
109
+ {"key": "query", "label": "Query expr", "type": "string", "default": "value > 0"},
110
+ ],
111
+ },
112
+ "Group By": {
113
+ "category": "Transform",
114
+ "headerColor": "#818cf8",
115
+ "inputs": [{"name": "df_in", "type": "DATAFRAME"}],
116
+ "outputs": [{"name": "df_out", "type": "DATAFRAME"}],
117
+ "params": [
118
+ {"key": "column", "label": "Column", "type": "string"},
119
+ {"key": "agg", "label": "Aggregate", "type": "select",
120
+ "options": ["sum", "mean", "count", "min", "max"]},
121
+ ],
122
+ },
123
+ "Bar Chart": {
124
+ "category": "Outputs",
125
+ "headerColor": "#fb923c",
126
+ "inputs": [{"name": "dataframe", "type": "DATAFRAME"}],
127
+ "outputs": [],
128
+ "params": [
129
+ {"key": "x", "label": "X column", "type": "string"},
130
+ {"key": "y", "label": "Y column", "type": "string"},
131
+ ],
132
+ },
133
+ }
134
+
135
+ graph = st_node_editor(NODE_DEFS, height=600, key="pipeline")
136
+
137
+ if graph:
138
+ st.subheader("Graph state")
139
+ st.json(graph)
140
+ ```
141
+
142
+ ## API Reference
143
+
144
+ ### `st_node_editor`
145
+
146
+ ```python
147
+ st_node_editor(
148
+ node_defs: dict[str, dict],
149
+ initial_nodes: list[dict] | None = None,
150
+ initial_connections: list[dict] | None = None,
151
+ height: int = 700,
152
+ key: str | None = None,
153
+ ) -> dict | None
154
+ ```
155
+
156
+ #### Parameters
157
+
158
+ | Parameter | Type | Default | Description |
159
+ |-----------|------|---------|-------------|
160
+ | `node_defs` | `dict[str, dict]` | required | Node type registry. Keys are node type names, values are definition dicts. See schema below. |
161
+ | `initial_nodes` | `list[dict]` or `None` | `[]` | Pre-placed nodes on the canvas. |
162
+ | `initial_connections` | `list[dict]` or `None` | `[]` | Pre-existing wire connections. |
163
+ | `height` | `int` | `700` | Canvas height in pixels. |
164
+ | `key` | `str` or `None` | `None` | An optional key that uniquely identifies this component. Required when placing multiple editors on one page. |
165
+
166
+ #### Return Value
167
+
168
+ Returns a `dict` with the full graph state after any interaction, or `None` before any interaction.
169
+
170
+ ```python
171
+ {
172
+ "nodes": [
173
+ {
174
+ "id": str, # unique node ID
175
+ "type": str, # node type name (key from node_defs)
176
+ "x": float, # canvas X position
177
+ "y": float, # canvas Y position
178
+ "params": {key: value, ...}, # current parameter values
179
+ },
180
+ ...
181
+ ],
182
+ "connections": [
183
+ {
184
+ "id": str, # unique connection ID
185
+ "fromNode": str, # source node ID
186
+ "fromPort": int, # output port index (0-based)
187
+ "toNode": str, # target node ID
188
+ "toPort": int, # input port index (0-based)
189
+ },
190
+ ...
191
+ ]
192
+ }
193
+ ```
194
+
195
+ ### Data Structures
196
+
197
+ #### Node Definition
198
+
199
+ ```python
200
+ "Node Type Name": {
201
+ "category": str, # palette grouping (e.g. "Sources", "Transform")
202
+ "headerColor": str, # hex color for the node's title bar
203
+ "inputs": [
204
+ {"name": str, "type": str} # typed input ports
205
+ ],
206
+ "outputs": [
207
+ {"name": str, "type": str} # typed output ports
208
+ ],
209
+ "params": [
210
+ {
211
+ "key": str, # parameter key (returned in node params)
212
+ "label": str, # display label inside the node
213
+ "type": str, # "int" | "float" | "string" | "select" | "textarea"
214
+ "default": any, # optional default value
215
+ "options": list[str], # required when type == "select"
216
+ }
217
+ ],
218
+ }
219
+ ```
220
+
221
+ #### Built-in Port Types
222
+
223
+ | Type | Color | Typical Use |
224
+ |------|-------|-------------|
225
+ | `IMAGE` | green | Pixel data |
226
+ | `LATENT` | purple | Latent tensors |
227
+ | `MODEL` | orange | Neural network weights |
228
+ | `CLIP` | yellow | Text encoders |
229
+ | `VAE` | red | Variational autoencoders |
230
+ | `INT` | blue | Integer values |
231
+ | `FLOAT` | indigo | Float values |
232
+ | `STRING` | stone | Text data |
233
+ | `MASK` | teal | Binary masks |
234
+ | `ANY` | gray | Accepts any type |
235
+
236
+ Define your own types freely in `node_defs` — any unrecognized type string uses the `ANY` gray color.
237
+
238
+ ---
239
+
240
+ ## Usage Examples
241
+
242
+ ### Pre-placing Nodes and Connections
243
+
244
+ ```python
245
+ graph = st_node_editor(
246
+ NODE_DEFS,
247
+ initial_nodes=[
248
+ {"id": "n1", "type": "CSV Source", "x": 50, "y": 100,
249
+ "params": {"path": "sales.csv", "sep": ","}},
250
+ {"id": "n2", "type": "Filter Rows", "x": 350, "y": 100,
251
+ "params": {"query": "revenue > 1000"}},
252
+ {"id": "n3", "type": "Bar Chart", "x": 650, "y": 100,
253
+ "params": {"x": "month", "y": "revenue"}},
254
+ ],
255
+ initial_connections=[
256
+ {"id": "w1", "fromNode": "n1", "fromPort": 0, "toNode": "n2", "toPort": 0},
257
+ {"id": "w2", "fromNode": "n2", "fromPort": 0, "toNode": "n3", "toPort": 0},
258
+ ],
259
+ height=600,
260
+ key="pipeline",
261
+ )
262
+ ```
263
+
264
+ ### Executing a Pipeline from the Graph
265
+
266
+ ```python
267
+ graph = st_node_editor(NODE_DEFS, key="pipeline")
268
+
269
+ if graph and st.button("Run Pipeline"):
270
+ nodes_by_id = {n["id"]: n for n in graph["nodes"]}
271
+
272
+ for node in graph["nodes"]:
273
+ node_type = node["type"]
274
+ params = node["params"]
275
+
276
+ if node_type == "CSV Source":
277
+ st.info(f"Loading {params.get('path', 'data.csv')}")
278
+ elif node_type == "Filter Rows":
279
+ st.info(f"Filtering: {params.get('query', '')}")
280
+ elif node_type == "Bar Chart":
281
+ st.info(f"Charting {params.get('x')} vs {params.get('y')}")
282
+
283
+ st.success(f"Executed {len(graph['nodes'])} nodes with {len(graph['connections'])} connections")
284
+ ```
285
+
286
+ ### Image Processing Workflow
287
+
288
+ ```python
289
+ IMAGE_NODES = {
290
+ "Load Image": {
291
+ "category": "Input",
292
+ "headerColor": "#4ade80",
293
+ "inputs": [],
294
+ "outputs": [{"name": "image", "type": "IMAGE"}],
295
+ "params": [
296
+ {"key": "path", "label": "Image path", "type": "string", "default": "photo.jpg"},
297
+ ],
298
+ },
299
+ "Resize": {
300
+ "category": "Transform",
301
+ "headerColor": "#38bdf8",
302
+ "inputs": [{"name": "image", "type": "IMAGE"}],
303
+ "outputs": [{"name": "image", "type": "IMAGE"}],
304
+ "params": [
305
+ {"key": "width", "label": "Width", "type": "int", "default": 512},
306
+ {"key": "height", "label": "Height", "type": "int", "default": 512},
307
+ ],
308
+ },
309
+ "Blur": {
310
+ "category": "Effects",
311
+ "headerColor": "#a78bfa",
312
+ "inputs": [{"name": "image", "type": "IMAGE"}],
313
+ "outputs": [{"name": "image", "type": "IMAGE"}],
314
+ "params": [
315
+ {"key": "radius", "label": "Radius", "type": "float", "default": 2.0},
316
+ ],
317
+ },
318
+ "Save Image": {
319
+ "category": "Output",
320
+ "headerColor": "#fb923c",
321
+ "inputs": [{"name": "image", "type": "IMAGE"}],
322
+ "outputs": [],
323
+ "params": [
324
+ {"key": "path", "label": "Output path", "type": "string", "default": "output.png"},
325
+ {"key": "format", "label": "Format", "type": "select",
326
+ "options": ["PNG", "JPEG", "WEBP"]},
327
+ ],
328
+ },
329
+ }
330
+
331
+ graph = st_node_editor(IMAGE_NODES, height=500, key="image_pipeline")
332
+ ```
333
+
334
+ ---
335
+
336
+ ## Architecture
337
+
338
+ The component is built with **React 18** communicating with Streamlit via the bidirectional component API (`streamlit-component-lib`). All rendering uses inline SVG for wires and standard HTML/CSS for nodes.
339
+
340
+ ```
341
+ ┌──────────────────────────────────────────────────────────┐
342
+ │ Python (Streamlit) │
343
+ │ st_node_editor(node_defs, initial_nodes, …, key) │
344
+ │ ↓ args ↑ componentValue │
345
+ ├──────────────────────────────────────────────────────────┤
346
+ │ React Frontend (iframe) │
347
+ │ ┌────────────────────────────────────────────────────┐ │
348
+ │ │ Toolbar: Add Node · Delete · Zoom · Fit │ │
349
+ │ ├─────────┬──────────────────────────────────────────┤ │
350
+ │ │ Palette │ Canvas (pan + zoom) │ │
351
+ │ │ │ ┌──────────┐ ┌──────────┐ │ │
352
+ │ │ Sources │ │ CSV Source│────→│Filter │ │ │
353
+ │ │ ├─CSV │ │ path: .. │ │ query: ..│ │ │
354
+ │ │ ├─API │ └──────────┘ └────┬─────┘ │ │
355
+ │ │ │ │ │ │
356
+ │ │ Transf. │ ┌────────▼──────┐ │ │
357
+ │ │ ├─Filter│ │ Bar Chart │ │ │
358
+ │ │ ├─Group │ │ x: .. y: .. │ │ │
359
+ │ │ │ └───────────────┘ │ │
360
+ │ │ Outputs │ │ │
361
+ │ │ ├─Chart │ · · · · · · · · (dot grid) · · · · · │ │
362
+ │ └─────────┴──────────────────────────────────────────┘ │
363
+ └──────────────────────────────────────────────────────────┘
364
+ ```
365
+
366
+ - **Wire engine** — SVG bezier curves with animated flowing dots; hit-test for click-to-delete
367
+ - **Port system** — typed ports with color mapping; connection validation runs on drop
368
+ - **Node renderer** — HTML div with color-coded header, inline param editors, and port circles
369
+ - **Pan / zoom** — CSS transform on the canvas container with scroll-wheel zoom
370
+ - **State sync** — every node move, add, delete, or connection change calls `Streamlit.setComponentValue()` with the full graph
371
+
372
+ ## Browser Compatibility
373
+
374
+ | Browser | Status |
375
+ |---------|--------|
376
+ | Chrome / Edge 90+ | ✅ Full support |
377
+ | Firefox 90+ | ✅ Full support |
378
+ | Safari 15+ | ✅ Full support |
379
+ | Mobile browsers | ⚠️ Touch drag may vary |
380
+
381
+ ## Requirements
382
+
383
+ - Python 3.8+
384
+ - Streamlit ≥ 1.28.0
385
+
386
+ ## License
387
+
388
+ MIT — see [LICENSE](LICENSE) for details.
389
+
390
+ ## Links
391
+
392
+ - **PyPI:** [https://pypi.org/project/streamlit-node-editor/](https://pypi.org/project/streamlit-node-editor/)
393
+ - **GitHub:** [https://github.com/RhythrosaLabs/streamlit-node-editor](https://github.com/RhythrosaLabs/streamlit-node-editor)
394
+ - **Changelog:** [CHANGELOG.md](CHANGELOG.md)
395
+ - **Issues:** [https://github.com/RhythrosaLabs/streamlit-node-editor/issues](https://github.com/RhythrosaLabs/streamlit-node-editor/issues)