NO_JIRA Added Pharmacophore generator script to create CrossMiner que… - #99
NO_JIRA Added Pharmacophore generator script to create CrossMiner que…#99CRingroseCCDC wants to merge 1 commit into
Conversation
…ries from Ligand Overlay outputs. Includes basic tests and examples.
|
|
||
| from ccdc.pharmacophore import Pharmacophore | ||
|
|
||
| def search(query_file: Path, database_file: Path): |
There was a problem hiding this comment.
🚫 [flake8] <302> reported by reviewdog 🐶
expected 2 blank lines, found 1
|
|
||
|
|
||
|
|
||
| @dataclass |
There was a problem hiding this comment.
🚫 [flake8] <303> reported by reviewdog 🐶
too many blank lines (3)
| feature_definitions=tmp_path / "does_not_exist", | ||
| output_file=tmp_path / "query.cm", | ||
| ) | ||
|
|
There was a problem hiding this comment.
blank line at end of file
| {} | ||
| FEATURE_SUBSTRUCTURE_END | ||
| """ | ||
| def __init__( |
There was a problem hiding this comment.
🚫 [flake8] <301> reported by reviewdog 🐶
expected 1 blank line, found 0
| return matches[0] | ||
|
|
||
|
|
||
| @staticmethod |
There was a problem hiding this comment.
🚫 [flake8] <303> reported by reviewdog 🐶
too many blank lines (2)
|
|
||
| from ccdc.pharmacophore import Pharmacophore | ||
|
|
||
| def search(query_file: Path, database_file: Path): |
There was a problem hiding this comment.
🚫 [flake8] <302> reported by reviewdog 🐶
expected 2 blank lines, found 1
|
|
||
|
|
||
|
|
||
| @dataclass |
There was a problem hiding this comment.
🚫 [flake8] <303> reported by reviewdog 🐶
too many blank lines (3)
| feature_definitions=tmp_path / "does_not_exist", | ||
| output_file=tmp_path / "query.cm", | ||
| ) | ||
|
|
There was a problem hiding this comment.
blank line at end of file
| {} | ||
| FEATURE_SUBSTRUCTURE_END | ||
| """ | ||
| def __init__( |
There was a problem hiding this comment.
🚫 [flake8] <301> reported by reviewdog 🐶
expected 1 blank line, found 0
| return matches[0] | ||
|
|
||
|
|
||
| @staticmethod |
There was a problem hiding this comment.
🚫 [flake8] <303> reported by reviewdog 🐶
too many blank lines (2)
| - Access to CSD CrossMiner and the feature definitions (`.cpf`) files. | ||
| - Access to the CSD Ligand Overlay Tool. | ||
|
|
||
| ## Licensing Requirements |
There was a problem hiding this comment.
[markdownlint] reported by reviewdog 🐶
error MD009/no-trailing-spaces Trailing spaces [Expected: 0 or 2; Actual: 1]
| (either directly, or in `any`/`protein`/`small_molecule` subdirectories). | ||
| Usually, the location is `C:\users\<username>\CCDC\ccdc-software\csd-crossminer\feature_definitions` | ||
|
|
||
| ``` |
There was a problem hiding this comment.
[markdownlint] reported by reviewdog 🐶
error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
|
|
||
| ### Options for Ligand Overlay Output | ||
|
|
||
| * `cluster`: Cluster the similar pharmacophore features based on proximity |
There was a problem hiding this comment.
[markdownlint] reported by reviewdog 🐶
error MD004/ul-style Unordered list style [Expected: dash; Actual: asterisk]
| ### Options for Ligand Overlay Output | ||
|
|
||
| * `cluster`: Cluster the similar pharmacophore features based on proximity | ||
| * `projected`: Treat pharmacophore features as projected when appropriate e.g. acceptors and donors |
There was a problem hiding this comment.
[markdownlint] reported by reviewdog 🐶
error MD004/ul-style Unordered list style [Expected: dash; Actual: asterisk]
|
|
||
| ### Using the Queries Generated | ||
|
|
||
| If you would like to use the queries generated with this tool, they can be opened in CrossMiner to run a search. |
There was a problem hiding this comment.
[markdownlint] reported by reviewdog 🐶
error MD009/no-trailing-spaces Trailing spaces [Expected: 0 or 2; Actual: 1]
|
| - Access to CSD CrossMiner and the feature definitions (`.cpf`) files. | ||
| - Access to the CSD Ligand Overlay Tool. | ||
|
|
||
| ## Licensing Requirements |
There was a problem hiding this comment.
[markdownlint-fix] reported by reviewdog 🐶
| ## Licensing Requirements | |
| ## Licensing Requirements |
| * `cluster`: Cluster the similar pharmacophore features based on proximity | ||
| * `projected`: Treat pharmacophore features as projected when appropriate e.g. acceptors and donors |
There was a problem hiding this comment.
[markdownlint-fix] reported by reviewdog 🐶
| * `cluster`: Cluster the similar pharmacophore features based on proximity | |
| * `projected`: Treat pharmacophore features as projected when appropriate e.g. acceptors and donors | |
| - `cluster`: Cluster the similar pharmacophore features based on proximity | |
| - `projected`: Treat pharmacophore features as projected when appropriate e.g. acceptors and donors |
|
|
||
| ### Using the Queries Generated | ||
|
|
||
| If you would like to use the queries generated with this tool, they can be opened in CrossMiner to run a search. |
There was a problem hiding this comment.
[markdownlint-fix] reported by reviewdog 🐶
| If you would like to use the queries generated with this tool, they can be opened in CrossMiner to run a search. | |
| If you would like to use the queries generated with this tool, they can be opened in CrossMiner to run a search. |
| raise FileNotFoundError(f"Feature definitions folder {feature_definitions} does not exist.") | ||
|
|
||
| output_folder = Path(args.output_folder) if args.output_folder else Path('queries') | ||
| output_folder.mkdir(parents=True, exist_ok=True) |
There was a problem hiding this comment.
Pull request overview
Adds a new overlay_to_pharmacophore script package that converts CSD Ligand Overlay pharmacophore outputs into CrossMiner query (.cm) files, with clustering support plus bundled example data and pytest coverage.
Changes:
- Implement pharmacophore feature extraction from
.mol2pharmacophore files and optional clustering. - Generate CrossMiner query files using external
.cpffeature definitions. - Add basic pytest suite and bundled example Ligand Overlay/pharmacophore files, plus usage documentation.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/discovery/overlay_to_pharmacophore/main.py | CLI entrypoint for producing query files from one or many overlay solutions. |
| scripts/discovery/overlay_to_pharmacophore/overlay.py | Parses pharmacophore mol2 ATOM blocks into labeled feature points (with virtual points). |
| scripts/discovery/overlay_to_pharmacophore/cluster.py | Clusters nearby features (including projected feature virtual-point distance checks). |
| scripts/discovery/overlay_to_pharmacophore/write_query.py | Writes CrossMiner .cm query output, embedding referenced feature definition files. |
| scripts/discovery/overlay_to_pharmacophore/datastructures.py | Defines core datatypes (OverlayData, PharmFeaturePoint, tolerances/weights). |
| scripts/discovery/overlay_to_pharmacophore/crossminer_search.py | Example CrossMiner search helper using CSD Python API. |
| scripts/discovery/overlay_to_pharmacophore/ReadMe.md | Usage instructions, requirements, and feature-definition setup guidance. |
| scripts/discovery/overlay_to_pharmacophore/tests/tests.py | Pytest suite validating parsing, projection handling, clustering, and query writing. |
| scripts/discovery/overlay_to_pharmacophore/tests/job1/solution_01.mol2 | Bundled example Ligand Overlay solution file for tests. |
| scripts/discovery/overlay_to_pharmacophore/tests/job1/pharmacophores/solution_pharm_01.mol2 | Bundled example pharmacophore file used by tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from pathlib import Path | ||
|
|
||
| import pytest | ||
|
|
||
| from cluster import cluster_features | ||
| from datastructures import OverlayData, PharmFeaturePoint | ||
| from overlay import OverlayToPharmFeatures | ||
| from write_query import FeaturesToCrossMinerQuery | ||
|
|
||
| TESTS_DIR = Path(__file__).parent | ||
| REPO_ROOT = TESTS_DIR.parent | ||
| JOB_FOLDER = TESTS_DIR / "job1" |
| def __repr__(self): | ||
| return ( | ||
| f"PharmFeaturePoint({self.x}, {self.y}, {self.z}, " | ||
| f"label={self.label}, virtual_points={self.virtual_point}), " | ||
| ) |
| elif prefix == 'NL': | ||
| if last_feature_point is None: | ||
| raise ValueError("Virtual point found before its parent feature point.") | ||
| last_feature_point.virtual_point = np.array([x, y, z], dtype=float) |
| parser = argparse.ArgumentParser( | ||
| description="Create Pharmacophore Features from a Ligand Overlay" | ||
| ) | ||
| parser.add_argument('-i', '--input_folder', type=str, help='Input file(s) path.') |
| @@ -0,0 +1,76 @@ | |||
| import argparse | |||
There was a problem hiding this comment.
I think we put this header at the top of each oy and ipynb file which we publish on the open source:
'''
This script can be used for any purpose without limitation subject to the
conditions at https://www.ccdc.cam.ac.uk/Community/Pages/Licences/v2.aspx
This permission notice and the following statement of attribution must be
included in all copies or substantial portions of this script.
"date of creation": created by the Cambridge Crystallographic Data Centre
'''
| @@ -0,0 +1,18 @@ | |||
| from pathlib import Path | |||
There was a problem hiding this comment.
I'm not sure that it is called from anywhere. You can probs add a flag like --run_search so users could do that without any extra actions.
| if last_feature_point is None: | ||
| raise ValueError("Virtual point found before its parent feature point.") | ||
| last_feature_point.virtual_point = np.array([x, y, z], dtype=float) | ||
| last_feature_point.label = 'ring_planar_projected' |
There was a problem hiding this comment.
This line suggests that it is always a planar ring. I have an example where it sems to be just a ring, I'll share the example




…ries from Ligand Overlay outputs. Includes basic tests and examples.