abhik1368 darabos commited on
Commit
5203f05
·
1 Parent(s): 7d05506

Update Cheminformatrics use Cases (#155)

Browse files

* Update Cheminformatrics use Cases

Add _cheminfo_tools.py with lipinksi filter , View Mol Image , View mol filter with smarts and smiles and highlights are done .

* Delete binary files. Create "Cheminformatics" folder for examples.

* MACCSkeys was undefined. rows was unused.

* Give ops human-readable names.

* Example workspace without images.

* Collapse parameters on "image" type boxes.

* Allow slow visualization boxes too.

* Simpler gallery drawing.

* Output for visualizations is now left empty.

---------

Co-authored-by: Daniel Darabos <[email protected]>

examples/Image table.lynxkite.json CHANGED
@@ -27,7 +27,7 @@
27
  {
28
  "data": {
29
  "__execution_delay": null,
30
- "collapsed": true,
31
  "display": null,
32
  "error": null,
33
  "input_metadata": [],
@@ -55,8 +55,8 @@
55
  "height": 200.0,
56
  "id": "Example image table 1",
57
  "position": {
58
- "x": 213.60043945845376,
59
- "y": 306.98088700969373
60
  },
61
  "type": "basic",
62
  "width": 280.0
@@ -138,8 +138,8 @@
138
  "height": 440.0,
139
  "id": "View tables 1",
140
  "position": {
141
- "x": 626.2831607914023,
142
- "y": 109.55448939208392
143
  },
144
  "type": "table_view",
145
  "width": 376.0
@@ -198,14 +198,14 @@
198
  "title": "Import CSV"
199
  },
200
  "dragHandle": ".bg-primary",
201
- "height": 313.0,
202
  "id": "Import CSV 1",
203
  "position": {
204
  "x": 13.802068621055497,
205
  "y": -269.65065144888104
206
  },
207
  "type": "basic",
208
- "width": 216.0
209
  },
210
  {
211
  "data": {
@@ -282,15 +282,15 @@
282
  "params": {
283
  "limit": 100.0
284
  },
285
- "status": "done",
286
  "title": "View tables"
287
  },
288
  "dragHandle": ".bg-primary",
289
  "height": 418.0,
290
  "id": "View tables 2",
291
  "position": {
292
- "x": 548.7706661684929,
293
- "y": -316.9626796191875
294
  },
295
  "type": "table_view",
296
  "width": 1116.0
@@ -300,7 +300,7 @@
300
  "__execution_delay": 0.0,
301
  "collapsed": null,
302
  "display": null,
303
- "error": null,
304
  "input_metadata": [
305
  {}
306
  ],
@@ -354,8 +354,8 @@
354
  "height": 296.0,
355
  "id": "Draw molecules 1",
356
  "position": {
357
- "x": 289.42386787591244,
358
- "y": -258.0823121715324
359
  },
360
  "type": "basic",
361
  "width": 212.0
 
27
  {
28
  "data": {
29
  "__execution_delay": null,
30
+ "collapsed": false,
31
  "display": null,
32
  "error": null,
33
  "input_metadata": [],
 
55
  "height": 200.0,
56
  "id": "Example image table 1",
57
  "position": {
58
+ "x": 356.1935187064265,
59
+ "y": 224.8472733628614
60
  },
61
  "type": "basic",
62
  "width": 280.0
 
138
  "height": 440.0,
139
  "id": "View tables 1",
140
  "position": {
141
+ "x": 757.4687936995374,
142
+ "y": 116.39895719598661
143
  },
144
  "type": "table_view",
145
  "width": 376.0
 
198
  "title": "Import CSV"
199
  },
200
  "dragHandle": ".bg-primary",
201
+ "height": 339.0,
202
  "id": "Import CSV 1",
203
  "position": {
204
  "x": 13.802068621055497,
205
  "y": -269.65065144888104
206
  },
207
  "type": "basic",
208
+ "width": 296.0
209
  },
210
  {
211
  "data": {
 
282
  "params": {
283
  "limit": 100.0
284
  },
285
+ "status": "planned",
286
  "title": "View tables"
287
  },
288
  "dragHandle": ".bg-primary",
289
  "height": 418.0,
290
  "id": "View tables 2",
291
  "position": {
292
+ "x": 815.4121289519509,
293
+ "y": -330.8232285057863
294
  },
295
  "type": "table_view",
296
  "width": 1116.0
 
300
  "__execution_delay": 0.0,
301
  "collapsed": null,
302
  "display": null,
303
+ "error": "module 'rdkit.Chem' has no attribute 'Draw'",
304
  "input_metadata": [
305
  {}
306
  ],
 
354
  "height": 296.0,
355
  "id": "Draw molecules 1",
356
  "position": {
357
+ "x": 351.1956913898301,
358
+ "y": -235.00831568554486
359
  },
360
  "type": "basic",
361
  "width": 212.0
lynxkite-app/web/src/workspace/nodes/NodeWithImage.tsx CHANGED
@@ -3,7 +3,7 @@ import { NodeWithParams } from "./NodeWithParams";
3
 
4
  const NodeWithImage = (props: any) => {
5
  return (
6
- <NodeWithParams {...props}>
7
  {props.data.display && <img src={props.data.display} alt="Node Display" />}
8
  </NodeWithParams>
9
  );
 
3
 
4
  const NodeWithImage = (props: any) => {
5
  return (
6
+ <NodeWithParams collapsed {...props}>
7
  {props.data.display && <img src={props.data.display} alt="Node Display" />}
8
  </NodeWithParams>
9
  );
lynxkite-core/src/lynxkite/core/ops.py CHANGED
@@ -129,7 +129,7 @@ class Result:
129
  `input_metadata` is a list of JSON objects describing each input.
130
  """
131
 
132
- output: typing.Any = None
133
  display: ReadOnlyJSON | None = None
134
  error: str | None = None
135
  input_metadata: ReadOnlyJSON | None = None
@@ -187,7 +187,6 @@ class Op(BaseConfig):
187
  res = self.func(*inputs, **params)
188
  if not isinstance(res, Result):
189
  # Automatically wrap the result in a Result object, if it isn't already.
190
- res = Result(output=res)
191
  if self.type in [
192
  "visualization",
193
  "table_view",
@@ -195,9 +194,10 @@ class Op(BaseConfig):
195
  "image",
196
  "molecule",
197
  ]:
198
- # If the operation is some kind of visualization, we use the output as the
199
- # value to display by default.
200
- res.display = res.output
 
201
  return res
202
 
203
  def get_input(self, name: str):
@@ -237,6 +237,10 @@ def op(
237
 
238
  def decorator(func):
239
  sig = inspect.signature(func)
 
 
 
 
240
  if slow:
241
  func = mem.cache(func)
242
  func = _global_slow(func)
@@ -256,10 +260,6 @@ def op(
256
  _outputs = [Output(name=name, type=None) for name in outputs]
257
  else:
258
  _outputs = [Output(name="output", type=None)] if view == "basic" else []
259
- _view = view
260
- if view == "matplotlib":
261
- _view = "image"
262
- func = matplotlib_to_image(func)
263
  op = Op(
264
  func=func,
265
  name=name,
 
129
  `input_metadata` is a list of JSON objects describing each input.
130
  """
131
 
132
+ output: typing.Any | None = None
133
  display: ReadOnlyJSON | None = None
134
  error: str | None = None
135
  input_metadata: ReadOnlyJSON | None = None
 
187
  res = self.func(*inputs, **params)
188
  if not isinstance(res, Result):
189
  # Automatically wrap the result in a Result object, if it isn't already.
 
190
  if self.type in [
191
  "visualization",
192
  "table_view",
 
194
  "image",
195
  "molecule",
196
  ]:
197
+ # If the operation is a visualization, we use the returned value for display.
198
+ res = Result(display=res)
199
+ else:
200
+ res = Result(output=res)
201
  return res
202
 
203
  def get_input(self, name: str):
 
237
 
238
  def decorator(func):
239
  sig = inspect.signature(func)
240
+ _view = view
241
+ if view == "matplotlib":
242
+ _view = "image"
243
+ func = matplotlib_to_image(func)
244
  if slow:
245
  func = mem.cache(func)
246
  func = _global_slow(func)
 
260
  _outputs = [Output(name=name, type=None) for name in outputs]
261
  else:
262
  _outputs = [Output(name="output", type=None)] if view == "basic" else []
 
 
 
 
263
  op = Op(
264
  func=func,
265
  name=name,
lynxkite-core/src/lynxkite/core/workspace.py CHANGED
@@ -65,10 +65,14 @@ class WorkspaceNode(BaseConfig):
65
  self.data.status = NodeStatus.done
66
  if hasattr(self, "_crdt"):
67
  with self._crdt.doc.transaction():
68
- self._crdt["data"]["display"] = self.data.display
69
- self._crdt["data"]["input_metadata"] = self.data.input_metadata
70
- self._crdt["data"]["error"] = self.data.error
71
- self._crdt["data"]["status"] = NodeStatus.done
 
 
 
 
72
 
73
  def publish_error(self, error: Exception | str | None):
74
  """Can be called with None to clear the error state."""
@@ -176,7 +180,6 @@ class Workspace(BaseConfig):
176
  # If the node is connected to a CRDT, update that too.
177
  if hasattr(node, "_crdt"):
178
  node._crdt["data"]["meta"] = op.model_dump()
179
- print("set metadata to", op)
180
  if node.type != op.type:
181
  node.type = op.type
182
  if hasattr(node, "_crdt"):
 
65
  self.data.status = NodeStatus.done
66
  if hasattr(self, "_crdt"):
67
  with self._crdt.doc.transaction():
68
+ try:
69
+ self._crdt["data"]["status"] = NodeStatus.done
70
+ self._crdt["data"]["display"] = self.data.display
71
+ self._crdt["data"]["input_metadata"] = self.data.input_metadata
72
+ self._crdt["data"]["error"] = self.data.error
73
+ except Exception as e:
74
+ self._crdt["data"]["error"] = str(e)
75
+ raise e
76
 
77
  def publish_error(self, error: Exception | str | None):
78
  """Can be called with None to clear the error state."""
 
180
  # If the node is connected to a CRDT, update that too.
181
  if hasattr(node, "_crdt"):
182
  node._crdt["data"]["meta"] = op.model_dump()
 
183
  if node.type != op.type:
184
  node.type = op.type
185
  if hasattr(node, "_crdt"):
lynxkite-core/tests/test_ops.py CHANGED
@@ -104,4 +104,4 @@ def test_visualization_operations_display_is_populated_automatically():
104
 
105
  result = ops.CATALOGS["test"]["display_op"]()
106
  assert isinstance(result, ops.Result)
107
- assert result.output == result.display == {"display_value": 1}
 
104
 
105
  result = ops.CATALOGS["test"]["display_op"]()
106
  assert isinstance(result, ops.Result)
107
+ assert result.display == {"display_value": 1}
lynxkite-graph-analytics/src/lynxkite_graph_analytics/core.py CHANGED
@@ -222,6 +222,7 @@ async def _execute_node(node, ws, catalog, outputs):
222
  try:
223
  result = op(*inputs, **params)
224
  result.output = await await_if_needed(result.output)
 
225
  except Exception as e:
226
  if not os.environ.get("LYNXKITE_SUPPRESS_OP_ERRORS"):
227
  traceback.print_exc()
 
222
  try:
223
  result = op(*inputs, **params)
224
  result.output = await await_if_needed(result.output)
225
+ result.display = await await_if_needed(result.display)
226
  except Exception as e:
227
  if not os.environ.get("LYNXKITE_SUPPRESS_OP_ERRORS"):
228
  traceback.print_exc()