smiles-drawer

repository·master·Indexed 20 days ago

https://github.com/reymond-group/smilesdrawer

A client-side JavaScript library for parsing SMILES strings and rendering molecular structure depictions to SVG or Canvas without requiring a server. Version 2.4.1 includes support for Cahn-Ingold-Prelog (CIP) priority determination, molecular formula retrieval, and customizable drawing options for bond thickness, atom visualization, and themes.

Tokens
3.1K
Snippets
9
Records
10
Agent score
70%

What's inside smiles-drawer

  1. Get Started with SmilesDrawer

    master

    To draw a SMILES string to a canvas, you need to:

    1. Include the smiles-drawer library.
    2. Include the Droid Sans font from Google Fonts for consistent rendering.
    3. Initialize a SmilesDrawer.Drawer (for Canvas) or SmilesDrawer.SvgDrawer (for SVG).
    4. Use SmilesDrawer.parse() to convert a SMILES string into a parse tree.
    5. Call the .draw() method on your drawer instance using the parse tree.
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <link href="https://fonts.googleapis.com/css?family=Droid+Sans:400,700" rel="stylesheet" />
      <script src="https://unpkg.com/smiles-drawer@2/dist/smiles-drawer.min.js"></script>
    </head>
    <body>
      <input id="example-input" />
      <canvas id="example-canvas" width="500" height="500"></canvas>
    
      <script>
        let input = document.getElementById("example-input");
        let smilesDrawer = new SmilesDrawer.Drawer({});
    
        input.addEventListener("input", function() {
          SmilesDrawer.parse(input.value, function(tree) {
            smilesDrawer.draw(tree, "example-canvas", "light", false);
          });
        });
      </script>
    </body>
    </html>
  2. Install SmilesDrawer

    master

    You can install smiles-drawer using yarn:

    yarn add smiles-drawer

    Alternatively, you can use the unpkg CDN to include it directly in your HTML: https://unpkg.com/smiles-drawer@2/dist/smiles-drawer.min.js

  3. How CIPTree handles priority determination

    master

    A CIPTree is a lazily evaluated tree used to determine CIP priority. It is optimized to delay expensive recursive operations as long as possible:

    1. Initialization: When a tree is built via CIPTree.build(graph, vertex), children are not immediately loaded.
    2. Loading Children: Calling findChildren() loads the immediate neighbors and performs a non-recursive sort using CIPTree.compareAtoms(). This only looks at local attributes like atomic number and weight.
    3. Full Sorting: Calling sortChildren() performs a full recursive sort using CIPTree.compareTrees(). This is necessary for resolving ties by looking deeper into the molecular branches.

    Node Types in CIPTree:

    • Real nodes: Correspond to actual atoms in the graph.
    • Clone nodes: Refer to real nodes that have already appeared in the tree (used to handle cycles/re-entry).
    • Implicit nodes: Represent atoms not explicitly in the graph, such as implicit hydrogens or aromatic phantom atoms.
  4. Configure SmilesDrawer options

    master

    Options are passed to the SmilesDrawer.Drawer or SmilesDrawer.SvgDrawer constructor.

    Key configuration options include:

    • width / height: Drawing dimensions (default 500).
    • bondThickness: Thickness of bonds (default 1.0).
    • bondLength: Base bond length (default 30).
    • atomVisualization: Style of atoms; options: 'default', 'balls', 'none' (default 'default').
    • showCarbons: Controls explicit carbon labels. Options: 'none', 'default', 'terminal', 'acyclic', 'all' (default 'default').
    • explicitHydrogens: Whether to show hydrogens (default true).
    • experimentalSSSR: Enable this boolean if you experience problems drawing complex ring systems (default false).
    • themes: An object defining colors for atoms (C, O, N, F, CL, BR, I, P, S, B, SI, H) and BACKGROUND.
    let options = {
        width: 500,
        height: 500,
        bondThickness: 1.0,
        bondLength: 30,
        shortBondLength: 0.8,
        bondSpacing: 5.1,
        atomVisualization: 'default',
        isomeric: true,
        debug: false,
        showCarbons: 'default',
        explicitHydrogens: true,
        overlapSensitivity: 0.42,
        overlapResolutionIterations: 1,
        compactDrawing: true,
        fontFamily: 'Arial, Helvetica, sans-serif',
        fontSizeLarge: 11,
        fontSizeSmall: 3,
        padding: 10.0,
        experimentalSSSR: false,
        themes: {
            dark: { C: '#ffffff', O: '#e74c3c', /* ... other atoms */ BACKGROUND: '#141414' },
            light: { C: '#222222', O: '#e74c3c', /* ... other atoms */ BACKGROUND: '#ffffff' }
        }
    };
    let smilesDrawer = new SmilesDrawer.Drawer(options);
  5. Use SmilesDrawer in Svelte

    master

    To integrate SmilesDrawer into a Svelte application, import SmilesDrawer from smiles-drawer. You can use SmilesDrawer.SvgDrawer to initialize a drawer instance with specific settings (like width and height). Use the SmilesDrawer.parse method to convert a SMILES string into a molecule tree, and then call drawer.draw(tree, svgElement, 'light') within a lifecycle hook like afterUpdate to render the molecule into an SVG element.

    <!--file:Molecule.svlete-->
    <!--Tested against v2.1.7 of smiles-drawer-->
    <script>
        import { afterUpdate } from "svelte";
        import SmilesDrawer from "smiles-drawer";
    
        export let smiles = "";
    
        const SETTINGS = {
            width: 300,
            height: 200,
        };
        let drawer = new SmilesDrawer.SvgDrawer(SETTINGS);
        let svgElement;
    
        afterUpdate(() => {
            SmilesDrawer.parse(smiles, function (tree) {
                drawer.draw(tree, svgElement, "light");
            });
        });
    </script>
    
    <div>
        <svg bind:this={svgElement} data-smiles={smiles} />
    </div>
    
    <style>
        svg {
            width: 300px;
            height: 200px;
        }
    </style>
    
    <!--usage-->
    <Molecule smiles="CCCO" />
  6. Draw structures with smilesDrawer.draw()

    master

    Once a SMILES string is parsed, use the .draw() method of a Drawer or SvgDrawer instance to render it.

    Arguments:

    1. tree: The parse tree returned by SmilesDrawer.parse().
    2. id: The id of the HTML canvas (or SVG) element where the structure will be drawn.
    3. theme (optional): 'light' or 'dark' (defaults to 'light').
    4. onlyCompute (optional): A boolean. If true, it only computes properties (like ring count, HAC, etc.) and does not depict the structure (defaults to false).
    // Assuming smilesDrawer is an instance of SmilesDrawer.Drawer
    smilesDrawer.draw(tree, 'output-canvas', 'light', false);
  7. Parse SMILES strings with SmilesDrawer.parse()

    master

    The SmilesDrawer.parse() static method converts a SMILES string into a parse tree required for drawing. It accepts three arguments:

    1. smiles: The SMILES string to parse.
    2. successCallback: A function called with the tree object upon successful parsing.
    3. errorCallback (optional): A function called with an error object if parsing fails.
    SmilesDrawer.parse('C1CCCCC1', function (tree) {
        // tree is the parsed structure
    }, function (err) {
        console.error(err);
    });
  8. Render SMILES molecules in a Jupyter Notebook

    master

    To render chemical structures from SMILES strings within a Jupyter Notebook, you can wrap the smiles-drawer JavaScript library inside an HTML string and display it using IPython.display.IFrame.

    This approach involves:

    1. Loading the smiles-drawer.min.js script from a CDN (e.g., unpkg.com).
    2. Creating an HTML template containing a <canvas> element for the drawing.
    3. Using SmilesDrawer.parse() to process the SMILES string and smilesDrawer.draw() to render the resulting tree onto the canvas.
    4. Encoding the HTML as a data URL to be rendered by the IFrame.
    from IPython.display import IFrame
    import urllib.parse
    
    def compound_html(s):
        html = f"""
        <!DOCTYPE html>
        <meta charset="utf-8">
    
    <script src="https://unpkg.com/smiles-drawer@1.0.10/dist/smiles-drawer.min.js"></script>
    
    <body style="background-color:#FFFFFF;">
    
    <canvas id="output-canvas"></canvas>
        </body>
    
    <script>
        let smilesDrawer = new SmilesDrawer.Drawer({{ width: 250, height: 250 }});
    
    SmilesDrawer.parse('{s}', function (tree) {{
            smilesDrawer.draw(tree, 'output-canvas', 'light', false);
            }}, function (err) {{
            console.log(err);
        }})
        </script>
        """
        return html
    
    def render_compound(s):
        html = compound_html(s)
        data_url = 'data:text/html,' + urllib.parse.quote(html, safe='')
        return IFrame(data_url, width=250, height=250)
    
    # Usage
    render_compound("C1CCCCC1")
  9. Get CIP priority order with CIP.getOrderArray()

    master

    Use CIP.getOrderArray(graph, vertex) to determine the Cahn-Ingold-Prelog (CIP) priority order of a vertex's neighbors. This is primarily used to compute wedge directions for stereocenters.

    Returns:

    • An Array<number> containing the indices of the neighbors in the order of their CIP priority, relative to the original vertex.neighbours array.
    • undefined if the vertex is not a stereocenter (i.e., if there are ties in the priority that do not involve stereocenters).
    import CIP from './CIP';
    
    // Assuming 'graph' and 'vertex' are already obtained from your molecule layout
    const priorityOrder = CIP.getOrderArray(graph, vertex);
    
    if (priorityOrder) {
      console.log("Neighbor priority indices:", priorityOrder);
    } else {
      console.log("Vertex is not a stereocenter.");
    }
  10. Get molecular formula with getMolecularFormula()

    master

    The getMolecularFormula() method returns the molecular formula (e.g., C22H30N6O4S) of the currently loaded molecule.

    // Returns a String
    const formula = smilesDrawer.getMolecularFormula();