Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
cbouy committed Oct 10, 2021
2 parents 389484f + 59644ee commit 1f0dc63
Show file tree
Hide file tree
Showing 31 changed files with 2,436 additions and 1,642 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Install python with pip
uses: actions/setup-python@v2
with:
python-version: pypy-3.6
python-version: 3.6
architecture: x64

- name: Install dependencies for packaging
Expand Down
106 changes: 106 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: CI
on:
push:
branches:
- "*"
pull_request:
branches:
- master
workflow_dispatch:

defaults:
run:
shell: bash -l {0}

concurrency:
group: "${{ github.ref }}-${{ github.head_ref }}"
cancel-in-progress: true

jobs:
tests:
name: CI-${{ matrix.os }} | py${{ matrix.python-version }} | ${{ matrix.rdkit-version }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
python-version: [3.6, 3.8]
rdkit-version: ["rdkit>2020.03.1"]
include:
- name: CI min version
os: ubuntu-latest
python-version: 3.6
rdkit-version: "rdkit==2020.03.1"

steps:
- uses: actions/checkout@v2

- name: Cache conda
uses: actions/cache@v2
env:
CACHE_NUMBER: 0
with:
path: ~/conda_pkgs_dir
key:
${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{
hashFiles('etc/example-environment.yml') }}

- name: Setup Conda
uses: conda-incubator/setup-miniconda@v2
with:
python-version: ${{ matrix.python-version }}
mamba-version: "*"
channels: conda-forge,defaults
use-only-tar-bz2: true

- name: Check conda and pip
run: |
which python
python --version
pip --version
conda --version
mamba --version
- name: Install conda dependencies
run: |
mamba install ${{ matrix.rdkit-version }}
mamba list
- name: Install package through pip
run: |
pip install .[tests]
pip list
- name: Run tests
run: |
pytest --color=yes --disable-pytest-warnings --cov=mols2grid --cov-report=xml tests/
- name: Measure tests coverage
uses: codecov/codecov-action@v1
with:
file: coverage.xml
fail_ci_if_error: True
verbose: True

- name: Prepare for build
run: |
pip uninstall -y mols2grid
python setup.py sdist bdist_wheel
echo "$SCRIPT" > test_install.py
cat test_install.py
env:
SCRIPT: |
import mols2grid as mg
from rdkit import RDConfig
sdf = f"{RDConfig.RDDocsDir}/Book/data/solubility.test.sdf"
mg.save(sdf, output="/dev/null", subset=["img", "mols2grid-id"])
- name: Test tar.gz build
run: |
pip install dist/mols2grid-*.tar.gz
python test_install.py
pip uninstall -y mols2grid
- name: Test wheel build
run: |
pip install dist/mols2grid-*.whl
python test_install.py
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,39 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.0] - 2021/10/11
### Added
- The grid can be filtered using pandas DataFrame's `query` and `loc` logic (mostly
useful to combine with ipywidgets) with `MolGrid.filter_by_index` and `MolGrid.filter`.
- Selections can now be modified (select and unselect all, or invert) and exported (to
clipboard or a SMILES file) even without a notebook kernel. Fixes: Issue #16.
- The grid can be sorted according to the selection status and to values in the tooltips.
- Added tracking the selection in multiple grids at the same time (i.e. it's not a
global object that get's overwritten anymore).
- Added support for executing custom JavaScript code or Python function when clicking on
a molecule's image through the `callback` argument.
- Added the `mols2grid.make_popup_callback` helper function to create a popup-like window
as a JavaScript callback.
- Added styling for the whole cell through `style={"__all__": userfunction}`.
- Added `mols2grid.get_selection()` allowing users to specify which grid selection should
be returned. Without argument, the most recently updated grid is returned.
- Added `mols2grid.list_grids()` to return a list of grid names available.
- Added the `mols2grid.sdf_to_dataframe` function to easily convert an SDF file to a
pandas DataFrame.
- Added the `custom_css` argument to pass custom CSS for the HTML document.
- Added the `sort_by` argument to change how the grid elements are ordered
### Changed
- The functions in `style` and `transform` are now also applied to tooltips.
- The sizing of the iframe displaying the grid is now fully automated and more precise.
- Reorganized the code to separate the JS, CSS and HTML templates.
### Fixed
- Fixed `mols2grid.save` that returned an error about missing the `output` argument.
- The tooltip is now compatible with the "focus" mode: `tooltip_trigger="focus"`.
- Fixed rendering SVG images in tooltips.
### Deprecated
- Deprecated `mols2grid.selection` in favor of `mols2grid.get_selection()`.
- Deprecated `mapping` in favor of `rename` in the MolGrid class and `mols2grid.display`.

## [0.0.6] - 2021/05/14
### Changed
- Javascript module for RDKit is now sourced from `unpkg.com` and pinned to `v2021.3.2`
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include README.md LICENSE CHANGELOG.md
recursive-include mols2grid/templates *
56 changes: 36 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# 👀 mols2grid

[![Pypi Version](https://img.shields.io/pypi/v/mols2grid.svg)](https://pypi.python.org/pypi/mols2grid)
[![Pypi version](https://img.shields.io/pypi/v/mols2grid.svg)](https://pypi.python.org/pypi/mols2grid)
![Conda version](https://img.shields.io/conda/vn/conda-forge/mols2grid)

[![Tests status](https://github.com/cbouy/mols2grid/workflows/CI/badge.svg)](https://github.com/cbouy/mols2grid/actions/workflows/ci.yml)
[![Code coverage](https://codecov.io/gh/cbouy/mols2grid/branch/master/graph/badge.svg?token=QDI1XQSDUC)](https://codecov.io/gh/cbouy/mols2grid)
[![Build status](https://github.com/cbouy/mols2grid/workflows/build/badge.svg)](https://github.com/cbouy/mols2grid/actions/workflows/build.yml)

[![Powered by RDKit](https://img.shields.io/static/v1?label=Powered%20by&message=RDKit&color=3838ff&style=flat&logo=data:image/x-icon;base64,AAABAAEAEBAQAAAAAABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAMAABILAAASCwAAAAAAAAAAAADc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nz/FBT/FBT/FBT/FBT/FBT/FBTc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nz/FBT/PBT/PBT/PBT/PBT/PBT/PBT/FBTc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nz/FBT/PBT/ZGT/ZGT/ZGT/ZGT/ZGT/ZGT/PBT/FBTc3Nzc3Nzc3Nzc3Nzc3Nz/FBT/PBT/ZGT/ZGT/ZGT/ZGT/ZGT/ZGT/ZGT/ZGT/PBT/FBTc3Nzc3Nzc3Nz/FBT/PBT/ZGT/ZGT/ZGT/jIz/jIz/jIz/jIz/ZGT/ZGT/ZGT/PBT/FBTc3Nzc3Nz/FBT/PBT/ZGT/ZGT/jIz/jIz/jIz/jIz/jIz/jIz/ZGT/ZGT/PBT/FBTc3Nzc3Nz/FBT/PBT/ZGT/ZGT/jIz/jIz/tLT/tLT/jIz/jIz/ZGT/ZGT/PBT/FBTc3Nzc3Nz/FBT/PBT/ZGT/ZGT/jIz/jIz/tLT/tLT/jIz/jIz/ZGT/ZGT/PBT/FBTc3Nzc3Nz/FBT/PBT/ZGT/ZGT/jIz/jIz/jIz/jIz/jIz/jIz/ZGT/ZGT/PBT/FBTc3Nzc3Nz/FBT/PBT/ZGT/ZGT/ZGT/jIz/jIz/jIz/jIz/ZGT/ZGT/ZGT/PBT/FBTc3Nzc3Nzc3Nz/FBT/PBT/ZGT/ZGT/ZGT/ZGT/ZGT/ZGT/ZGT/ZGT/PBT/FBTc3Nzc3Nzc3Nzc3Nzc3Nz/FBT/PBT/ZGT/ZGT/ZGT/ZGT/ZGT/ZGT/PBT/FBTc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nz/FBT/PBT/PBT/PBT/PBT/PBT/PBT/FBTc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nz/FBT/FBT/FBT/FBT/FBT/FBTc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nz/////+B////AP///gB///wAP//4AB//+AAf//gAH//4AB//+AAf//gAH//8AD///gB///8A////gf////////)](https://www.rdkit.org/)
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cbouy/mols2grid/blob/master/demo.ipynb)

Expand Down Expand Up @@ -37,9 +42,9 @@ mols2grid.display("path/to/molecules.sdf",
# RDKit's MolDrawOptions parameters
fixedBondLength=25,
# rename fields for the output document
mapping={"SOL": "Solubility",
"SOL_classification": "Class",
"NAME": "Name"},
rename={"SOL": "Solubility",
"SOL_classification": "Class",
"NAME": "Name"},
# set what's displayed on the grid
subset=["ID", "img", "Solubility"],
# set what's displayed on the tooltips
Expand All @@ -57,12 +62,13 @@ You can setup the grid from various inputs:
* a list of **RDKit molecules** (with properties accessible through the `mol.GetPropsAsDict()` method),
* or an **SDF file**

You can also rename each field of your input with the `mapping` parameter. Please note that 3 fields are automatically added regardless of your input: `mols2grid-id`, `SMILES` and `img`. If a "SMILES" field already exists, it will not be overwritten.
You can also rename each field of your input with the `rename` parameter. Please note that 3 fields are automatically added regardless of your input: `mols2grid-id`, `SMILES` and `img`. If a "SMILES" field already exists, it will not be overwritten.

#### Parameters for the drawing of each molecule

* `useSVG=True`: use SVG images or PNG
* `coordGen=True`: use the coordGen library instead of the RDKit one to depict the molecules in 2D
* `removeHs=False`: remove explicit hydrogen atoms from the drawings
* `size=(160, 120)`: size of each image
* `use_coords=True`: use the coordinates of the input molecules if available
* `MolDrawOptions=None`: RDKit's [MolDrawOptions](https://www.rdkit.org/docs/source/rdkit.Chem.Draw.rdMolDraw2D.html#rdkit.Chem.Draw.rdMolDraw2D.MolDrawOptions) class. Useful for making highly customized drawings. You can also leave this to `None`, and directly use the attributes of this class as parameters like `addStereoAnnotation=True`
Expand All @@ -73,7 +79,8 @@ You can control the general look of the document through the `template` argument
* `template="pages"` (default) which is displayed above. It integrates nicely with Jupyter notebooks and has a search bar
* `template="table"`, which displays the full list of molecules (no pages). Useful if you ever need to print the full list of molecules on paper (or print to PDF)

Both templates can be configured with the same parameters (a lot of which are [CSS](https://www.w3schools.com/cssref/) declarations):
Both templates can be configured with the same parameters (a lot of which are [CSS](https://www.w3schools.com/cssref/) declarations).
For the `pages` template, the following parameters are available:

* `subset=None`: list or None
Columns to be displayed in each cell of the grid. Each column's value will be displayed from top to bottom in the same order given here. Use `"img"` for the image of the molecule. Default: all columns (with "img" in first position)
Expand All @@ -87,6 +94,8 @@ Both templates can be configured with the same parameters (a lot of which are [C
Position of the tooltip: auto, top, bottom, left, right
* `n_cols=5`: int
Number of columns per page
* `n_rows=3` : int
Number of rows per page
* `border="1px solid #cccccc"`: str
Styling of the border around each cell (CSS)
* `gap=0`: int or str
Expand All @@ -103,29 +112,36 @@ Both templates can be configured with the same parameters (a lot of which are [C
CSS styling applied to each item in a cell. The dict must follow a `key: function` structure where the key must correspond to one of the columns in `subset` or `tooltip`. The function takes the item's value as input, and outputs a valid CSS styling. For example, if you want to color the text corresponding to the "Solubility"
column in your dataframe:
```python
style={"Solubility": lambda x: "color: red" if x < -3 else "color: black"}
style={"Solubility": lambda x: "color: red" if x < -3 else ""}
```
You can also style a whole cell using `__all__` as a key, the corresponding function then has access to all values for each cell:
```python
style={"__all__": lambda x: "background-color: yellow" if x["Solubility"] < -5 else ""}
```
* `transform=None`: dict or None
Functions applied to specific items in all cells. The dict must follow a `key: function` structure where the key must correspond to one of the columns in `subset`. The function takes the item's value as input and transforms it. For example, to round the "Solubility" to 2 decimals, and display the "Melting point" in Celsius instead of Fahrenheit with a single digit precision and some text before ("MP") and after ("°C") the value:
* `transform=None`: dict or None
Functions applied to specific items in all cells. The dict must follow a `key: function` structure where the key must correspond to one of the columns in `subset` or `tooltip`. The function takes the item's value as input and transforms it. For example, to round the "Solubility" to 2 decimals, and display the "Melting point" in Celsius instead of Fahrenheit with a single digit precision and some text before ("MP") and after ("°C") the value:
```python
transform={"Solubility": lambda x: f"{x:.2f}",
"Melting point": lambda x: f"MP: {5/9*(x-32):.1f}°C"}
```
These transformations only affect columns in `subset` (not `tooltip`) and are applied independantly from `style`.

The `pages` template comes with additional parameters:

* `n_rows=3` : int
Number of rows per page
* `selection=True` : bool
Enables the selection of molecules using a checkbox. Only usefull in the context of a Jupyter notebook. You can retrieve your selection of molecules (index and SMILES) through `mols2grid.selection`

The `pages` template also allows searching (by text or SMARTS) and sorting the grid.
These transformations only affect columns in `subset` and `tooltip` and do not interfere with `style`.
* `selection=True` : bool
Enables the selection of molecules using a checkbox. Only usefull in the context of a Jupyter notebook. You can retrieve your selection of molecules (index and SMILES) through `mols2grid.get_selection()`
* `custom_css=None` : str or None
Custom CSS properties applied to the content of the HTML document
* `custom_header=None` : str or None
Custom libraries (CSS or JS) to be loaded in the header of the document
* `callback=None` : str or callable
JavaScript or Python callback to be executed when clicking on an image. A dictionnary containing the data for the full cell is directly available as `data` in JS. For Python, the callback function must have `data` as the first argument to the function. All the values in the `data` dict are parsed as strings, except "mols2grid-id" which is always an integer.
* `sort_by` : str or None
Sort the grid according to the following field (which must be present in `subset` or `tooltip`).

Less options are available for the `table` template, you can check the complete list of arguments with `help(mols2grid.MolGrid.to_table)`

#### Output parameters

You can either:
* save the grid with `mols2grid.save(output_path, ...)`. The file that is generated is a standalone HTML document that should work with most web browsers.
* save the grid with `mols2grid.save(input, output="path/grid.html", ...)`. The file that is generated is a standalone HTML document that should work with most web browsers.
* display it directly in a Jupyter notebook with `mols2grid.display(...)` (optionnal argument: `width="100%"`, `height=None`)

## 🚀 Resources
Expand Down
Loading

0 comments on commit 1f0dc63

Please sign in to comment.