Spaces:
Running
Running
Register operations into categories, and a rough UI for displaying them.
Browse files
lynxkite-app/web/src/workspace/NodeSearch.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
|
| 3 |
|
| 4 |
export type OpsOp = {
|
| 5 |
name: string;
|
|
|
|
| 6 |
type: string;
|
| 7 |
position: { x: number; y: number };
|
| 8 |
params: { name: string; default: any }[];
|
|
@@ -81,6 +82,7 @@ export default function NodeSearch(props: {
|
|
| 81 |
onClick={addSelected}
|
| 82 |
className={`search-result ${index === selectedIndex ? "selected" : ""}`}
|
| 83 |
>
|
|
|
|
| 84 |
{box.item.name}
|
| 85 |
</div>
|
| 86 |
))}
|
|
|
|
| 3 |
|
| 4 |
export type OpsOp = {
|
| 5 |
name: string;
|
| 6 |
+
categories: string[];
|
| 7 |
type: string;
|
| 8 |
position: { x: number; y: number };
|
| 9 |
params: { name: string; default: any }[];
|
|
|
|
| 82 |
onClick={addSelected}
|
| 83 |
className={`search-result ${index === selectedIndex ? "selected" : ""}`}
|
| 84 |
>
|
| 85 |
+
{box.item.categories.map((category) => `${category}\u00A0›\u00A0`)}
|
| 86 |
{box.item.name}
|
| 87 |
</div>
|
| 88 |
))}
|
lynxkite-core/src/lynxkite/core/ops.py
CHANGED
|
@@ -184,6 +184,7 @@ def _param_to_type(name, value, type):
|
|
| 184 |
|
| 185 |
class Op(BaseConfig):
|
| 186 |
func: typing.Callable = pydantic.Field(exclude=True)
|
|
|
|
| 187 |
name: str
|
| 188 |
params: list[Parameter | ParameterGroup]
|
| 189 |
inputs: list[Input]
|
|
@@ -234,11 +235,15 @@ class Op(BaseConfig):
|
|
| 234 |
res[p.name] = _param_to_type(p.name, params[p.name], p.type)
|
| 235 |
return res
|
| 236 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
def op(
|
| 239 |
env: str,
|
| 240 |
-
|
| 241 |
-
*,
|
| 242 |
view="basic",
|
| 243 |
outputs=None,
|
| 244 |
params=None,
|
|
@@ -247,6 +252,7 @@ def op(
|
|
| 247 |
cache=None,
|
| 248 |
):
|
| 249 |
"""Decorator for defining an operation."""
|
|
|
|
| 250 |
|
| 251 |
def decorator(func):
|
| 252 |
doc = parse_doc(func)
|
|
@@ -279,6 +285,7 @@ def op(
|
|
| 279 |
func=func,
|
| 280 |
doc=doc,
|
| 281 |
name=name,
|
|
|
|
| 282 |
params=_params,
|
| 283 |
inputs=inputs,
|
| 284 |
outputs=_outputs,
|
|
@@ -286,7 +293,7 @@ def op(
|
|
| 286 |
color=color or "orange",
|
| 287 |
)
|
| 288 |
CATALOGS.setdefault(env, {})
|
| 289 |
-
CATALOGS[env][
|
| 290 |
func.__op__ = op
|
| 291 |
return func
|
| 292 |
|
|
@@ -364,11 +371,13 @@ def no_op(*args, **kwargs):
|
|
| 364 |
return None
|
| 365 |
|
| 366 |
|
| 367 |
-
def register_passive_op(env: str,
|
| 368 |
"""A passive operation has no associated code."""
|
|
|
|
| 369 |
op = Op(
|
| 370 |
func=no_op,
|
| 371 |
name=name,
|
|
|
|
| 372 |
params=params,
|
| 373 |
inputs=[Input(name=i, type=None) if isinstance(i, str) else i for i in inputs],
|
| 374 |
outputs=[Output(name=o, type=None) if isinstance(o, str) else o for o in outputs],
|
|
@@ -382,6 +391,7 @@ def register_passive_op(env: str, name: str, inputs=[], outputs=["output"], para
|
|
| 382 |
COMMENT_OP = Op(
|
| 383 |
func=no_op,
|
| 384 |
name="Comment",
|
|
|
|
| 385 |
params=[Parameter.basic("text", "", LongStr)],
|
| 386 |
inputs=[],
|
| 387 |
outputs=[],
|
|
|
|
| 184 |
|
| 185 |
class Op(BaseConfig):
|
| 186 |
func: typing.Callable = pydantic.Field(exclude=True)
|
| 187 |
+
categories: list[str]
|
| 188 |
name: str
|
| 189 |
params: list[Parameter | ParameterGroup]
|
| 190 |
inputs: list[Input]
|
|
|
|
| 235 |
res[p.name] = _param_to_type(p.name, params[p.name], p.type)
|
| 236 |
return res
|
| 237 |
|
| 238 |
+
@property
|
| 239 |
+
def id(self) -> str:
|
| 240 |
+
"""The name and categories of the operation."""
|
| 241 |
+
return " > ".join(self.categories + [self.name])
|
| 242 |
+
|
| 243 |
|
| 244 |
def op(
|
| 245 |
env: str,
|
| 246 |
+
*names: str,
|
|
|
|
| 247 |
view="basic",
|
| 248 |
outputs=None,
|
| 249 |
params=None,
|
|
|
|
| 252 |
cache=None,
|
| 253 |
):
|
| 254 |
"""Decorator for defining an operation."""
|
| 255 |
+
[*categories, name] = names
|
| 256 |
|
| 257 |
def decorator(func):
|
| 258 |
doc = parse_doc(func)
|
|
|
|
| 285 |
func=func,
|
| 286 |
doc=doc,
|
| 287 |
name=name,
|
| 288 |
+
categories=categories,
|
| 289 |
params=_params,
|
| 290 |
inputs=inputs,
|
| 291 |
outputs=_outputs,
|
|
|
|
| 293 |
color=color or "orange",
|
| 294 |
)
|
| 295 |
CATALOGS.setdefault(env, {})
|
| 296 |
+
CATALOGS[env][op.id] = op
|
| 297 |
func.__op__ = op
|
| 298 |
return func
|
| 299 |
|
|
|
|
| 371 |
return None
|
| 372 |
|
| 373 |
|
| 374 |
+
def register_passive_op(env: str, *names: str, inputs=[], outputs=["output"], params=[], **kwargs):
|
| 375 |
"""A passive operation has no associated code."""
|
| 376 |
+
[*categories, name] = names
|
| 377 |
op = Op(
|
| 378 |
func=no_op,
|
| 379 |
name=name,
|
| 380 |
+
categories=categories,
|
| 381 |
params=params,
|
| 382 |
inputs=[Input(name=i, type=None) if isinstance(i, str) else i for i in inputs],
|
| 383 |
outputs=[Output(name=o, type=None) if isinstance(o, str) else o for o in outputs],
|
|
|
|
| 391 |
COMMENT_OP = Op(
|
| 392 |
func=no_op,
|
| 393 |
name="Comment",
|
| 394 |
+
categories=[],
|
| 395 |
params=[Parameter.basic("text", "", LongStr)],
|
| 396 |
inputs=[],
|
| 397 |
outputs=[],
|
lynxkite-graph-analytics/src/lynxkite_graph_analytics/networkx_ops.py
CHANGED
|
@@ -242,6 +242,41 @@ _REPLACEMENTS = [
|
|
| 242 |
("Watts Strogatz", "Watts–Strogatz"),
|
| 243 |
("Weisfeiler Lehman", "Weisfeiler–Lehman"),
|
| 244 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
|
| 246 |
|
| 247 |
def register_networkx(env: str):
|
|
@@ -254,12 +289,13 @@ def register_networkx(env: str):
|
|
| 254 |
except UnsupportedParameterType:
|
| 255 |
continue
|
| 256 |
inputs = [ops.Input(name=k, type=nx.Graph) for k in func.graphs]
|
| 257 |
-
nicename =
|
| 258 |
for a, b in _REPLACEMENTS:
|
| 259 |
nicename = nicename.replace(a, b)
|
| 260 |
op = ops.Op(
|
| 261 |
func=wrapped(name, func),
|
| 262 |
name=nicename,
|
|
|
|
| 263 |
params=params,
|
| 264 |
inputs=inputs,
|
| 265 |
outputs=[ops.Output(name="output", type=nx.Graph)],
|
|
|
|
| 242 |
("Watts Strogatz", "Watts–Strogatz"),
|
| 243 |
("Weisfeiler Lehman", "Weisfeiler–Lehman"),
|
| 244 |
]
|
| 245 |
+
_CATEGORY_REPLACEMENTS = [
|
| 246 |
+
("Networkx", "NetworkX"),
|
| 247 |
+
("D separation", "D-separation"),
|
| 248 |
+
("Dag", "DAG"),
|
| 249 |
+
("Pagerank alg", "PageRank alg"),
|
| 250 |
+
("Richclub", "Rich-club"),
|
| 251 |
+
("Smallworld", "Small-world"),
|
| 252 |
+
("Smetric", "S-metric"),
|
| 253 |
+
("Structuralholes", "Structural holes"),
|
| 254 |
+
("Edgedfs", "Edge DFS"),
|
| 255 |
+
("Edgebfs", "Edge BFS"),
|
| 256 |
+
("Edge_kcomponents", "Edge k-components"),
|
| 257 |
+
("Mincost", "Min cost"),
|
| 258 |
+
("Networksimplex", "Network simplex"),
|
| 259 |
+
("Vf2pp", "VF2++"),
|
| 260 |
+
("Mst", "MST"),
|
| 261 |
+
("Attrmatrix", "Attr matrix"),
|
| 262 |
+
("Graphmatrix", "Graph matrix"),
|
| 263 |
+
("Laplacianmatrix", "Laplacian matrix"),
|
| 264 |
+
("Algebraicconnectivity", "Algebraic connectivity"),
|
| 265 |
+
("Modularitymatrix", "Modularity matrix"),
|
| 266 |
+
("Bethehessianmatrix", "Bethe–Hessian matrix"),
|
| 267 |
+
]
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
def _categories(func) -> list[str]:
|
| 271 |
+
"""Extract categories from the function's docstring."""
|
| 272 |
+
path = func.__module__.split(".")
|
| 273 |
+
cats = []
|
| 274 |
+
for p in path:
|
| 275 |
+
p = p.replace("_", " ").capitalize()
|
| 276 |
+
for a, b in _CATEGORY_REPLACEMENTS:
|
| 277 |
+
p = p.replace(a, b)
|
| 278 |
+
cats.append(p)
|
| 279 |
+
return cats
|
| 280 |
|
| 281 |
|
| 282 |
def register_networkx(env: str):
|
|
|
|
| 289 |
except UnsupportedParameterType:
|
| 290 |
continue
|
| 291 |
inputs = [ops.Input(name=k, type=nx.Graph) for k in func.graphs]
|
| 292 |
+
nicename = name.replace("_", " ").title()
|
| 293 |
for a, b in _REPLACEMENTS:
|
| 294 |
nicename = nicename.replace(a, b)
|
| 295 |
op = ops.Op(
|
| 296 |
func=wrapped(name, func),
|
| 297 |
name=nicename,
|
| 298 |
+
categories=_categories(func),
|
| 299 |
params=params,
|
| 300 |
inputs=inputs,
|
| 301 |
outputs=[ops.Output(name="output", type=nx.Graph)],
|