darabos commited on
Commit
5be461a
·
1 Parent(s): 25e1fae

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
- name: str,
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][name] = op
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, name: str, inputs=[], outputs=["output"], params=[], **kwargs):
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 = "NX › " + name.replace("_", " ").title()
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)],