Skip to content

Commit 1940285

Browse files
committed
Updated docs with Colab intro demo
1 parent 0c49594 commit 1940285

8 files changed

Lines changed: 333 additions & 182 deletions

File tree

main/_assets/icons_readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Icons can be found under main/\_overrides/.icons/carbon.
Lines changed: 4 additions & 0 deletions
Loading

main/blog/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
# Tutorials
22

3+
!!! Newcomers
4+
5+
If you're new to OpenAD, we highly recommend to take our our 3-step demo on Google Colab.
6+
7+
[:carbon-icn-colab: Colab Demo](https://colab.research.google.com/drive/13r9LojtJTLZ8MEO1KNqJAKTieWmEUJQM){ .md-button .md-button--primary target=\_blank .btn-large }
8+
9+
<hr>

main/blog/posts/tutorials/plugins/01-create-plugin/_post.md

Lines changed: 67 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,29 @@ We'll use Greg Landrum's [2022 blog post on generating fingerprints with RDKIt](
2222
This is an example plugin implementation. For a more general (and shorter) guide on building plugins for OpenAD, check out our [Plugin Developer Guide](/docs/plugin-development/index.md).
2323

2424
!!! note
25-
Download the finished plugin from GitHub: [openad-plugin-tutorial](https://github.com/acceleratedscience/openad-plugin-tutorial)
25+
Download the finished plugin from GitHub: [openad-plugin-tutorial](https://github.com/acceleratedscience/openad-plugin-tutorial)
2626

2727
## 1. Creating the Scaffold
2828

2929
<div class="padded-list" markdown>
3030

3131
1. Clone the [demo plugin repository](https://github.com/acceleratedscience/openad-plugin-demo) to use as a scaffold.
32+
3233
```shell
3334
git clone --no-remote git@github.com:acceleratedscience/openad-plugin-demo.git
3435
```
35-
36+
3637
1. Rename the plugin directories:
37-
`/openad-plugin-demo/openad_plugin_demo` to `/openad-plugin-fingerprint/openad_plugin_fingerprint`
38+
`/openad-plugin-demo/openad_plugin_demo` to `/openad-plugin-fingerprint/openad_plugin_fingerprint`
3839

3940
```shell
4041
mv openad-plugin-demo openad-plugin-fingerprint
4142
```
43+
4244
```shell
4345
cd openad-plugin-fingerprint
4446
```
47+
4548
```shell
4649
mv openad_plugin_demo openad_plugin_fingerprint
4750
```
@@ -51,6 +54,7 @@ git clone --no-remote git@github.com:acceleratedscience/openad-plugin-demo.git
5154
3. Update `pyproject.toml` and set the `name` field to `openad_plugin_fingerprint`.
5255

5356
4. Update `plugin_metadata.yaml` - this is used for the help display.
57+
5458
```shell
5559
name: Fingerprint
5660
namespace: fp
@@ -70,11 +74,12 @@ website: null
7074
4. Open `/calculate_fp/command.py` and look for `# <-- UPDATE` and update the import statements so they point to `openad_plugin_fingerprint`
7175

7276
5. Install the plugin
73-
If you haven't already, make sure your file cursor is pointed to the parent `/openad-plugin-fingerprint` directory, and if you have installed OpenAD in a virtual environment, of course make sure you have the virtual environment activated. We'll install the plugin with the `--editable` flag, so we can update the code and see the results in real time.
77+
If you haven't already, make sure your working directory is pointed to the parent `/openad-plugin-fingerprint` directory, and if you have installed OpenAD in a virtual environment, of course make sure you have the virtual environment activated. We'll install the plugin with the `--editable` flag, so we can update the code and see the results in real time.
7478

7579
```shell
7680
cd openad-plugin-fingerprint
7781
```
82+
7883
```shell
7984
pip install -e .
8085
```
@@ -91,41 +96,43 @@ We'll start with the command documentation. The `help_dict_create_v2()` function
9196
9297
Let's start with defining what our plugin will do:
9398
94-
- Input: one or more SMILES identifiers, or the molecules in your molecule working set (MWS)
95-
- Calculate one of 5 types of fingerprints:
96-
- `mfp` - Morgan fingerprint (default)
97-
- `rdk` - RDKit fingerprint
98-
- `ap` - Atom pair fingerprint
99-
- `tt` - Topological torsion fingerprint
100-
- `fm` - Feature Morgan fingerprint
101-
- Optionally store the results in the MWS, if the MWS was the input source
99+
- Input: one or more SMILES identifiers, or the molecules in your molecule working set (MWS)
100+
- Calculate one of 5 types of fingerprints:
101+
- `mfp` - Morgan fingerprint (default)
102+
- `rdk` - RDKit fingerprint
103+
- `ap` - Atom pair fingerprint
104+
- `tt` - Topological torsion fingerprint
105+
- `fm` - Feature Morgan fingerprint
106+
- Optionally store the results in the MWS, if the MWS was the input source
102107
103108
### Defining Command Structure
104109
105110
We would like to enable the following command variations:
106111
107-
- `fp calc for C1=CC(=C(C=C1CCN)O)O`
108-
Calculate default fingerprint for a single molecule.
109-
- `fp calc for [CC(C)[N+](=O)[O-],O=C1CNC(=O)N1,Nc1ccccc1O]`
110-
Calculate default fingerprint for a list of molecules.
111-
- `fp calc for @mws`
112-
Calculate default fingerprint for all molecules in my molecule working set.
113-
- `fp calc for @mws update`
114-
Calculate default fingerprint for all molecules in my MWS, then update MWS with results.
115-
- `fp calc tt for C1=CC(=C(C=C1CCN)O)O`
116-
Calculate topological torsion fingerprint for a single molecule.
117-
- etc.
118-
112+
- `fp calc for C1=CC(=C(C=C1CCN)O)O`
113+
Calculate default fingerprint for a single molecule.
114+
- `fp calc for [CC(C)[N+](=O)[O-],O=C1CNC(=O)N1,Nc1ccccc1O]`
115+
Calculate default fingerprint for a list of molecules.
116+
- `fp calc for @mws`
117+
Calculate default fingerprint for all molecules in my molecule working set.
118+
- `fp calc for @mws update`
119+
Calculate default fingerprint for all molecules in my MWS, then update MWS with results.
120+
- `fp calc tt for C1=CC(=C(C=C1CCN)O)O`
121+
Calculate topological torsion fingerprint for a single molecule.
122+
- etc.
123+
119124
### Notating Command Structure
120125
121126
We can summarize this structure in three variations:
122127
123128
```shell
124129
fp calc [ <fp_type> ] for <smiles>
125130
```
131+
126132
```shell
127133
fp calc [ <fp_type> ] for [<smiles>,<smiles>,...]
128134
```
135+
129136
```shell
130137
fp calc [ <fp_type> ] for @mws [ update ]
131138
```
@@ -192,7 +199,6 @@ You can either pass a single SMILES, a a list of smiles, or refer to your molecu
192199
<cmd>show mol Nc1ccccc1O</cmd>
193200
```
194201

195-
196202
To see the result, you can now run:
197203

198204
```shell
@@ -209,23 +215,23 @@ Earlier you duplicated `commands/hello_world` and renamed it to `commands/calcul
209215

210216
### Notes
211217

212-
- The command definition is created using PyParsing. If you're new to PyParsing, check out our [PyParsing 101](/docs/plugin-development/pyparsing-101.md) crash course to get up to speed in no time.
213-
- Each word in a command is represented by a "grammar definition". We'll store our grammar definitions in `plugin_grammar_def.py` so they can be reused across commands.
214-
- We have a number of readymade grammar definitions that can be imported as building blocks. You can check these out here: [openad_tools.grammar_def.py](https://github.com/acceleratedscience/openad-tools/blob/main/openad_tools/grammar_def.py)
218+
- The command definition is created using PyParsing. If you're new to PyParsing, check out our [PyParsing 101](/docs/plugin-development/pyparsing-101.md) crash course to get up to speed in no time.
219+
- Each word in a command is represented by a "grammar definition". We'll store our grammar definitions in `plugin_grammar_def.py` so they can be reused across commands.
220+
- We have a number of readymade grammar definitions that can be imported as building blocks. You can check these out here: [openad_tools.grammar_def.py](https://github.com/acceleratedscience/openad-tools/blob/main/openad_tools/grammar_def.py)
215221

216222
### Compiling the Command
217223

218224
<div class="padded-list" markdown>
219225

220-
1. We want to support an individual molecule identifier as well as a list of identifiers as input. For this we can simply import the `molecule_identifier_s` definition, which handles both.
226+
1. We want to support an individual molecule identifier as well as a list of identifiers as input. For this we can simply import the `molecule_identifier_s` definition, which handles both.
221227

222228
```python
223229
from openad_tools.grammar_def import molecule_identifier_s
224230
```
225231

226-
2. Then we'll create the other parts of our command and store them in `plugin_grammar_def.py`.
232+
2. Then we'll create the other parts of our command and store them in `plugin_grammar_def.py`.
227233
Two things to note: we'll support both `calc` as `calculate`, and the identifier for the word `for` is called `f_or` so it doesn't interfer with the Python's "for" used for looping.
228-
234+
229235
```python
230236
# File: plugin_grammar_def.py
231237
calculate = py.CaselessKeyword("calc") | py.CaselessKeyword("calculate")
@@ -241,27 +247,27 @@ Earlier you duplicated `commands/hello_world` and renamed it to `commands/calcul
241247
)
242248
clause_update = py.Optional(py.CaselessKeyword("update"))("update")
243249
```
250+
244251
```python
245252
# File: command.py
246253
from openad_plugin_fingerprint.plugin_grammar_def import calculate, fp_type, f_or, clause_update
247254
```
248255

249-
3. Let's now put them together to create our command.
250-
251-
```python
252-
# Command definition
253-
statements.append(
254-
py.Forward(
255-
py.CaselessKeyword(PLUGIN_NAMESPACE)
256-
+ calculate
257-
+ py.Optional(fp_type)
258-
+ f_or
259-
+ (molecule_working_set | molecule_identifier_s)
260-
+ clause_update
261-
)(self.parser_id)
262-
)
263-
```
264-
</div>
256+
3. Let's now put them together to create our command.
257+
```python
258+
# Command definition
259+
statements.append(
260+
py.Forward(
261+
py.CaselessKeyword(PLUGIN_NAMESPACE)
262+
+ calculate
263+
+ py.Optional(fp_type)
264+
+ f_or
265+
+ (molecule_working_set | molecule_identifier_s)
266+
+ clause_update
267+
)(self.parser_id)
268+
)
269+
```
270+
</div>
265271

266272
## 4. Testing the Parser
267273

@@ -276,25 +282,31 @@ def exec_command(self, cmd_pointer, parser):
276282
```
277283

278284
Input / output #1:
285+
279286
```shell
280287
fp calc for C1=CC(=C(C=C1CCN)O)O
281288
```
289+
282290
```shell
283291
{'identifiers': ['C1=CC(=C(C=C1CCN)O)O'], 'plugin_fingerprint_calculate_fp': ['fp', 'calc', 'for', ['C1=CC(=C(C=C1CCN)O)O']]}
284292
```
285293

286294
Input / output #2:
295+
287296
```shell
288297
fp calc ap for [CC(C)[N+](=O)[O-],O=C1CNC(=O)N1,Nc1ccccc1O]
289298
```
299+
290300
```shell
291301
{'fp_type': 'ap', 'identifiers': ['CC(C)[N+](=O)[O-]', 'O=C1CNC(=O)N1', 'Nc1ccccc1O'], 'plugin_fingerprint_calculate_fp': ['fp', 'calc', 'ap', 'for', 'CC(C)[N+](=O)[O-]', 'O=C1CNC(=O)N1', 'Nc1ccccc1O']}
292302
```
293303

294-
Input / output #3:
304+
Input / output #3:
305+
295306
```shell
296307
fp calc ap for @mws update
297308
```
309+
298310
```shell
299311
{'fp_type': 'ap', 'mws': '@mws', 'update': 'update', 'plugin_fingerprint_calculate_fp': ['fp', 'calc', 'ap', 'for', '@mws', 'update']}
300312
```
@@ -306,6 +318,7 @@ This is looking good. Let's move on to the command's logic.
306318
To keep things organized, we'll put the functionality in a separate file which we'll call `calculate_fp.py` and store it in the command folder. This way we can separate the parsing logic from the function logic and keep things organized.
307319

308320
Parsing logic:
321+
309322
```python
310323
# File: command.py
311324
from openad_plugin_fingerprint.commands.calculate_fp.calculate_fp import calculate_fp, fp_to_list
@@ -358,6 +371,7 @@ def exec_command(self, cmd_pointer, parser):
358371
```
359372

360373
Function logic:
374+
361375
```python
362376
# RDKit
363377
from rdkit import Chem
@@ -462,6 +476,7 @@ print(f"Numpy array:\n {fingerprint_array[:10]} ... (showing first 10)\n")
462476
```
463477

464478
Output:
479+
465480
```shell
466481
Fingerprint class name:
467482
ExplicitBitVect
@@ -483,18 +498,21 @@ Numpy array:
483498

484499
More practical would be to update all molecules in the MWS with a certain fingerprint.
485500
To demo this, we'll first need to add a few molecules to the MWS:
501+
486502
```shell
487503
add mol CC(C)[N+](=O)[O-] basic force
488504
add mol O=C1CNC(=O)N1 basic force
489505
add mol Nc1ccccc1O basic force
490506
```
491507

492508
Then we can calculate the topological torsion fingerprint and update our molecules with the result:
509+
493510
```python
494511
fp calc ap for @mws update
495512
```
496513

497514
Let's check one of the results:
515+
498516
```shell
499517
show mol CC(C)[N+](=O)[O-]
500518
```
@@ -508,4 +526,4 @@ show mol CC(C)[N+](=O)[O-]
508526
You've created your first plugin.
509527

510528
!!! note
511-
Download the finished plugin from GitHub: [openad-plugin-tutorial](https://github.com/acceleratedscience/openad-plugin-tutorial)
529+
Download the finished plugin from GitHub: [openad-plugin-tutorial](https://github.com/acceleratedscience/openad-plugin-tutorial)

0 commit comments

Comments
 (0)