diff --git a/.github/workflows/run-notebooks.yml b/.github/workflows/run-notebooks.yml new file mode 100644 index 0000000..0cf7a17 --- /dev/null +++ b/.github/workflows/run-notebooks.yml @@ -0,0 +1,91 @@ +name: Run Jupyter Notebooks + +on: + push: + branches: + - "**" + pull_request: + types: [opened, synchronize, reopened] + +jobs: + run-notebooks: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install dependencies + run: | + pip install --upgrade pip + pip install chemaxon jupyter nbconvert ipykernel + python -m ipykernel install --user --name python3 + + - name: Run 01_basic_functions.ipynb + run: | + jupyter nbconvert --to notebook --execute \ + --ExecutePreprocessor.timeout=600 \ + --output /tmp/01_basic_functions_executed.ipynb \ + jupyter/01_basic_functions.ipynb + + - name: Run 02_calculators.ipynb + run: | + jupyter nbconvert --to notebook --execute \ + --ExecutePreprocessor.timeout=600 \ + --output /tmp/02_calculators_executed.ipynb \ + jupyter/02_calculators.ipynb + + - name: Run 03_molecular_similarity.ipynb + run: | + jupyter nbconvert --to notebook --execute \ + --ExecutePreprocessor.timeout=600 \ + --output /tmp/03_molecular_similarity_executed.ipynb \ + jupyter/03_molecular_similarity.ipynb + + - name: Run 04_standardizer.ipynb + run: | + jupyter nbconvert --to notebook --execute \ + --ExecutePreprocessor.timeout=600 \ + --output /tmp/04_standardizer_executed.ipynb \ + jupyter/04_standardizer.ipynb + + - name: Run 05_structure_checker.ipynb + run: | + jupyter nbconvert --to notebook --execute \ + --ExecutePreprocessor.timeout=600 \ + --output /tmp/05_structure_checker_executed.ipynb \ + jupyter/05_structure_checker.ipynb + + - name: Run 06_molecule_search.ipynb + run: | + jupyter nbconvert --to notebook --execute \ + --ExecutePreprocessor.timeout=600 \ + --output /tmp/06_molecule_search_executed.ipynb \ + jupyter/06_molecule_search.ipynb + + - name: Run 07_pandas_integration_examples.ipynb + run: | + jupyter nbconvert --to notebook --execute \ + --ExecutePreprocessor.timeout=600 \ + --output /tmp/07_pandas_integration_examples_executed.ipynb \ + jupyter/07_pandas_integration_examples.ipynb + + - name: Run 08_fingerprint_calculations.ipynb + run: | + jupyter nbconvert --to notebook --execute \ + --ExecutePreprocessor.timeout=600 \ + --output /tmp/08_fingerprint_calculations_executed.ipynb \ + jupyter/08_fingerprint_calculations.ipynb + + - name: Upload executed notebooks as artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: executed-notebooks + path: /tmp/*_executed.ipynb + retention-days: 7 \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..e3c9ae0 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,209 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, +reproduction, + and distribution as defined by Sections 1 through 9 of this +document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under +common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making +modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or +Object + form, that is based on (or derived from) the Work and for which +the + editorial revisions, annotations, elaborations, or other +modifications + represent, as a whole, an original work of authorship. For the +purposes + of this License, Derivative Works shall not include works that +remain + separable from, or merely link (or bind by name) to the interfaces +of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or +additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright +owner + or by an individual or Legal Entity authorized to submit on behalf +of + the copyright owner. For the purposes of this definition, +"submitted" + means any form of electronic, verbal, or written communication +sent + to the Licensor or its representatives, including but not limited +to + communication on electronic mailing lists, source code control +systems, + and issue tracking systems that are managed by, or on behalf of, +the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a +Contribution." + + "Contributor" shall mean Licensor and any individual or Legal +Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have +made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute +must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; +or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The +contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state +otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or +modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the +trade + names, trademarks, service marks, or product names of the +Licensor, + except as required for reasonable and customary use in describing +the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or +conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this +License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, +special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by +reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README.md b/README.md index 187541f..258eb88 100644 --- a/README.md +++ b/README.md @@ -10,5 +10,5 @@ This repository contains usage examples for [Chemaxon Python API](https://docs.c ## Note -If you have any question, suggestion please feel free to contact us at -[`chemlib@chemaxon.com`](mailto:chemlib@chemaxon.com) +If you have any question, suggestion please feel free to contact us via +[FreshDesk support](https://chemaxon.freshdesk.com/a/tickets/new) diff --git a/jupyter/01_basic_functions.ipynb b/jupyter/01_basic_functions.ipynb index 3de9c46..c9660dc 100644 --- a/jupyter/01_basic_functions.ipynb +++ b/jupyter/01_basic_functions.ipynb @@ -12,27 +12,15 @@ }, { "cell_type": "code", - "execution_count": 1, "id": "0fade33e-d909-44f6-a37b-ac210794ff72", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Collecting chemaxon\n", - " Using cached chemaxon-25.1.0b5-cp313-cp313-macosx_14_0_arm64.whl.metadata (1.9 kB)\n", - "Using cached chemaxon-25.1.0b5-cp313-cp313-macosx_14_0_arm64.whl (57.6 MB)\n", - "Installing collected packages: chemaxon\n", - "Successfully installed chemaxon-25.1.0b5\n" - ] - } - ], "source": [ - "import sys\n", + " import sys\n", "\n", - "!{sys.executable} -m pip install chemaxon" - ] + " !{sys.executable} -m pip install chemaxon" + ], + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -44,27 +32,17 @@ }, { "cell_type": "code", - "execution_count": 2, "id": "76ca42b3-30a1-4d4f-971c-e37d3af1c1b7", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Version: 25.1.0b5\n", - "CCL version: 25.1.3\n", - "CCL build date: 2025-04-24\n" - ] - } - ], "source": [ "import chemaxon\n", "\n", "print('Version: ', chemaxon.__version__)\n", "print('CCL version: ', chemaxon.ccl_version())\n", "print('CCL build date:', chemaxon.ccl_build_date())" - ] + ], + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -76,27 +54,13 @@ }, { "cell_type": "code", - "execution_count": 3, "id": "8d9f4205-d0a9-467c-97e9-054d78bdde60", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'product': 'Python API',\n", - " 'expiration': '2025-06-30',\n", - " 'licensee': 'Chemaxon',\n", - " 'state': 'VALID'}]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ "[lic for lic in chemaxon.licenses() if lic['product'] == 'Python API']" - ] + ], + "outputs": [], + "execution_count": null }, { "cell_type": "markdown", @@ -659,12 +623,219 @@ ] }, { + "metadata": {}, + "cell_type": "markdown", + "source": "### **Molecule property handling**", + "id": "6588cf0d348eed22" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "You can store custom properties in the __Molecule__ objects using the __set_property__ and __get_property__ methods. A dictionary of the __Molecule__ object's properties can also be reteived using the __get_properties_dict__ method.\n", + "\n", + "_**Note:** Modifying that dictionary will not change the properties of the __Molecule__ object. For that, you should use __set_property__ method._" + ], + "id": "d6d63c6344fc92ac" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Supported property value types are: __str__, __int__, __float__, __bool__, __list__ (of int, float). Considering the list of scalar values, the api is aligned to the behavior of Chemaxon Java API. So, double values can only be used with dots, not with commas.", + "id": "c5c0afd0a3dd4cdd" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "#### Reading properties:", + "id": "4df4fca46fb9372d" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-03T08:09:55.633222159Z", + "start_time": "2026-02-03T08:09:55.544785396Z" + } + }, "cell_type": "code", - "execution_count": null, - "id": "02aab71e-3d23-4713-98d9-ba75d47511af", + "source": [ + "from chemaxon import open_for_import\n", + "\n", + "with open_for_import('mol_with_properties.mrv') as mol_iterator:\n", + " mols = list(mol_iterator)\n", + "\n", + "mols[0]" + ], + "id": "36b4c96ad9ab34b8", + "outputs": [ + { + "data": { + "text/plain": [ + "Molecule(_source='\\n\\nTRUEasd424.2asd1 2 3 4 542TRUE1.5 2.7 3.3 4.567\\n', _format='mrv', _to_svg=, bonds=(Bond(type=1, atoms=(0, 1)), Bond(type=2, atoms=(1, 2)), Bond(type=1, atoms=(2, 3)), Bond(type=2, atoms=(3, 4)), Bond(type=1, atoms=(4, 5)), Bond(type=2, atoms=(0, 5)), Bond(type=2, atoms=(7, 8)), Bond(type=1, atoms=(8, 9)), Bond(type=2, atoms=(9, 10)), Bond(type=1, atoms=(10, 11)), Bond(type=1, atoms=(6, 7)), Bond(type=2, atoms=(6, 11)), Bond(type=1, atoms=(4, 6)), Bond(type=2, atoms=(13, 14)), Bond(type=1, atoms=(14, 15)), Bond(type=2, atoms=(15, 16)), Bond(type=1, atoms=(16, 17)), Bond(type=1, atoms=(12, 13)), Bond(type=2, atoms=(12, 17)), Bond(type=1, atoms=(9, 12))), atoms=(Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(0, 1)), Bond(type=2, atoms=(0, 5)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(0, 1)), Bond(type=2, atoms=(1, 2)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(1, 2)), Bond(type=1, atoms=(2, 3)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(2, 3)), Bond(type=2, atoms=(3, 4)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(3, 4)), Bond(type=1, atoms=(4, 5)), Bond(type=1, atoms=(4, 6)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(4, 5)), Bond(type=2, atoms=(0, 5)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(6, 7)), Bond(type=2, atoms=(6, 11)), Bond(type=1, atoms=(4, 6)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(7, 8)), Bond(type=1, atoms=(6, 7)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(7, 8)), Bond(type=1, atoms=(8, 9)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(8, 9)), Bond(type=2, atoms=(9, 10)), Bond(type=1, atoms=(9, 12)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(9, 10)), Bond(type=1, atoms=(10, 11)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(10, 11)), Bond(type=2, atoms=(6, 11)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(12, 13)), Bond(type=2, atoms=(12, 17)), Bond(type=1, atoms=(9, 12)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(13, 14)), Bond(type=1, atoms=(12, 13)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(13, 14)), Bond(type=1, atoms=(14, 15)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(14, 15)), Bond(type=2, atoms=(15, 16)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(15, 16)), Bond(type=1, atoms=(16, 17)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(16, 17)), Bond(type=2, atoms=(12, 17))))), native_handle=34, _to_str=, properties=[, , , , , ])" + ], + "image/svg+xml": "asd1 2 3 4 542TRUE1.5 2.7 3.3 4.567\n" + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 31 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-03T09:24:48.581391621Z", + "start_time": "2026-02-03T09:24:48.531897571Z" + } + }, + "cell_type": "code", + "source": [ + "from chemaxon import open_for_import\n", + "\n", + "with open_for_import('mol_with_properties.mrv') as mol_iterator:\n", + " mols = list(mol_iterator)\n", + "\n", + "mol = mols[0]\n", + "\n", + "print(\"Number of properties: \" + str(len(mol.properties)))\n", + "print(\"\\ttest_str_property -> \" + mol.get_property(\"test_str_property\"))\n", + "print(\"\\ttest_double_property -> \" + str(mol.get_property(\"test_double_property\")))\n", + "print(\"\\ttest_int_property -> \" + str(mol.get_property(\"test_int_property\")))\n", + "print(\"\\ttest_boolean_property -> \" + str(mol.get_property(\"test_boolean_property\")))\n", + "print(\"\\ttest_int_array_property -> \" + str(mol.get_property(\"test_int_array_property\")))\n", + "print(\"\\ttest_double_array_property -> \" + str(mol.get_property(\"test_double_array_property\")))\n", + "\n", + "print()\n", + "print(\"All properties as dict: \\n\" + str(mol.get_property_dict()))" + ], + "id": "3174830bcf4c2edd", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of properties: 6\n", + "\ttest_str_property -> asd\n", + "\ttest_double_property -> 4.2\n", + "\ttest_int_property -> 42\n", + "\ttest_boolean_property -> True\n", + "\ttest_int_array_property -> [1, 2, 3, 4, 5]\n", + "\ttest_double_array_property -> [1.2, 3.4, 5.22, 6.7889]\n", + "\n", + "All properties as dict: \n", + "{'test_boolean_property': True, 'test_str_property': 'asd', 'test_int_property': 42, 'test_double_property': 4.2, 'test_int_array_property': [1, 2, 3, 4, 5], 'test_double_array_property': [1.2, 3.4, 5.22, 6.7889]}\n" + ] + } + ], + "execution_count": 36 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "#### Adding properties to the molecule object:\n", + "\n", + "Supported types are: __bool__, __int__, __float__, __str__, __list__ of int, __list__ of float__. Note that the list of scalar values should be provided as a list of the corresponding type, not as a string. So, double values can only be used with dots, not with commas." + ], + "id": "ddc34a664bc27eed" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-06T14:26:44.259402624Z", + "start_time": "2026-02-06T14:26:44.197003574Z" + } + }, + "cell_type": "code", + "source": [ + "from chemaxon import import_mol\n", + "\n", + "mol = import_mol('CC(=O)NC1=CC=C(O)C=C1')\n", + "\n", + "mol.set_property('test_str_property', 'test string')\n", + "mol.set_property('test_double_property', 3.14)\n", + "mol.set_property('test_int_property', 42)\n", + "mol.set_property('test_boolean_property', True)\n", + "mol.set_property('test_int_array_property', [1, 2, 3])\n", + "mol.set_property('test_double_array_property', [1.1, 2.2, 3.3])\n", + "\n", + "print(\"Number of properties: \" + str(len(mol.properties)))\n", + "print(\"\\ttest_str_property -> \" + mol.get_property(\"test_str_property\"))\n", + "\n", + "\n", + "# Properties are persisted on export of course:\n", + "from chemaxon import export_mol\n", + "\n", + "print(export_mol(mol, 'sdf'))" + ], + "id": "cfec6f58a612938e", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of properties: 6\n", + "\ttest_str_property -> test string\n", + "\n", + " Mrv2503 02062615262D \n", + "\n", + " 11 11 0 0 0 0 999 V2000\n", + " 0.0000 3.3000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0.0000 2.4750 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n", + " -0.7145 2.0625 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0.7145 2.0625 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0.7145 1.2375 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 1.4289 0.8250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 1.4289 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0.7145 -0.4125 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0.7145 -1.2375 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0.0000 0.8250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 1 2 1 0 0 0 0\n", + " 2 3 2 0 0 0 0\n", + " 2 4 1 0 0 0 0\n", + " 4 5 1 0 0 0 0\n", + " 5 6 2 0 0 0 0\n", + " 6 7 1 0 0 0 0\n", + " 7 8 2 0 0 0 0\n", + " 8 9 1 0 0 0 0\n", + " 8 10 1 0 0 0 0\n", + " 10 11 2 0 0 0 0\n", + " 5 11 1 0 0 0 0\n", + "M END\n", + "> \n", + "test string\n", + "\n", + "> \n", + "3.14\n", + "\n", + "> \n", + "42\n", + "\n", + "> \n", + "True\n", + "\n", + "> \n", + "[1, 2, 3]\n", + "\n", + "> \n", + "[1.1, 2.2, 3.3]\n", + "\n", + "$$$$\n", + "\n" + ] + } + ], + "execution_count": 2 + }, + { "metadata": {}, + "cell_type": "code", "outputs": [], - "source": [] + "execution_count": null, + "source": "", + "id": "1f169e93d6c6c99d" } ], "metadata": { diff --git a/jupyter/02_calculators.ipynb b/jupyter/02_calculators.ipynb index d430751..527aa8e 100644 --- a/jupyter/02_calculators.ipynb +++ b/jupyter/02_calculators.ipynb @@ -12,177 +12,37 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "4651ecec-55a8-48d2-a76e-a5c8487ef569", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "logP: 0.91\n", - "logD[pH 9.0]: 0.78\n", - "pKa: [atom: 8, pka: 9.46 (ACIDIC)], [atom: 2, pka: -4.36 (BASIC)], [atom: 8, pka: -5.94 (BASIC)]\n", - "hlb: 14.14\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T07:37:44.342663665Z", + "start_time": "2026-03-16T07:37:44.281900876Z" } - ], + }, + "outputs": [], "source": [ "from chemaxon import import_mol, logp, logd, pka, hlb\n", "\n", "mol = import_mol('CC(=O)NC1=CC=C(O)C=C1') # paracetamol\n", "\n", "print('logP: ', logp(mol))\n", - "print('logD[pH 9.0]:', logd(mol, pH=9.0))\n", + "print('logD[pH 9.0]:', logd(mol, ph=9.0))\n", "print('pKa: ', pka(mol))\n", "print('hlb: ', hlb(mol))" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "a23b02ed-fe3b-419e-95e2-a2fee78abb3f", - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "CH3O-7.14 OOH3.41 O\n" - ], - "text/plain": [ - "Molecule(_mrv='\\nTCC\\n', _mrv_to_svg=, bonds=(Bond(type=1, atoms=(0, 1)), Bond(type=2, atoms=(1, 2)), Bond(type=1, atoms=(1, 3)), Bond(type=1, atoms=(3, 4)), Bond(type=2, atoms=(4, 5)), Bond(type=1, atoms=(5, 6)), Bond(type=2, atoms=(6, 7)), Bond(type=1, atoms=(7, 8)), Bond(type=2, atoms=(8, 9)), Bond(type=1, atoms=(4, 9)), Bond(type=1, atoms=(9, 10)), Bond(type=1, atoms=(10, 11)), Bond(type=2, atoms=(10, 12))), atoms=(Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(0, 1)),)), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(0, 1)), Bond(type=2, atoms=(1, 2)), Bond(type=1, atoms=(1, 3)))), Atom(symbol='O', atom_number=8, mass_number=0, bonds=(Bond(type=2, atoms=(1, 2)),)), Atom(symbol='O', atom_number=8, mass_number=0, bonds=(Bond(type=1, atoms=(1, 3)), Bond(type=1, atoms=(3, 4)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(3, 4)), Bond(type=2, atoms=(4, 5)), Bond(type=1, atoms=(4, 9)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(4, 5)), Bond(type=1, atoms=(5, 6)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(5, 6)), Bond(type=2, atoms=(6, 7)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(6, 7)), Bond(type=1, atoms=(7, 8)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(7, 8)), Bond(type=2, atoms=(8, 9)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=2, atoms=(8, 9)), Bond(type=1, atoms=(4, 9)), Bond(type=1, atoms=(9, 10)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(9, 10)), Bond(type=1, atoms=(10, 11)), Bond(type=2, atoms=(10, 12)))), Atom(symbol='O', atom_number=8, mass_number=0, bonds=(Bond(type=1, atoms=(10, 11)),)), Atom(symbol='O', atom_number=8, mass_number=0, bonds=(Bond(type=2, atoms=(10, 12)),))))" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T07:30:40.398412454Z", + "start_time": "2026-03-16T07:30:38.972522816Z" } - ], + }, + "outputs": [], "source": [ "from chemaxon import import_mol, pka\n", "\n", @@ -192,6 +52,35 @@ "pka_result.structure" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "657e9aeb-8a20-47cd-8443-3df87c474e07", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "\n", + "!{sys.executable} -m pip install matplotlib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51086e75-7995-4010-96ef-b96444770342", + "metadata": {}, + "outputs": [], + "source": [ + "from chemaxon import logd_ph_range, PhRange\n", + "import matplotlib.pyplot as pyplt\n", + "\n", + "res = logd_ph_range(import_mol('aspirin'), PhRange(0, 14, 0.5))\n", + "pyplt.plot([r.pH for r in res],[r.logd for r in res])\n", + "pyplt.title(\"logD by pH\")\n", + "pyplt.xlabel(\"pH\")\n", + "pyplt.ylabel(\"logD\")" + ] + }, { "cell_type": "markdown", "id": "303cb2c6-84d3-4511-8c62-af1141dbefd5", @@ -204,23 +93,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "bc97b4ee-ecc0-41da-b0c1-de15e3dde46b", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Formula: C9H8O4\n", - "Atom count: 21\n", - "Ring count: 1\n", - "Fsp3: 0.1111111111111111\n", - "logP: 1.238089698333333\n", - "logS: -1.8489350401969602\n" - ] - } - ], + "outputs": [], "source": [ "from chemaxon import evaluate\n", "\n", @@ -242,163 +118,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "edca4a1e-dda0-41e4-9a3c-1062765dcb24", "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "OOOO\n" - ], - "text/plain": [ - "Molecule(_mrv='\\n\\n', _mrv_to_svg=, bonds=(Bond(type=0, atoms=(0, 1)), Bond(type=0, atoms=(1, 2)), Bond(type=0, atoms=(1, 3)), Bond(type=1, atoms=(3, 4)), Bond(type=1, atoms=(4, 5)), Bond(type=0, atoms=(5, 6)), Bond(type=0, atoms=(6, 7)), Bond(type=1, atoms=(6, 8)), Bond(type=1, atoms=(8, 9)), Bond(type=4, atoms=(9, 10)), Bond(type=4, atoms=(10, 11)), Bond(type=4, atoms=(11, 12)), Bond(type=4, atoms=(12, 13)), Bond(type=4, atoms=(13, 14)), Bond(type=4, atoms=(9, 14)), Bond(type=1, atoms=(14, 15)), Bond(type=0, atoms=(5, 15)), Bond(type=0, atoms=(15, 16)), Bond(type=1, atoms=(4, 17)), Bond(type=4, atoms=(17, 18)), Bond(type=4, atoms=(18, 19)), Bond(type=4, atoms=(19, 20)), Bond(type=4, atoms=(20, 21)), Bond(type=4, atoms=(21, 22)), Bond(type=4, atoms=(17, 22))), atoms=(Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=0, atoms=(0, 1)),)), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=0, atoms=(0, 1)), Bond(type=0, atoms=(1, 2)), Bond(type=0, atoms=(1, 3)))), Atom(symbol='O', atom_number=8, mass_number=0, bonds=(Bond(type=0, atoms=(1, 2)),)), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=0, atoms=(1, 3)), Bond(type=1, atoms=(3, 4)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(3, 4)), Bond(type=1, atoms=(4, 5)), Bond(type=1, atoms=(4, 17)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(4, 5)), Bond(type=0, atoms=(5, 6)), Bond(type=0, atoms=(5, 15)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=0, atoms=(5, 6)), Bond(type=0, atoms=(6, 7)), Bond(type=1, atoms=(6, 8)))), Atom(symbol='O', atom_number=8, mass_number=0, bonds=(Bond(type=0, atoms=(6, 7)),)), Atom(symbol='O', atom_number=8, mass_number=0, bonds=(Bond(type=1, atoms=(6, 8)), Bond(type=1, atoms=(8, 9)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(8, 9)), Bond(type=4, atoms=(9, 10)), Bond(type=4, atoms=(9, 14)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(9, 10)), Bond(type=4, atoms=(10, 11)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(10, 11)), Bond(type=4, atoms=(11, 12)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(11, 12)), Bond(type=4, atoms=(12, 13)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(12, 13)), Bond(type=4, atoms=(13, 14)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(13, 14)), Bond(type=4, atoms=(9, 14)), Bond(type=1, atoms=(14, 15)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(14, 15)), Bond(type=0, atoms=(5, 15)), Bond(type=0, atoms=(15, 16)))), Atom(symbol='O', atom_number=8, mass_number=0, bonds=(Bond(type=0, atoms=(15, 16)),)), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=1, atoms=(4, 17)), Bond(type=4, atoms=(17, 18)), Bond(type=4, atoms=(17, 22)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(17, 18)), Bond(type=4, atoms=(18, 19)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(18, 19)), Bond(type=4, atoms=(19, 20)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(19, 20)), Bond(type=4, atoms=(20, 21)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(20, 21)), Bond(type=4, atoms=(21, 22)))), Atom(symbol='C', atom_number=6, mass_number=0, bonds=(Bond(type=4, atoms=(21, 22)), Bond(type=4, atoms=(17, 22))))))" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "warfarin = import_mol(\"warfarin\")\n", "import_mol(evaluate(warfarin, \"molFormat(genericTautomer(), 'smarts')\"))" @@ -414,29 +137,12 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "abf54870-2e45-4bb6-a317-95cb3006ce92", "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Collecting pandas\n", - " Using cached pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl.metadata (89 kB)\n", - "Collecting matplotlib\n", - " Using cached matplotlib-3.10.3-cp313-cp313-macosx_11_0_arm64.whl.metadata (11 kB)\n", - "Requirement already satisfied: numpy>=1.26.0 in /opt/homebrew/Cellar/jupyterlab/4.4.1/libexec/lib/python3.13/site-packages (from pandas) (2.2.5)\n", - "...\n", - "Using cached pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl (11.3 MB)\n", - "Using cached matplotlib-3.10.3-cp313-cp313-macosx_11_0_arm64.whl (8.1 MB)\n", - "Installing collected packages: pandas, matplotlib\n", - "Successfully installed matplotlib-3.10.3 pandas-2.2.3\n" - ] - } - ], + "outputs": [], "source": [ "import sys\n", "\n", @@ -445,118 +151,15 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "a72c8cd9-154c-450e-80a4-58ad8a44d92c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
SMILESNCI_ID
0CC1=CC(=O)C=CC1=O1
1S(SC1=NC2=CC=CC=C2S1)C3=NC4=C(S3)C=CC=C42
2OC1=C(Cl)C=C(C=C1[N+]([O-])=O)[N+]([O-])=O3
3[O-][N+](=O)C1=CNC(=N)S14
4NC1=CC2=C(C=C1)C(=O)C3=C(C=CC=C3)C2=O5
.........
995OC(=O)CN(CC(O)=O)CC1=CC=CC=C11003
996CC(C)N(CC(O)=O)CC(O)=O1004
997C1=CC=C(C=C1)C=NC(N=CC2=CC=CC=C2)C3=CC=CC=C31005
998CC(C)(C)C[C]1(C)NC(=O)NC1=O1006
999CCOC(=O)C(C(C)C)C(=O)OCC1007
\n", - "

1000 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " SMILES NCI_ID\n", - "0 CC1=CC(=O)C=CC1=O 1\n", - "1 S(SC1=NC2=CC=CC=C2S1)C3=NC4=C(S3)C=CC=C4 2\n", - "2 OC1=C(Cl)C=C(C=C1[N+]([O-])=O)[N+]([O-])=O 3\n", - "3 [O-][N+](=O)C1=CNC(=N)S1 4\n", - "4 NC1=CC2=C(C=C1)C(=O)C3=C(C=CC=C3)C2=O 5\n", - ".. ... ...\n", - "995 OC(=O)CN(CC(O)=O)CC1=CC=CC=C1 1003\n", - "996 CC(C)N(CC(O)=O)CC(O)=O 1004\n", - "997 C1=CC=C(C=C1)C=NC(N=CC2=CC=CC=C2)C3=CC=CC=C3 1005\n", - "998 CC(C)(C)C[C]1(C)NC(=O)NC1=O 1006\n", - "999 CCOC(=O)C(C(C)C)C(=O)OCC 1007\n", - "\n", - "[1000 rows x 2 columns]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T07:44:59.388750945Z", + "start_time": "2026-03-16T07:44:59.329950593Z" } - ], + }, + "outputs": [], "source": [ "import pandas\n", "\n", @@ -566,220 +169,197 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "4e7eace2-925b-4b32-b8f4-cde853fbf7ff", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
SMILESNCI_IDLOGPLOGD[3.0]LOGD[7.4]LOGD[11.0]
0CC1=CC(=O)C=CC1=O11.421.421.421.42
1S(SC1=NC2=CC=CC=C2S1)C3=NC4=C(S3)C=CC=C426.226.226.226.22
2OC1=C(Cl)C=C(C=C1[N+]([O-])=O)[N+]([O-])=O32.151.960.250.25
3[O-][N+](=O)C1=CNC(=N)S14-0.22-1.69-0.27-0.33
4NC1=CC2=C(C=C1)C(=O)C3=C(C=CC=C3)C2=O52.092.042.092.09
.....................
995OC(=O)CN(CC(O)=O)CC1=CC=CC=C11003-2.08-2.08-5.27-6.17
996CC(C)N(CC(O)=O)CC(O)=O1004-3.19-3.96-6.34-6.35
997C1=CC=C(C=C1)C=NC(N=CC2=CC=CC=C2)C3=CC=CC=C310055.725.725.725.72
998CC(C)(C)C[C]1(C)NC(=O)NC1=O10061.111.101.10-0.05
999CCOC(=O)C(C(C)C)C(=O)OCC10071.951.951.951.95
\n", - "

1000 rows × 6 columns

\n", - "
" - ], - "text/plain": [ - " SMILES NCI_ID LOGP LOGD[3.0] \\\n", - "0 CC1=CC(=O)C=CC1=O 1 1.42 1.42 \n", - "1 S(SC1=NC2=CC=CC=C2S1)C3=NC4=C(S3)C=CC=C4 2 6.22 6.22 \n", - "2 OC1=C(Cl)C=C(C=C1[N+]([O-])=O)[N+]([O-])=O 3 2.15 1.96 \n", - "3 [O-][N+](=O)C1=CNC(=N)S1 4 -0.22 -1.69 \n", - "4 NC1=CC2=C(C=C1)C(=O)C3=C(C=CC=C3)C2=O 5 2.09 2.04 \n", - ".. ... ... ... ... \n", - "995 OC(=O)CN(CC(O)=O)CC1=CC=CC=C1 1003 -2.08 -2.08 \n", - "996 CC(C)N(CC(O)=O)CC(O)=O 1004 -3.19 -3.96 \n", - "997 C1=CC=C(C=C1)C=NC(N=CC2=CC=CC=C2)C3=CC=CC=C3 1005 5.72 5.72 \n", - "998 CC(C)(C)C[C]1(C)NC(=O)NC1=O 1006 1.11 1.10 \n", - "999 CCOC(=O)C(C(C)C)C(=O)OCC 1007 1.95 1.95 \n", - "\n", - " LOGD[7.4] LOGD[11.0] \n", - "0 1.42 1.42 \n", - "1 6.22 6.22 \n", - "2 0.25 0.25 \n", - "3 -0.27 -0.33 \n", - "4 2.09 2.09 \n", - ".. ... ... \n", - "995 -5.27 -6.17 \n", - "996 -6.34 -6.35 \n", - "997 5.72 5.72 \n", - "998 1.10 -0.05 \n", - "999 1.95 1.95 \n", - "\n", - "[1000 rows x 6 columns]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T07:30:08.992554897Z", + "start_time": "2026-03-16T07:30:04.107512383Z" } - ], + }, + "outputs": [], "source": [ "mols['LOGP'] = mols.apply(lambda row: round(logp(import_mol(row['SMILES'])), 2), axis = 'columns')\n", - "mols['LOGD[3.0]'] = mols.apply(lambda row: logd(import_mol(row['SMILES']), pH=3.0), axis = 'columns')\n", - "mols['LOGD[7.4]'] = mols.apply(lambda row: logd(import_mol(row['SMILES']), pH=7.4), axis = 'columns')\n", - "mols['LOGD[11.0]'] = mols.apply(lambda row: logd(import_mol(row['SMILES']), pH=11.0), axis = 'columns')\n", + "mols['LOGD[3.0]'] = mols.apply(lambda row: logd(import_mol(row['SMILES']), ph=3.0), axis = 'columns')\n", + "mols['LOGD[7.4]'] = mols.apply(lambda row: logd(import_mol(row['SMILES']), ph=7.4), axis = 'columns')\n", + "mols['LOGD[11.0]'] = mols.apply(lambda row: logd(import_mol(row['SMILES']), ph=11.0), axis = 'columns')\n", "mols" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "1eb642b1-4087-4f7e-90f6-6d0cc6891abe", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[,\n", - " ],\n", - " [,\n", - " ]], dtype=object)" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "mols.hist(['LOGP', 'LOGD[3.0]', 'LOGD[7.4]', 'LOGD[11.0]'], bins=50)" ] + }, + { + "cell_type": "markdown", + "id": "3342b6123213a517", + "metadata": {}, + "source": [ + "### **ADMET predictors**" + ] + }, + { + "cell_type": "markdown", + "id": "b55ece180fc11860", + "metadata": {}, + "source": [ + "There are four endpoints available in the Chemaxon Python API falling into the ADMET predictions category: _herg_classifiaction_, _herg_activity_, _bbb_ (Blood-Brain Barrier) and _cns_mpo_ (CNS Multiparameter Optimisation)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "283cae5aef6dbd02", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T07:51:06.979709769Z", + "start_time": "2026-03-16T07:51:06.856689261Z" + } + }, + "outputs": [], + "source": [ + "from chemaxon import herg_classification, herg_activity, bbb, cns_mpo\n", + "\n", + "print(str(mol), ' (aspirin)')\n", + "print()\n", + "print('HERG classification:', \"SAFE\" if herg_classification(mol).classification == 0 else \"TOXIC\")\n", + "print('HERG activity: ', herg_activity(mol).value)\n", + "print('BBB score: ', bbb(mol).score)\n", + "print('CNS MPO score: ', cns_mpo(mol).score)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b919537734868299", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T07:47:48.713812526Z", + "start_time": "2026-03-16T07:47:46.021149489Z" + } + }, + "outputs": [], + "source": [ + "mols_admet = pandas.read_table('nci50.smiles', names=['SMILES', 'NCI_ID'])\n", + "\n", + "mols_admet['HERG classification'] = mols_admet.apply(lambda row: \"SAFE\" if herg_classification(import_mol(row['SMILES'])).classification == 0 else \"TOXIC\", axis = 'columns')\n", + "mols_admet['HERG activity'] = mols_admet.apply(lambda row: herg_activity(import_mol(row['SMILES'])).value, axis = 'columns')\n", + "mols_admet['BBB score'] = mols_admet.apply(lambda row: bbb(import_mol(row['SMILES'])).score, axis = 'columns')\n", + "mols_admet['CNS MPO score'] = mols_admet.apply(lambda row: cns_mpo(import_mol(row['SMILES'])).score, axis = 'columns')\n", + "\n", + "mols_admet" + ] + }, + { + "cell_type": "markdown", + "id": "e38e8bb09a41c99c", + "metadata": {}, + "source": [ + "Filter out the TOXIC compounds based on their hERG classification." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e832650c7a89f47f", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T07:49:29.758151366Z", + "start_time": "2026-03-16T07:49:29.706743346Z" + } + }, + "outputs": [], + "source": [ + "mols_admet.filter(items=['SMILES', 'NCI_ID', 'HERG classification', 'HERG activity']).query('`HERG classification` == \"TOXIC\"')" + ] + }, + { + "cell_type": "markdown", + "id": "460ca8eb85abedbe", + "metadata": {}, + "source": [ + "### **Isoelectric point calculation**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d623f46db883daf", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T08:32:16.587113874Z", + "start_time": "2026-03-16T08:32:16.546646690Z" + } + }, + "outputs": [], + "source": [ + "from chemaxon import isoelectric_point\n", + "\n", + "glycine_mol = import_mol('C(C(=O)O)N')\n", + "\n", + "res = isoelectric_point(glycine_mol)\n", + "\n", + "print('Isoelectric point of glycine: ', res.isoelectric_point)\n", + "print('Charge distributions: \\n', res.charge_distributions)\n", + "print()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efa7a82fc57b8f03", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T09:02:42.633423104Z", + "start_time": "2026-03-16T09:02:42.579911400Z" + } + }, + "outputs": [], + "source": [ + "from chemaxon import PhRange\n", + "\n", + "res = isoelectric_point(glycine_mol, ph_range=PhRange(0, 14, 0.5))\n", + "\n", + "rows = []\n", + "for charge_res in res.charge_distributions:\n", + " rows.append({'pH': charge_res.pH, 'Charge distribution': charge_res.charge})\n", + "\n", + "df = pandas.DataFrame(rows)\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07b2160b-1162-4c08-afa5-40d0197fccec", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b391de8a48db2d5", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-16T09:01:30.686598128Z", + "start_time": "2026-03-16T09:01:30.503011191Z" + } + }, + "outputs": [], + "source": [ + "#!{sys.executable} -m pip install matplotlib\n", + "\n", + "import matplotlib\n", + "\n", + "df.plot(x='pH', y='Charge distribution', kind='line', marker='o', title='Charge Distribution vs pH for Glycine', grid=True)" + ] } ], "metadata": { @@ -798,7 +378,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.3" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/jupyter/04_standardizer.ipynb b/jupyter/04_standardizer.ipynb index 46dae10..7cc81ed 100644 --- a/jupyter/04_standardizer.ipynb +++ b/jupyter/04_standardizer.ipynb @@ -2478,6 +2478,28 @@ "source": [ "Standardizer('ungroupsgroups..aromatize').standardize(mol_w_sgroups)" ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Using XML configuration for standardizer:", + "id": "507a202d9414b975" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "from chemaxon import import_mol, Standardizer\n", + "\n", + "configFile = \"path/to/my_config.xml\"\n", + "with open(configFile) as config:\n", + " standardizer = Standardizer(config)\n", + " mol = import_mol(\"[H].[H]C1=C([H])C([H])=C([H])C([H])=C1[H]\")\n", + " standard_mol = standardizer.standardize(mol)" + ], + "id": "44372e0f4eee37a6" } ], "metadata": { diff --git a/jupyter/05_structure_checker.ipynb b/jupyter/05_structure_checker.ipynb index 715d187..53cef01 100644 --- a/jupyter/05_structure_checker.ipynb +++ b/jupyter/05_structure_checker.ipynb @@ -1,5 +1,17 @@ { "cells": [ + { + "metadata": {}, + "cell_type": "markdown", + "source": "### **Structure Checker**", + "id": "a516f35da6f8f94a" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "For the concept of Structure Checker in general see [Structure Checker User's Guide](https://docs.chemaxon.com/latest/structure-checker_user-guide.html).", + "id": "cd0228716795281f" + }, { "cell_type": "code", "execution_count": 1, diff --git a/jupyter/06_molecule_search.ipynb b/jupyter/06_molecule_search.ipynb index 8d35147..0560b34 100644 --- a/jupyter/06_molecule_search.ipynb +++ b/jupyter/06_molecule_search.ipynb @@ -91,9 +91,7 @@ "cell_type": "markdown", "id": "696bd8fc-05a7-4b74-b700-b095fec68733", "metadata": {}, - "source": [ - "Hit indexes" - ] + "source": "### **Hit indexes**" }, { "cell_type": "code", @@ -111,9 +109,7 @@ "cell_type": "markdown", "id": "75c7ad5b-0e83-4525-a9fb-d9d65f472434", "metadata": {}, - "source": [ - "Duplicate search, setting search options" - ] + "source": "### **Duplicate search, setting search options**" }, { "cell_type": "code", @@ -131,9 +127,7 @@ "cell_type": "markdown", "id": "bca9acc0-dfe1-4a34-be7e-5892ff677905", "metadata": {}, - "source": [ - "Hit coloring" - ] + "source": "### **Hit coloring**" }, { "cell_type": "code", @@ -151,9 +145,7 @@ "cell_type": "markdown", "id": "5ef2d767-c818-4577-8322-98cc6680f375", "metadata": {}, - "source": [ - "Setting standardizer" - ] + "source": "### **Setting standardizer**" }, { "cell_type": "code", @@ -182,9 +174,7 @@ "cell_type": "markdown", "id": "a6fd2f42-6a18-4bf8-af30-a8126c92109a", "metadata": {}, - "source": [ - "No standardizer" - ] + "source": "### **No standardizer**" }, { "cell_type": "code", @@ -212,9 +202,7 @@ "cell_type": "markdown", "id": "a366b219-1232-4b65-bd10-73589713a051", "metadata": {}, - "source": [ - "Bulk Search" - ] + "source": "### **Bulk Search**" }, { "cell_type": "code", @@ -342,9 +330,7 @@ "cell_type": "markdown", "id": "06c1cba7-2407-41f4-ab96-adcbaa3f590f", "metadata": {}, - "source": [ - "Bulk search speed" - ] + "source": "### **Bulk search speed**" }, { "cell_type": "code", diff --git a/jupyter/07_pandas_integration_examples.ipynb b/jupyter/07_pandas_integration_examples.ipynb index f724308..023cb96 100644 --- a/jupyter/07_pandas_integration_examples.ipynb +++ b/jupyter/07_pandas_integration_examples.ipynb @@ -21,8 +21,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2026-02-02T15:19:21.211892562Z", - "start_time": "2026-02-02T15:19:21.143339417Z" + "end_time": "2025-12-01T14:43:22.339727Z", + "start_time": "2025-12-01T14:43:21.966248Z" } }, "cell_type": "code", @@ -276,6 +276,87 @@ } ], "execution_count": 6 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "You can also use molecule properties in __DataFrame__ objects:", + "id": "7a1336fb96c1f03f" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-02-02T15:22:55.201768939Z", + "start_time": "2026-02-02T15:22:55.143300052Z" + } + }, + "cell_type": "code", + "source": [ + "from chemaxon import open_for_import\n", + "\n", + "with open_for_import('mol_with_properties.mrv') as mol_iterator:\n", + " mols = list(mol_iterator)\n", + "\n", + "d = {'molecule': mols }\n", + "df_props = pd.DataFrame(data=d)\n", + "df_props['string property'] = df_props['molecule'].apply(lambda m: m.get_property('test_str_property'))\n", + "df_props['int array property'] = df_props['molecule'].apply(lambda m: m.get_property('test_int_array_property'))\n", + "\n", + "df_props" + ], + "id": "61d10376399bc9a8", + "outputs": [ + { + "data": { + "text/plain": [ + " molecule string property \\\n", + "0 C1=CC=C(C=C1)C1=CC=C(C=C1)C1=CC=CC=C1 |c:0,2,4... asd \n", + "\n", + " int array property \n", + "0 [1, 2, 3, 4, 5] " + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
moleculestring propertyint array property
0C1=CC=C(C=C1)C1=CC=C(C=C1)C1=CC=CC=C1 |c:0,2,4...asd[1, 2, 3, 4, 5]
\n", + "
" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 11 } ], "metadata": { diff --git a/jupyter/08_fingerprint_calculations.ipynb b/jupyter/08_fingerprint_calculations.ipynb new file mode 100644 index 0000000..48112cc --- /dev/null +++ b/jupyter/08_fingerprint_calculations.ipynb @@ -0,0 +1,137 @@ +{ + "cells": [ + { + "metadata": {}, + "cell_type": "markdown", + "source": "### **Fingerprint calculations**\n", + "id": "7d616c2b9d0bfbda" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Chemaxon has a number of functions that you can use to generate fingerprints.\n", + "id": "441988c36dd15dbd" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "from chemaxon import cfp, ecfp\n", + "cfp = cfp(mol)\n", + "ecfp = ecfp(mol, 4, 1024)" + ], + "id": "796299eb324647db" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "These functions return `chemaxon.fingerprints.fingerprint.Fingerprint` objects. You can get the fingerprints\n", + "in bytes or in binary string format." + ], + "id": "9a8cdfb35a01c4a7" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "ecfp.to_bytes()\n", + "ecfp.to_binary_string()" + ], + "id": "f731dd656c472138" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "You can also calculate pharmacophore fingerprints:\n", + "id": "222cbcbc51b6ae4" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "from chemaxon import pharmacophore_fp\n", + "pf = pharmacophore_fp(mol)" + ], + "id": "fba02898f19a990a" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "This method returns a `FloatVectorFingerprint`, which contains a float array.\n", + "\n", + "You can also calculate Tanimoto Dissimilarity for the fingerprints:" + ], + "id": "276808c169d1198e" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "from chemaxon import tanimoto, ecfp, pharmacophore_fp, float_vector_tanimoto\n", + "ecfp1 = ecfp(mol, 4, 1024)\n", + "ecfp2 = ecfp(mol2, 4, 1024)\n", + "\n", + "result1 = tanimoto(ecfp1, ecfp2)\n", + "\n", + "pf1 = pharmacophore_fp(mol)\n", + "pf2 = pharmacophore_fp(mol2)\n", + "result2 = float_vector_tanimoto(pf1, pf2)" + ], + "id": "3f858051237a41e5" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Reaction fingerprints can also be claucluated using the `reaction_fp` function.", + "id": "defbff32f7c6f3c1" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "from chemaxon import reaction_fp, import_mol\n", + "\n", + "r_str = \"[#7:1][H:2].[#6:4][S:3]([#7,#9,#17,#35,#53:7])(=[O:5])=[O:6]>>[#6:4][S:3]([#7:1])(=[O:6])=[O:5]\"\n", + "\n", + "reaction_mol = import_mol(reaction_str)\n", + "result_reaction = reaction_fp(reaction_mol)\n", + "\n", + "result_reaction" + ], + "id": "36c51f56f3f34840" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/jupyter/mol_with_properties.mrv b/jupyter/mol_with_properties.mrv new file mode 100644 index 0000000..55439a2 --- /dev/null +++ b/jupyter/mol_with_properties.mrv @@ -0,0 +1,4 @@ + + +TRUEasd424.2asd1 2 3 4 542TRUE1.5 2.7 3.3 4.567 + \ No newline at end of file diff --git a/jupyter/nci50.smiles b/jupyter/nci50.smiles new file mode 100644 index 0000000..471085f --- /dev/null +++ b/jupyter/nci50.smiles @@ -0,0 +1,50 @@ +CC1=CC(=O)C=CC1=O 1 +S(SC1=NC2=CC=CC=C2S1)C3=NC4=C(S3)C=CC=C4 2 +OC1=C(Cl)C=C(C=C1[N+]([O-])=O)[N+]([O-])=O 3 +[O-][N+](=O)C1=CNC(=N)S1 4 +NC1=CC2=C(C=C1)C(=O)C3=C(C=CC=C3)C2=O 5 +OC(=O)C1=C(C=CC=C1)C2=C3C=CC(=O)C(=C3OC4=C2C=CC(=C4Br)O)Br 6 +CN(C)C1=C(Cl)C(=O)C2=C(C=CC=C2)C1=O 7 +CC1=C(C2=C(C=C1)C(=O)C3=CC=CC=C3C2=O)[N+]([O-])=O 8 +CC(=NO)C(C)=NO 9 +C1=CC=C(C=C1)P(C2=CC=CC=C2)C3=CC=CC=C3 10 +CC(C)(C)C1=C(O)C=C(C(=C1)O)C(C)(C)C 11 +CC1=NN(C(=O)C1)C2=CC=CC=C2 12 +NC1=CC=NC2=C1C=CC(=C2)Cl 13 +CCCCCC[CH]1CCCCN1 14 +O=CC1=C2C=CC=CC2=CC3=C1C=CC=C3 15 +BrN1C(=O)CCC1=O 16 +CCCCCCCCCCCCCCCC1=C(N)C=CC(=C1)O 17 +C(COC1=C(C=CC=C1)C2=CC=CC=C2)OC3=CC=CC=C3C4=CC=CC=C4 18 +CCCCSCC 19 +CC(=O)NC1=NC2=C(C=C1)C(=CC=N2)O 20 +CC1=C2C=CC(=NC2=NC(=C1)O)N 21 +CCOC(=O)C1=CN=C2N=C(N)C=CC2=C1O 22 +CC1=CC(=NC=C1)N=CC2=CC=CC=C2 23 +C[N+](C)(C)CC1=CC=CC=C1 24 +C[N+](C)(C)C(=O)C1=CC=CC=C1 25 +ICCC(C1=CC=CC=C1)(C2=CC=CC=C2)C3=CC=CC=C3 26 +CC1=CC(=C(C[N+](C)(C)C)C(=C1)C)C 27 +C[C](O)(CC(O)=O)C1=CC=C(C=C1)[N+]([O-])=O 28 +CC1=CC=C(C=C1)C(=O)C2=CC=C(Cl)C=C2 29 +ON=CC1=CC=C(O)C=C1 30 +CC1=CC(=C(N)C(=C1)C)C 31 +CC1=CC=C(C=C1)C(=O)C2=CC=C(C=C2)[N+]([O-])=O 32 +CC(O)(C1=CC=CC=C1)C2=CC=CC=C2 33 +ON=CC1=CC(=CC=C1)[N+]([O-])=O 34 +OC1=C2C=CC(=CC2=NC=C1[N+]([O-])=O)Cl 35 +CC1=CC=CC2=NC=C(C)C(=C12)Cl 36 +CCC(CC)([CH](OC(N)=O)C1=CC=CC=C1)C2=CC=CC=C2 37 +ON=C(CC1=CC=CC=C1)[CH](C#N)C2=CC=CC=C2 38 +O[CH](CC1=CC=CC=C1)C2=CC=CC=C2 39 +COC1=CC=C(CC2=CC=C(OC)C=C2)C=C1 40 +CN(C)[CH](C1=CC=CC=C1)C2=C(C)C=CC=C2 41 +COC1=CC(=C(N)C(=C1)[N+]([O-])=O)[N+]([O-])=O 42 +NN=C(C1=CC=CC=C1)C2=CC=CC=C2 43 +COC1=CC=C(C=C1)C=NO 44 +C1=CC=C(C=C1)C(N=C(C2=CC=CC=C2)C3=CC=CC=C3)C4=CC=CC=C4 45 +C1=CC=C(C=C1)N=C(C2=CC=CC=C2)C3=CC=CC=C3 46 +CC1=C(C2=CC=CC=C2)C(=C3C=CC=CC3=N1)O 47 +CCC1=[O+][Cu]2([O+]=C(CC)C1)[O+]=C(CC)CC(=[O+]2)CC 48 +OC(=O)[CH](CC1=CC=CC=C1)C2=CC=CC=C2 49 +CCC1=C(N)C=C(C)N=C1 50