Skip to content

Commit

Permalink
Add custom transform functions. Would solve #10. (#12)
Browse files Browse the repository at this point in the history
* New `transform` parameter that accepts a dictionary of field-function items where each function transforms the input value that will be displayed.

Co-authored-by: Fredrik Wallner <fredrik.wallner@irlab.se>
Co-authored-by: Cédric Bouysset <cedric.bouysset@unice.fr>
  • Loading branch information
3 people committed Apr 7, 2021
1 parent dcd986f commit d008989
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 54 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,11 @@ 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).

## [Unreleased]
### Added
- New `transform` parameter that accepts a dictionnary of field-function items where each
function transforms the input value that will be displayed. Fixes: Issue #10

## [0.0.4] - 2021/04/01
### Changed
- The demo notebook can now be run on Google Colab
Expand Down
11 changes: 10 additions & 1 deletion README.md
Expand Up @@ -41,7 +41,9 @@ mols2grid.display("path/to/molecules.sdf",
# set what's displayed on the tooltips
tooltip=["Name", "smiles", "Class", "Solubility"],
# style for the grid labels and tooltips
style={"Solubility": lambda x: "color: red" if x < -3 else "color: black"})
style={"Solubility": lambda x: "color: red" if x < -3 else "color: black"},
# change the precision and format (or other transformations)
transform={"Solubility": lambda x: f"{x:+.2f}"})
```

#### Input parameters
Expand Down Expand Up @@ -99,6 +101,13 @@ Both templates can be configured with the same parameters (a lot of which are [C
```python
style={"Solubility": lambda x: "color: red" if x < -3 else "color: black"}
```
* `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:
```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:

Expand Down
94 changes: 49 additions & 45 deletions demo.ipynb

Large diffs are not rendered by default.

51 changes: 43 additions & 8 deletions mols2grid/molgrid.py
Expand Up @@ -204,7 +204,7 @@ def to_pages(self, subset=None, tooltip=None,
fontsize="12pt", fontfamily="'DejaVu', sans-serif",
textalign="center", tooltip_fmt="<strong>{key}</strong>: {value}",
tooltip_trigger="click hover", tooltip_placement="bottom",
hover_color="#e7e7e7", style=None, selection=True):
hover_color="#e7e7e7", style=None, selection=True, transform=None):
"""Returns the HTML document for the "pages" template
Parameters
Expand Down Expand Up @@ -240,7 +240,7 @@ def to_pages(self, subset=None, tooltip=None,
hover_color : str
Background color when hovering a cell (CSS)
style : dict or None
CSS styling applied to each item in a cell. The dict must follow a
CSS styling 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 outputs a valid CSS styling, for example
Expand All @@ -251,6 +251,17 @@ def to_pages(self, subset=None, tooltip=None,
Enables the selection of molecules and displays a checkbox at the top of each
cell. This is only usefull in the context of a Jupyter notebook, which gives
you access to your selection (index and SMILES) through `mols2grid.selection`
transform : 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:
`transform={"Solubility": lambda x: f"{x:.2f}",
"Melting point": lambda x: f"MP: {5/9*(x-32):.1f}°C"}`
will 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. These transformations only affect
columns in `subset` (not `tooltip`) and are applied independantly from `style`
"""
df = self.dataframe.drop(columns=self.mol_col).copy()
cell_width = self.img_size[0]
Expand All @@ -266,6 +277,8 @@ def to_pages(self, subset=None, tooltip=None,
sort_cols = ["mols2grid-id"] + sort_cols
if style is None:
style = {}
if transform is None:
transform = {}
value_names = list(set(subset + [smiles]))
value_names = [f"data-{col}" for col in value_names]
width = n_cols * (cell_width + 2 * (gap + 2))
Expand Down Expand Up @@ -308,17 +321,23 @@ def to_pages(self, subset=None, tooltip=None,
final_columns = final_columns + ["mols2grid-tooltip"]
value_names = (value_names[:-1] +
", {attr: 'data-content', name: 'mols2grid-tooltip'}]")


# apply CSS styles
for col, func in style.items():
name = f"style-{col}"
df[name] = df[col].apply(func)
final_columns.append(name)
value_names = value_names[:-1] + f", {{ attr: 'style', name: {name!r} }}]"

# apply custom user function
for col, func in transform.items():
df[col] = df[col].apply(func)

checkbox = '<input type="checkbox" class="position-relative float-left">'
item = '<div class="cell" data-mols2grid-id="0">{}{}</div>'.format(
checkbox if selection else "",
"".join(content))

df = df[final_columns].rename(columns=column_map)

template = env.get_template('pages.html')
Expand Down Expand Up @@ -368,7 +387,7 @@ def to_table(self, subset=None, tooltip=None, n_cols=6,
fontsize="12pt", fontfamily="'DejaVu', sans-serif",
textalign="center", tooltip_fmt="<strong>{key}</strong>: {value}",
tooltip_trigger="click hover", tooltip_placement="bottom",
hover_color="#e7e7e7", style=None):
hover_color="#e7e7e7", style=None, transform=None):
"""Returns the HTML document for the "table" template
Parameters
Expand Down Expand Up @@ -402,13 +421,24 @@ def to_table(self, subset=None, tooltip=None, n_cols=6,
hover_color : str
Background color when hovering a cell (CSS)
style : dict or None
CSS styling applied to each item in a cell. The dict must follow a
CSS styling 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 outputs a valid CSS styling, for example
`style={"Solubility": lambda x: "color: red" if x < -5 else "color: black"}`
if you want to color the text corresponding to the "Solubility"
column in your dataframe.
column in your dataframe
transform : 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:
`transform={"Solubility": lambda x: f"{x:.2f}",
"Melting point": lambda x: f"MP: {5/9*(x-32):.1f}°C"}`
will 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. These transformations only affect
columns in `subset` (not `tooltip`) and are applied independantly from `style`
"""
tr = []
data = []
Expand All @@ -420,6 +450,8 @@ def to_table(self, subset=None, tooltip=None, n_cols=6,
subset = [subset.pop(subset.index("img"))] + subset
if style is None:
style = {}
if transform is None:
transform = {}

for i, row in df.iterrows():
ncell = i + 1
Expand All @@ -435,9 +467,12 @@ def to_table(self, subset=None, tooltip=None, n_cols=6,
else:
func = style.get(col)
if func:
item = f'<div class="data data-{col}" style="{func(v)}">{v}</div>'
item = f'<div class="data data-{col}" style="{func(v)}">'
else:
item = f'<div class="data data-{col}">{v}</div>'
item = f'<div class="data data-{col}">'
func = transform.get(col)
v = func(v) if func else v
item += f'{v}</div>'
div.append(item)
div.append("</div>")
td.append("\n".join(div))
Expand Down

0 comments on commit d008989

Please sign in to comment.