Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/tylermorganwall/raymolecule

Parse and Render 3D Molecular Structures in R
https://github.com/tylermorganwall/raymolecule

Last synced: about 2 months ago
JSON representation

Parse and Render 3D Molecular Structures in R

Awesome Lists containing this project

README

        

---
output: github_document
---

```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%",
fig.width=10,
fig.height=10,
cache = TRUE
)
```

# raymolecule

[![R-CMD-check](https://github.com/tylermorganwall/raymolecule/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tylermorganwall/raymolecule/actions/workflows/R-CMD-check.yaml)

`raymolecule` is an R package to parse and render molecules in 3D. Rendering is powered by two packages: [rayrender](https://www.rayrender.net/) package, a pathtracer for R, and [rayvertex](https://www.rayvertex.com/), a rasterizer for R. `raymolecule` currently supports and parses SDF (structure-data file) and PDB (Protein Data Bank) files and returns a `rayrender` scene, which we then pathtrace and visualize in R. This initial release of the package only supports visualizing atoms and bonds.

## Installation

You can install the released version of raymolecule from Github:

```{r eval=FALSE}
install.packages("remotes")
remotes::install_github("tylermorganwall/raymolecule")
```

## Examples

`raymolecule` includes several example SDF files for the following molecules: "benzene", "buckyball", "caffeine", "capsaicin", "cinnemaldehyde", "geraniol", "luciferin", "morphine", "penicillin", "pfoa", "skatole", "tubocurarine_chloride". You can get the file path to these example files using the `get_example_molecule()` function. We pass this path to the `read_sdf()` file to parse the file and extract the atom coordinates and bond information in a list. `raymolecule` also includes the ability to fetch molecules from PubChem using the `get_molecule()` function. The magrittr pipe is automatically imported in the package, so we will use it to pass the output of each function to the input of the next.

Here's the format of the data:

```{r}

library(raymolecule)

get_example_molecule("benzene") |>
read_sdf()

```

Alternatively, you can fetch any molecule from [PubChem](https://pubchem.ncbi.nlm.nih.gov) by passing either the molecule name. You can also fetch a molecule using the official compound ID (CID), in case you have a specific molecule with a long name or unique isoform:

```{r}

str(get_molecule("estradiol"))

str(get_molecule(5757)) #this is the CID for estradiol (aka estrogen)

```

We can then pass the list from `get_example_molecule() |> read_sdf()` or from `get_molecule()` to the `generate_full_scene()`, `generate_atom_scene()`, or `generate_bond_scene()` functions to convert this representation to a rayrender/rayvertex scene. This can then be passed on the `render_model()` function, which will call rayrender's `render_scene()` or rayvertex's `rasterize_scene()` functions to render it. This function automatically ensures the molecule is centered and in frame, and sets up lighting, and can accept arguments to rotate the molecule. For more rendering options, see `rayrender::render_scene()` and `rayvertex::rasterize_scene()`.

```{r}

#Specify a width, height, and number of samples for the image (more samples == less noise)
get_example_molecule("caffeine") |>
read_sdf() |>
generate_full_scene() |>
render_model(width=800,height=800,samples=1000, clamp_value=10)

#Light from both bottom and top
get_example_molecule("cinnemaldehyde") |>
read_sdf() |>
generate_full_scene() |>
render_model(lights="both",width=800,height=800,samples=1000,clamp_value=10)

#Rotate the molecule and add a non-zero aperture setting to get depth of field effect
get_example_molecule("penicillin") |>
read_sdf() |>
generate_full_scene() |>
render_model(lights="both",width=800,height=800,samples=1000,angle=c(0,30,0),aperture=3,
clamp_value=10)

```

We can use `rayvertex` to render images much more quickly and noise free, as well as include a toon cel-shading effect.

```{r}

library(rayvertex)

#Render a basic example with rayvertex
get_example_molecule("tubocurarine_chloride") |>
read_sdf() |>
generate_full_scene(pathtrace=FALSE) |>
render_model(width=800,height=800,background="grey66")

#Customize the material with toon shading
shiny_toon_material = material_list(type="toon_phong",
toon_levels=,
toon_outline_width=0.1)
get_example_molecule("morphine") |>
read_sdf() |>
generate_full_scene(pathtrace=FALSE, material_vertex = shiny_toon_material) |>
render_model(width=800,height=800,background="grey66")

#Customize the lights with rayvertex
get_example_molecule("skatole") |>
read_sdf() |>
generate_full_scene(pathtrace=FALSE) |>
render_model(width=800,height=800,angle=c(0,30,0), background="grey66",
lights = directional_light(c(0,1,1)) |>
add_light(directional_light(c(0,-1,0),color="red")))

```

You can turn off lighting in `render_model()` and customize the scene (adding different objects or lights) by using rayrender's `add_object()` function or rayvertex's `add_shape()` function. If you use `rayrender::render_scene()`/`rayvertex::rasterize_scene()` instead of `render_model()`, you have to set up the camera position and field of view yourself.

```{r}

library(rayrender)

buckyball = get_example_molecule("buckyball") |>
read_sdf() |>
generate_full_scene()

#Add custom lighting
buckyball |>
add_object(sphere(y=12,radius=3,material=light(color="white", intensity=50))) |>
add_object(sphere(y=-12,radius=3,material=light(color="red", intensity=50))) |>
render_model(lights="none",width=800,height=800,samples=1000, clamp_value=10)

#Generate ground underneath the model and use a light to cast a shadow
generate_ground(depth=-4,material=diffuse(sigma=90)) |>
add_object(buckyball) |>
add_object(sphere(y=8,material=light(intensity=100))) |>
render_scene(width=800,height=800,samples=1000,aperture=1,fov=30,lookfrom = c(0,1,30),
clamp_value = 10)

```