cnotebook 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cnotebook/__init__.py +400 -0
- cnotebook/align.py +454 -0
- cnotebook/context.py +523 -0
- cnotebook/grid/__init__.py +55 -0
- cnotebook/grid/grid.py +1649 -0
- cnotebook/helpers.py +201 -0
- cnotebook/ipython_ext.py +56 -0
- cnotebook/marimo_ext.py +272 -0
- cnotebook/pandas_ext.py +1156 -0
- cnotebook/polars_ext.py +1235 -0
- cnotebook/render.py +200 -0
- cnotebook-2.1.0.dist-info/METADATA +336 -0
- cnotebook-2.1.0.dist-info/RECORD +16 -0
- cnotebook-2.1.0.dist-info/WHEEL +5 -0
- cnotebook-2.1.0.dist-info/licenses/LICENSE +21 -0
- cnotebook-2.1.0.dist-info/top_level.txt +1 -0
cnotebook/render.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import base64
|
|
3
|
+
from .context import CNotebookContext, pass_cnotebook_context
|
|
4
|
+
from openeye import oechem, oedepict
|
|
5
|
+
|
|
6
|
+
log = logging.getLogger("cnotebook")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
########################################################################################################################
|
|
10
|
+
# Renderers for specific types
|
|
11
|
+
########################################################################################################################
|
|
12
|
+
|
|
13
|
+
def create_img_tag(
|
|
14
|
+
width: float,
|
|
15
|
+
height: float,
|
|
16
|
+
image_mime_type: str,
|
|
17
|
+
image_bytes: bytes,
|
|
18
|
+
wrap_svg: bool = True
|
|
19
|
+
|
|
20
|
+
) -> str:
|
|
21
|
+
"""
|
|
22
|
+
Create the <img> HTML tag for rendering image bytes. This could be either plain text (in the case of SVG) or base64
|
|
23
|
+
encoded (in binary format cases).
|
|
24
|
+
:param width: Image width
|
|
25
|
+
:param height: Image height
|
|
26
|
+
:param image_mime_type: Image MIME type
|
|
27
|
+
:param image_bytes: Image bytes
|
|
28
|
+
:param wrap_svg: Wrap SVG in a specifically sized <div> tag for maximum control of size
|
|
29
|
+
:return: Image tag
|
|
30
|
+
"""
|
|
31
|
+
if image_mime_type == "image/svg+xml":
|
|
32
|
+
if wrap_svg:
|
|
33
|
+
return '<div style=\'width:{}px;max-width:{}px;height:{}px;max-height:{}px\'>\n\t{}\n</div>'.format(
|
|
34
|
+
int(width),
|
|
35
|
+
int(width),
|
|
36
|
+
int(height),
|
|
37
|
+
int(height),
|
|
38
|
+
image_bytes.decode("utf-8")
|
|
39
|
+
)
|
|
40
|
+
else:
|
|
41
|
+
return image_bytes.decode("utf-8")
|
|
42
|
+
|
|
43
|
+
return '<img src=\'data:{};base64,{}\' style=\'width:{}px;max-width:{}px;height:{}px;max-height:{}px\' />'.format(
|
|
44
|
+
image_mime_type,
|
|
45
|
+
base64.b64encode(image_bytes).decode("utf-8"),
|
|
46
|
+
int(width),
|
|
47
|
+
int(width),
|
|
48
|
+
int(height),
|
|
49
|
+
int(height)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@pass_cnotebook_context
|
|
54
|
+
def oedisp_to_html(
|
|
55
|
+
disp: oedepict.OE2DMolDisplay,
|
|
56
|
+
*,
|
|
57
|
+
ctx: CNotebookContext
|
|
58
|
+
) -> str:
|
|
59
|
+
"""
|
|
60
|
+
Convert an OpenEye 2D molecule display object to HTML
|
|
61
|
+
:param ctx: Current molecule render context
|
|
62
|
+
:param disp: OpenEye 2D molecule display object
|
|
63
|
+
:return: HTML image tag
|
|
64
|
+
"""
|
|
65
|
+
# Convert the display object to an <img> tag
|
|
66
|
+
image = oedepict.OEImage(disp.GetWidth(), disp.GetHeight())
|
|
67
|
+
oedepict.OERenderMolecule(image, disp)
|
|
68
|
+
image_bytes = oedepict.OEWriteImageToString(ctx.image_format, image)
|
|
69
|
+
|
|
70
|
+
return create_img_tag(
|
|
71
|
+
disp.GetWidth(),
|
|
72
|
+
disp.GetHeight(),
|
|
73
|
+
image_mime_type=ctx.image_mime_type,
|
|
74
|
+
image_bytes=image_bytes,
|
|
75
|
+
wrap_svg=ctx.structure_scale != oedepict.OEScale_AutoScale
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def render_empty_molecule(*, ctx: CNotebookContext) -> str:
|
|
80
|
+
"""
|
|
81
|
+
Render an image that says Empty Molecule
|
|
82
|
+
:param ctx: Render context
|
|
83
|
+
:return: Image tag
|
|
84
|
+
"""
|
|
85
|
+
image = oedepict.OEImage(ctx.min_width, ctx.min_height)
|
|
86
|
+
image.DrawText(
|
|
87
|
+
oedepict.OE2DPoint(ctx.min_width / 2, ctx.min_height / 2),
|
|
88
|
+
"Empty Molecule",
|
|
89
|
+
oedepict.OEFont(
|
|
90
|
+
oedepict.OEFontFamily_Arial,
|
|
91
|
+
oedepict.OEFontStyle_Normal,
|
|
92
|
+
14,
|
|
93
|
+
oedepict.OEAlignment_Center,
|
|
94
|
+
oechem.OEDarkBlue
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return create_img_tag(
|
|
99
|
+
ctx.min_width,
|
|
100
|
+
ctx.min_height,
|
|
101
|
+
image_mime_type=ctx.image_mime_type,
|
|
102
|
+
image_bytes=oedepict.OEWriteImageToString(ctx.image_format, image),
|
|
103
|
+
wrap_svg=ctx.structure_scale != oedepict.OEScale_AutoScale
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def render_invalid_molecule(*, ctx: CNotebookContext) -> str:
|
|
108
|
+
"""
|
|
109
|
+
Render an image that says Empty Molecule
|
|
110
|
+
:param ctx: Render context
|
|
111
|
+
:return: Image tag
|
|
112
|
+
"""
|
|
113
|
+
image = oedepict.OEImage(ctx.min_width, ctx.min_height)
|
|
114
|
+
image.DrawText(
|
|
115
|
+
oedepict.OE2DPoint(ctx.min_width / 2, ctx.min_height / 2),
|
|
116
|
+
"Invalid Molecule",
|
|
117
|
+
oedepict.OEFont(
|
|
118
|
+
oedepict.OEFontFamily_Arial,
|
|
119
|
+
oedepict.OEFontStyle_Normal,
|
|
120
|
+
14,
|
|
121
|
+
oedepict.OEAlignment_Center,
|
|
122
|
+
oechem.OERed
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return create_img_tag(
|
|
127
|
+
ctx.min_width,
|
|
128
|
+
ctx.min_height,
|
|
129
|
+
image_mime_type=ctx.image_mime_type,
|
|
130
|
+
image_bytes=oedepict.OEWriteImageToString(ctx.image_format, image),
|
|
131
|
+
wrap_svg=ctx.structure_scale != oedepict.OEScale_AutoScale
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def oemol_to_disp(
|
|
136
|
+
mol: oechem.OEMolBase,
|
|
137
|
+
*,
|
|
138
|
+
ctx: CNotebookContext
|
|
139
|
+
) -> oedepict.OE2DMolDisplay:
|
|
140
|
+
"""
|
|
141
|
+
Convert a valid OpenEye molecule object to a display object for depiction. Note that it is highly recommended to
|
|
142
|
+
test that the molecule is valid first before calling this function.
|
|
143
|
+
:param ctx: Render context
|
|
144
|
+
:param mol: Molecule to convert
|
|
145
|
+
:return: Display object for depiction
|
|
146
|
+
"""
|
|
147
|
+
# Only recalculate coordinates if we don't have a 2D structure
|
|
148
|
+
if mol.GetDimension() == 2:
|
|
149
|
+
oedepict.OEPrepareDepiction(mol, False)
|
|
150
|
+
else:
|
|
151
|
+
oedepict.OEPrepareDepiction(mol, True)
|
|
152
|
+
|
|
153
|
+
return ctx.create_molecule_display(mol)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@pass_cnotebook_context
|
|
157
|
+
def oemol_to_html(mol: oechem.OEMolBase, *, ctx: CNotebookContext) -> str:
|
|
158
|
+
"""
|
|
159
|
+
Convert an OpenEye Molecule object to HTML
|
|
160
|
+
:param ctx: Render context
|
|
161
|
+
:param mol: Molecule to convert
|
|
162
|
+
:return: HTML string
|
|
163
|
+
"""
|
|
164
|
+
# Render valid molecules
|
|
165
|
+
if mol.IsValid():
|
|
166
|
+
|
|
167
|
+
# Create the display object from the context
|
|
168
|
+
disp = oemol_to_disp(mol, ctx=ctx)
|
|
169
|
+
|
|
170
|
+
# Render the display
|
|
171
|
+
return oedisp_to_html(disp, ctx=ctx)
|
|
172
|
+
|
|
173
|
+
# Render empty molecules
|
|
174
|
+
elif mol.NumAtoms() == 0:
|
|
175
|
+
return render_empty_molecule(ctx=ctx)
|
|
176
|
+
|
|
177
|
+
# Render other invalid molecules
|
|
178
|
+
else:
|
|
179
|
+
return render_invalid_molecule(ctx=ctx)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@pass_cnotebook_context
|
|
183
|
+
def oeimage_to_html(image: oedepict.OEImage, *, ctx: CNotebookContext) -> str:
|
|
184
|
+
"""
|
|
185
|
+
Convert an OEImage to HTML
|
|
186
|
+
:param ctx: Render context
|
|
187
|
+
:param image: Image to render
|
|
188
|
+
:return: HTML string
|
|
189
|
+
"""
|
|
190
|
+
# Convert the image to an <img> tag
|
|
191
|
+
image_bytes = oedepict.OEWriteImageToString(ctx.image_format, image)
|
|
192
|
+
return create_img_tag(
|
|
193
|
+
image.GetWidth(),
|
|
194
|
+
image.GetHeight(),
|
|
195
|
+
image_mime_type=ctx.image_mime_type,
|
|
196
|
+
image_bytes=image_bytes,
|
|
197
|
+
wrap_svg=ctx.structure_scale != oedepict.OEScale_AutoScale
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cnotebook
|
|
3
|
+
Version: 2.1.0
|
|
4
|
+
Summary: Chemistry visualization in Jupyter Notebooks with the OpenEye Toolkits
|
|
5
|
+
Author-email: Scott Arne Johnson <scott.arne.johnson@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/scott-arne/cnotebook
|
|
8
|
+
Project-URL: Bug Reports, https://github.com/scott-arne/cnotebook/issues
|
|
9
|
+
Project-URL: Source, https://github.com/scott-arne/cnotebook
|
|
10
|
+
Project-URL: Documentation, https://github.com/scott-arne/cnotebook#readme
|
|
11
|
+
Project-URL: Changelog, https://github.com/scott-arne/cnotebook/blob/master/CHANGELOG.md
|
|
12
|
+
Keywords: chemistry,cheminformatics,computational-chemistry,molecular-visualization,jupyter,marimo,openeye,scientific-computing
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
23
|
+
Classifier: Operating System :: OS Independent
|
|
24
|
+
Classifier: Framework :: Jupyter
|
|
25
|
+
Classifier: Framework :: IPython
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: openeye-toolkits>=2025.2.1
|
|
30
|
+
Requires-Dist: anywidget>=0.9.0
|
|
31
|
+
Requires-Dist: jinja2>=3.0.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: invoke; extra == "dev"
|
|
34
|
+
Requires-Dist: build; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest; extra == "dev"
|
|
36
|
+
Provides-Extra: test
|
|
37
|
+
Requires-Dist: pytest; extra == "test"
|
|
38
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# CNotebook
|
|
42
|
+
|
|
43
|
+
[](https://www.python.org/downloads/)
|
|
44
|
+
[](https://www.eyesopen.com/toolkits)
|
|
45
|
+
|
|
46
|
+
**Author:** Scott Arne Johnson ([scott.arne.johnson@gmail.com](mailto:scott.arne.johnson@gmail.com))
|
|
47
|
+
|
|
48
|
+
CNotebook provides chemistry visualization for Jupyter Notebooks and Marimo using the OpenEye Toolkits.
|
|
49
|
+
Import the package and your molecular data will automatically render as chemical structures without additional
|
|
50
|
+
configuration.
|
|
51
|
+
|
|
52
|
+
Supports both Pandas and Polars DataFrames with automatic environment detection.
|
|
53
|
+
|
|
54
|
+
**Render molecules in Jupyter and Marimo with style**
|
|
55
|
+
<br>
|
|
56
|
+
<img src="docs/_static/molecule_with_style.png" height="200">
|
|
57
|
+
|
|
58
|
+
**Maintain Jupyter table formatting for Pandas and Polars**
|
|
59
|
+
<br>
|
|
60
|
+
<img src="docs/_static/simple_pandas.png" height="600">
|
|
61
|
+
|
|
62
|
+
**Compatible with native Marimo tables**
|
|
63
|
+
<br>
|
|
64
|
+
<img src="docs/_static/marimo_pandas_polars.png" height="600">
|
|
65
|
+
|
|
66
|
+
**Interactive molecule grids that support data**
|
|
67
|
+
<br>
|
|
68
|
+
<img src="docs/_static/simple_molgrid.png" height="300">
|
|
69
|
+
|
|
70
|
+
## Table of Contents
|
|
71
|
+
|
|
72
|
+
- [Installation](#installation)
|
|
73
|
+
- [Getting Started](#getting-started)
|
|
74
|
+
- [Features](#features)
|
|
75
|
+
- [MolGrid Interactive Visualization](#molgrid-interactive-visualization)
|
|
76
|
+
- [DataFrame Integration](#dataframe-integration)
|
|
77
|
+
- [Advanced Usage](#advanced-usage)
|
|
78
|
+
- [Example Notebooks](#example-notebooks)
|
|
79
|
+
- [Documentation](#documentation)
|
|
80
|
+
- [Contributing](#contributing)
|
|
81
|
+
- [License](#license)
|
|
82
|
+
|
|
83
|
+
## Installation
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pip install cnotebook
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Prerequisites:**
|
|
90
|
+
- [OpenEye Toolkits](http://eyesopen.com): `pip install openeye-toolkits`
|
|
91
|
+
- You must have a valid license (free for academia).
|
|
92
|
+
|
|
93
|
+
**Optional backends:**
|
|
94
|
+
- Pandas support: `pip install pandas oepandas`
|
|
95
|
+
- Polars support: `pip install polars oepolars`
|
|
96
|
+
|
|
97
|
+
Both backends can be installed together, neither are required unless you want to work with DataFrames.
|
|
98
|
+
|
|
99
|
+
## Getting Started
|
|
100
|
+
|
|
101
|
+
The fastest way to learn CNotebook is through the example notebooks in the `examples/` directory:
|
|
102
|
+
|
|
103
|
+
| Environment | Pandas | Polars | MolGrid |
|
|
104
|
+
|-------------|-----------------------------------------------------------------|-----------------------------------------------------------------|-------------------------------------------------------------------|
|
|
105
|
+
| **Jupyter** | [pandas_jupyter_demo.ipynb](examples/pandas_jupyter_demo.ipynb) | [polars_jupyter_demo.ipynb](examples/polars_jupyter_demo.ipynb) | [molgrid_jupyter_demo.ipynb](examples/molgrid_jupyter_demo.ipynb) |
|
|
106
|
+
| **Marimo** | [pandas_marimo_demo.py](examples/pandas_marimo_demo.py) | [polars_marimo_demo.py](examples/polars_marimo_demo.py) | [molgrid_marimo_demo.py](examples/molgrid_marimo_demo.py) |
|
|
107
|
+
|
|
108
|
+
### Basic Usage
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
import cnotebook
|
|
112
|
+
from openeye import oechem
|
|
113
|
+
|
|
114
|
+
# Create a molecule (supports titles in SMILES)
|
|
115
|
+
mol = oechem.OEGraphMol()
|
|
116
|
+
oechem.OESmilesToMol(mol, "c1cnccc1 Benzene")
|
|
117
|
+
|
|
118
|
+
# Display it - automatically renders as a chemical structure
|
|
119
|
+
mol
|
|
120
|
+
```
|
|
121
|
+
<img src="docs/_static/benzene.png" />
|
|
122
|
+
|
|
123
|
+
CNotebook registers formatters so OpenEye molecule objects display as chemical structures instead of text representations.
|
|
124
|
+
|
|
125
|
+
## Features
|
|
126
|
+
|
|
127
|
+
### Automatic Rendering
|
|
128
|
+
- Zero configuration required
|
|
129
|
+
- Supports Jupyter Notebooks and Marimo
|
|
130
|
+
- Automatic environment and backend detection
|
|
131
|
+
|
|
132
|
+
### Molecule Support
|
|
133
|
+
- Direct rendering of `oechem.OEMolBase` objects
|
|
134
|
+
- Advanced rendering with `OE2DMolDisplay` options
|
|
135
|
+
- Pandas integration via OEPandas
|
|
136
|
+
- Polars integration via OEPolars
|
|
137
|
+
|
|
138
|
+
### Visualization Options
|
|
139
|
+
- PNG (default) or SVG output
|
|
140
|
+
- Configurable width, height, and scaling
|
|
141
|
+
- Substructure highlighting with SMARTS patterns
|
|
142
|
+
- Molecular alignment to reference structures
|
|
143
|
+
|
|
144
|
+
### MolGrid Interactive Visualization
|
|
145
|
+
- Paginated grid display for browsing molecules
|
|
146
|
+
- Text search across molecular properties
|
|
147
|
+
- SMARTS substructure filtering
|
|
148
|
+
- Selection tools with export to SMILES or CSV
|
|
149
|
+
- Information tooltips with molecular data
|
|
150
|
+
- DataFrame integration with automatic field detection
|
|
151
|
+
|
|
152
|
+
### DataFrame Integration
|
|
153
|
+
- Automatic molecule column detection and rendering
|
|
154
|
+
- Per-row substructure highlighting
|
|
155
|
+
- Molecular alignment within DataFrames
|
|
156
|
+
- Fingerprint similarity visualization
|
|
157
|
+
- Property calculations on molecule columns
|
|
158
|
+
|
|
159
|
+
## MolGrid Interactive Visualization
|
|
160
|
+
|
|
161
|
+
MolGrid provides an interactive grid for browsing molecular datasets with search and selection capabilities.
|
|
162
|
+
|
|
163
|
+
### Basic Example
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from cnotebook import MolGrid
|
|
167
|
+
from openeye import oechem
|
|
168
|
+
|
|
169
|
+
# Create molecules
|
|
170
|
+
molecules = []
|
|
171
|
+
for smi in ["CCO", "c1ccccc1", "CC(=O)O"]:
|
|
172
|
+
mol = oechem.OEGraphMol()
|
|
173
|
+
oechem.OESmilesToMol(mol, smi)
|
|
174
|
+
molecules.append(mol)
|
|
175
|
+
|
|
176
|
+
# Display interactive grid
|
|
177
|
+
grid = MolGrid(molecules)
|
|
178
|
+
grid.display()
|
|
179
|
+
```
|
|
180
|
+
<img src="docs/_static/simple_molgrid.png" height="300">
|
|
181
|
+
|
|
182
|
+
### Search and Filter
|
|
183
|
+
|
|
184
|
+
MolGrid provides two search modes:
|
|
185
|
+
- **Properties mode:** Search by molecular titles and configurable text fields
|
|
186
|
+
- **SMARTS mode:** Filter by substructure patterns with match highlighting
|
|
187
|
+
|
|
188
|
+
### Selection
|
|
189
|
+
|
|
190
|
+
- Click molecules or checkboxes to select
|
|
191
|
+
- Use the menu for Select All, Clear, and Invert operations
|
|
192
|
+
- Export selections to SMILES or CSV files
|
|
193
|
+
|
|
194
|
+
### Information Tooltips
|
|
195
|
+
|
|
196
|
+
- Hover over the information button to view molecular data
|
|
197
|
+
- Click to pin tooltips for comparing multiple molecules
|
|
198
|
+
- Configure displayed fields with the `data` parameter
|
|
199
|
+
|
|
200
|
+
### DataFrame Integration
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
import pandas as pd
|
|
204
|
+
from cnotebook import MolGrid
|
|
205
|
+
from openeye import oechem, oemolprop
|
|
206
|
+
|
|
207
|
+
# Create DataFrame
|
|
208
|
+
df = pd.DataFrame(
|
|
209
|
+
{"Molecule": ["CCO", "c1ccccc1", "CC(=O)O"]}
|
|
210
|
+
).chem.as_molecule("Molecule")
|
|
211
|
+
|
|
212
|
+
# Calculate some properties
|
|
213
|
+
df["MW"] = df.Molecule.apply(oechem.OECalculateMolecularWeight)
|
|
214
|
+
df["PSA"] = df.Molecule.apply(oemolprop.OEGet2dPSA)
|
|
215
|
+
df["HBA"] = df.Molecule.apply(oemolprop.OEGetHBondAcceptorCount)
|
|
216
|
+
df["HBD"] = df.Molecule.apply(oemolprop.OEGetHBondDonorCount)
|
|
217
|
+
|
|
218
|
+
# Display the grid (using the 'Molecule' column for structures)
|
|
219
|
+
grid = df.chem.molgrid("Molecule")
|
|
220
|
+
grid.display()
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
This will display the same grid as above, but with molecule data if you click the "i".
|
|
224
|
+
|
|
225
|
+
### Retrieving Selections
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
# Get selected molecules
|
|
229
|
+
selected_mols = grid.get_selection()
|
|
230
|
+
|
|
231
|
+
# Get selected indices
|
|
232
|
+
indices = grid.get_selection_indices()
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## DataFrame Integration
|
|
236
|
+
|
|
237
|
+
### Pandas DataFrames
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
import cnotebook
|
|
241
|
+
import oepandas as oepd
|
|
242
|
+
|
|
243
|
+
# Read the example unaligned molecules
|
|
244
|
+
df = oepd.read_sdf("examples/assets/rotations.sdf", no_title=True)
|
|
245
|
+
|
|
246
|
+
# Rename the "Molecule" column to "Original" so that we can
|
|
247
|
+
# see the original unaligned molecules
|
|
248
|
+
df = df.rename(columns={"Molecule": "Original"})
|
|
249
|
+
|
|
250
|
+
# Create a new molecule column called "Aligned" so that we can
|
|
251
|
+
# see the aligned molecules
|
|
252
|
+
df["Aligned"] = df.Original.chem.copy_molecules()
|
|
253
|
+
|
|
254
|
+
# Add substructure highlighting
|
|
255
|
+
df["Original"].chem.highlight("c1ccccc1")
|
|
256
|
+
df["Aligned"].chem.highlight("c1ccccc1")
|
|
257
|
+
|
|
258
|
+
# Align molecules to a reference
|
|
259
|
+
df["Aligned"].chem.align_depictions("first")
|
|
260
|
+
|
|
261
|
+
# Display the DataFrame
|
|
262
|
+
df
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
<img src="docs/_static/pandas_highlight_and_align_dataframe.png" height="400">
|
|
266
|
+
|
|
267
|
+
### Polars DataFrames
|
|
268
|
+
|
|
269
|
+
Same example as above using Polars instead of Pandas. The main difference is that some methods are called
|
|
270
|
+
from the DataFrame instead of the Series.
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
import cnotebook
|
|
274
|
+
import oepolars as oepl
|
|
275
|
+
|
|
276
|
+
# Read the example unaligned molecules
|
|
277
|
+
df = oepl.read_sdf("examples/assets/rotations.sdf", no_title=True)
|
|
278
|
+
|
|
279
|
+
# Rename the "Molecule" column to "Original" so that we can
|
|
280
|
+
# see the original unaligned molecules
|
|
281
|
+
df = df.rename({"Molecule": "Original"})
|
|
282
|
+
|
|
283
|
+
# # Create a new molecule column called "Aligned" so that we can
|
|
284
|
+
# # see the aligned molecules
|
|
285
|
+
df = df.chem.copy_molecules("Original", "Aligned")
|
|
286
|
+
|
|
287
|
+
# # Add substructure highlighting
|
|
288
|
+
df.chem.highlight("Original", "c1ccccc1")
|
|
289
|
+
df.chem.highlight("Aligned", "c1ccccc1")
|
|
290
|
+
|
|
291
|
+
# # Align molecules to a reference
|
|
292
|
+
df["Aligned"].chem.align_depictions("first")
|
|
293
|
+
|
|
294
|
+
# Display the DataFrame
|
|
295
|
+
df
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
This will display the exact same table as above.
|
|
299
|
+
|
|
300
|
+
## Example Notebooks
|
|
301
|
+
|
|
302
|
+
The `examples/` directory contains comprehensive tutorials for learning CNotebook:
|
|
303
|
+
|
|
304
|
+
### Jupyter Notebooks
|
|
305
|
+
|
|
306
|
+
- **[pandas_jupyter_demo.ipynb](examples/pandas_jupyter_demo.ipynb)** - Complete Pandas integration tutorial covering molecule rendering, highlighting, alignment, and fingerprint similarity
|
|
307
|
+
- **[polars_jupyter_demo.ipynb](examples/polars_jupyter_demo.ipynb)** - Complete Polars integration tutorial with the same features adapted for Polars patterns
|
|
308
|
+
- **[molgrid_jupyter_demo.ipynb](examples/molgrid_jupyter_demo.ipynb)** - Interactive molecule grid tutorial with search, selection, and export features
|
|
309
|
+
- **[pandas_jupyter_svgs.ipynb](examples/pandas_jupyter_svgs.ipynb)** - SVG vs PNG rendering comparison and quality considerations
|
|
310
|
+
|
|
311
|
+
### Marimo Applications
|
|
312
|
+
|
|
313
|
+
- **[pandas_marimo_demo.py](examples/pandas_marimo_demo.py)** - Pandas tutorial in reactive Marimo environment
|
|
314
|
+
- **[polars_marimo_demo.py](examples/polars_marimo_demo.py)** - Polars tutorial in reactive Marimo environment
|
|
315
|
+
- **[molgrid_marimo_demo.py](examples/molgrid_marimo_demo.py)** - MolGrid tutorial with reactive selection feedback
|
|
316
|
+
|
|
317
|
+
**Recommended starting point:** Begin with the MolGrid demo for your preferred environment, then explore the Pandas or Polars tutorials for DataFrame integration.
|
|
318
|
+
|
|
319
|
+
## Contributing
|
|
320
|
+
|
|
321
|
+
Contributions are welcome. Please ensure your code:
|
|
322
|
+
- Follows existing code style and conventions
|
|
323
|
+
- Includes appropriate tests
|
|
324
|
+
- Works with both Jupyter and Marimo environments
|
|
325
|
+
- Maintains compatibility with OpenEye Toolkits
|
|
326
|
+
- Works with both Pandas and Polars when applicable
|
|
327
|
+
|
|
328
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
|
|
329
|
+
|
|
330
|
+
## License
|
|
331
|
+
|
|
332
|
+
This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
|
|
333
|
+
|
|
334
|
+
## Support
|
|
335
|
+
|
|
336
|
+
For bug reports, feature requests, or questions, please open an issue on GitHub or contact [scott.arne.johnson@gmail.com](mailto:scott.arne.johnson@gmail.com).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
cnotebook/__init__.py,sha256=C5wYJ0-6bmccYcbKCekAat08vWyk_IyqSHvob6AWfMU,13746
|
|
2
|
+
cnotebook/align.py,sha256=wDJy79PvRG0O_XHCAXkGv2uqp6nL65g-NO-oQSnOkpI,17926
|
|
3
|
+
cnotebook/context.py,sha256=HKTx0Bxz0LfleaWjBco_AoSGR2iPrVY-0OsJ_ro6O0o,19229
|
|
4
|
+
cnotebook/helpers.py,sha256=TCcNfykhSi77FrTQC2_2W8G9lxP0n3S7V8tEiGcE0hg,7121
|
|
5
|
+
cnotebook/ipython_ext.py,sha256=Z6IhHg_YP6-becgruEDiE-tVkSB0SZTUU6R2MItaVa4,1874
|
|
6
|
+
cnotebook/marimo_ext.py,sha256=F2WBiM0F3vLcL9vAcZesB7XgIWULd7QiWe78dQy1h3s,9790
|
|
7
|
+
cnotebook/pandas_ext.py,sha256=iOURve2nDg1z37Jq56GjP1KyvgG7BH9DYu4hlTsfIzg,43323
|
|
8
|
+
cnotebook/polars_ext.py,sha256=AMWVGPdS8qbFH-lNcGrekPwT9vFUxZxq41Rlqx4jjB4,47725
|
|
9
|
+
cnotebook/render.py,sha256=jn47U5I0t0H5R_iydhBsz_vVdtBVXyQYwrMb_XG8zy0,6143
|
|
10
|
+
cnotebook/grid/__init__.py,sha256=yNcddI5PP-6BBXCNhRALvNrlgAn7UeR9ntrhmMMShu8,1804
|
|
11
|
+
cnotebook/grid/grid.py,sha256=y-uV_cNmazI3aDWbRI2JSuOB83jhdZbiivlsPS4wBSk,51217
|
|
12
|
+
cnotebook-2.1.0.dist-info/licenses/LICENSE,sha256=HbIgeZz-pWGC7BEnYFCQ-jfD1m_BfiosF9qjgWw64GU,1080
|
|
13
|
+
cnotebook-2.1.0.dist-info/METADATA,sha256=adbX-E5iLz0yJwJaK_X7FUyT-FNzrYyH-e4GPIvQP5M,11860
|
|
14
|
+
cnotebook-2.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
15
|
+
cnotebook-2.1.0.dist-info/top_level.txt,sha256=jzkieTjQwdNKfMwnoElvDDtNPkeLMjbvWbsbkSsboo8,10
|
|
16
|
+
cnotebook-2.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2025 Scott Arne Johnson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cnotebook
|