From 1f9c8ac5f784441e47d15e68e195ad96e2bd741c Mon Sep 17 00:00:00 2001 From: wjm41 Date: Sun, 27 Feb 2022 15:05:57 +0000 Subject: [PATCH] Replaced slider with dropdown menu --- example_multiple_columns.ipynb | 247 ++------------------------------- molplotly/main.py | 108 ++++++++------ 2 files changed, 81 insertions(+), 274 deletions(-) diff --git a/example_multiple_columns.ipynb b/example_multiple_columns.ipynb index 32e4e00..c6bf67d 100644 --- a/example_multiple_columns.ipynb +++ b/example_multiple_columns.ipynb @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -37,190 +37,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
Aryl_halide_SMILESAdditive_SMILESBase_SMILESLigand_SMILESyield
entry
49FC(F)(F)c1ccc(Cl)cc1o1nccc1c2ccccc2CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCCCC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)...10.657812
50FC(F)(F)c1ccc(Br)cc1o1nccc1c2ccccc2CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCCCC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)...14.747896
51FC(F)(F)c1ccc(I)cc1o1nccc1c2ccccc2CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCCCC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)...18.278686
52COc1ccc(Cl)cc1o1nccc1c2ccccc2CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCCCC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)...2.475058
53COc1ccc(Br)cc1o1nccc1c2ccccc2CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCCCC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)...6.119058
..................
4603Brc1ccccn1COC(=O)c1cc(on1)c2sccc2CN1CCCN2CCCN=C12CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5...57.426670
4604Ic1ccccn1COC(=O)c1cc(on1)c2sccc2CN1CCCN2CCCN=C12CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5...86.233157
4605Clc1cccnc1COC(=O)c1cc(on1)c2sccc2CN1CCCN2CCCN=C12CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5...1.440081
4606Brc1cccnc1COC(=O)c1cc(on1)c2sccc2CN1CCCN2CCCN=C12CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5...43.538365
4607Ic1cccnc1COC(=O)c1cc(on1)c2sccc2CN1CCCN2CCCN=C12CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5...69.795902
\n", - "

3955 rows × 5 columns

\n", - "
" - ], - "text/plain": [ - " Aryl_halide_SMILES Additive_SMILES \\\n", - "entry \n", - "49 FC(F)(F)c1ccc(Cl)cc1 o1nccc1c2ccccc2 \n", - "50 FC(F)(F)c1ccc(Br)cc1 o1nccc1c2ccccc2 \n", - "51 FC(F)(F)c1ccc(I)cc1 o1nccc1c2ccccc2 \n", - "52 COc1ccc(Cl)cc1 o1nccc1c2ccccc2 \n", - "53 COc1ccc(Br)cc1 o1nccc1c2ccccc2 \n", - "... ... ... \n", - "4603 Brc1ccccn1 COC(=O)c1cc(on1)c2sccc2 \n", - "4604 Ic1ccccn1 COC(=O)c1cc(on1)c2sccc2 \n", - "4605 Clc1cccnc1 COC(=O)c1cc(on1)c2sccc2 \n", - "4606 Brc1cccnc1 COC(=O)c1cc(on1)c2sccc2 \n", - "4607 Ic1cccnc1 COC(=O)c1cc(on1)c2sccc2 \n", - "\n", - " Base_SMILES \\\n", - "entry \n", - "49 CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCC \n", - "50 CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCC \n", - "51 CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCC \n", - "52 CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCC \n", - "53 CN(C)P(N(C)C)(N(C)C)=NP(N(C)C)(N(C)C)=NCC \n", - "... ... \n", - "4603 CN1CCCN2CCCN=C12 \n", - "4604 CN1CCCN2CCCN=C12 \n", - "4605 CN1CCCN2CCCN=C12 \n", - "4606 CN1CCCN2CCCN=C12 \n", - "4607 CN1CCCN2CCCN=C12 \n", - "\n", - " Ligand_SMILES yield \n", - "entry \n", - "49 CC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)... 10.657812 \n", - "50 CC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)... 14.747896 \n", - "51 CC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)... 18.278686 \n", - "52 CC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)... 2.475058 \n", - "53 CC(C)C1=CC(C(C)C)=CC(C(C)C)=C1C2=C(P(C3CCCCC3)... 6.119058 \n", - "... ... ... \n", - "4603 CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5... 57.426670 \n", - "4604 CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5... 86.233157 \n", - "4605 CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5... 1.440081 \n", - "4606 CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5... 43.538365 \n", - "4607 CC(C1=C(C2=C(OC)C=CC(OC)=C2P(C34CC5CC(C4)CC(C5... 69.795902 \n", - "\n", - "[3955 rows x 5 columns]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df = pd.read_csv('https://raw.githubusercontent.com/b-shields/edbo/master/experiments/data/aryl_amination/experiment_index.csv',\n", " index_col=0)\n", @@ -236,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -287,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -303,7 +122,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -319,20 +138,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RandomForestRegressor()" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "model = RandomForestRegressor()\n", "model.fit(X_train, Y_train)" @@ -340,7 +148,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -352,36 +160,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now we can use molplotly to see all the components corresponding to each point in the scatter plot!" + "Now we can use molplotly to see all the components corresponding to each point in the scatter plot! Select the SMILES columns you'd like to plot by choosing from the dropdown menu :)" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - " \n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "fig_scatter = px.scatter(df_test,\n", " x=\"yield\",\n", @@ -400,13 +186,6 @@ "# change the arguments here to run the dash app on an external server and/or change the size of the app!\n", "app_scatter.run_server(mode='inline', port=8751, height=1000)\n" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now changing the slider value changes which column is used for displaying the structure of the molecule." - ] } ], "metadata": { @@ -428,7 +207,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.10.0" }, "orig_nbformat": 4 }, diff --git a/molplotly/main.py b/molplotly/main.py index 643c2c1..728e916 100644 --- a/molplotly/main.py +++ b/molplotly/main.py @@ -95,34 +95,49 @@ def add_molecules( "color_col needs to be specified if there is more than one plotly curve in the figure!" ) - app = JupyterDash(__name__) + app = JupyterDash(__name__) if isinstance(smiles_col, str): smiles_col = [smiles_col] - - if len(smiles_col)>1: - slider = dcc.Slider(min=0, max=len(smiles_col)-1, step=1, marks={i:smiles_col[i] for i in range(len(smiles_col))}, value=0, - id='smiles-slider') + + if len(smiles_col) > 1: + menu = dcc.Dropdown( + options=[{"label": x, "value": x} for x in smiles_col], + value=smiles_col[0], + multi=True, + id="smiles-menu", + placeholder="Select a SMILES column to display", + ) else: - slider = dcc.Store(id='smiles-slider', data=0) - - app.layout = html.Div([ - dcc.Graph(id="graph-basic-2", figure=fig, clear_on_unhover=True), - dcc.Tooltip( + menu = dcc.Store(id="smiles-menu", data=0) + app.layout = html.Div( + [ + menu, + dcc.Graph(id="graph-basic-2", figure=fig, clear_on_unhover=True), + dcc.Tooltip( id="graph-tooltip", background_color=f"rgba(255,255,255,{alpha})" ), - slider - ]) + ] + ) @app.callback( - output=[Output("graph-tooltip", "show"), Output("graph-tooltip", - "bbox"), Output("graph-tooltip", "children")], - inputs=[Input("graph-basic-2", "hoverData"), Input("smiles-slider", "value")] + output=[ + Output("graph-tooltip", "show"), + Output("graph-tooltip", "bbox"), + Output("graph-tooltip", "children"), + ], + inputs=[Input("graph-basic-2", "hoverData"), Input("smiles-menu", "value")], ) def display_hover(hoverData, value): if hoverData is None: return False, no_update, no_update + if value is None: - value = 0 + value = smiles_col + if isinstance(value, str): + chosen_smiles = [value] + else: + chosen_smiles = value + pt = hoverData["points"][0] bbox = pt["bbox"] num = pt["pointNumber"] @@ -137,30 +152,43 @@ def display_hover(hoverData, value): hoverbox_elements = [] if show_img: - # The 2D image of the molecule is generated here - smiles = df_row[smiles_col[value]] - buffered = BytesIO() - img = Chem.Draw.MolToImage(Chem.MolFromSmiles(smiles)) - d2d = rdMolDraw2D.MolDraw2DSVG(svg_size, svg_size) - opts = d2d.drawOptions() - opts.clearBackground = False - d2d.DrawMolecule(Chem.MolFromSmiles(smiles)) - d2d.FinishDrawing() - img_str = d2d.GetDrawingText() - buffered.write(str.encode(img_str)) - img_str = base64.b64encode(buffered.getvalue()) + # # The 2D image of the molecule is generated here + for col in chosen_smiles: + # if col in chosen_smiles: + # print(df_row) + smiles = df_row[col] + buffered = BytesIO() + d2d = rdMolDraw2D.MolDraw2DSVG(svg_size, svg_size) + opts = d2d.drawOptions() + opts.clearBackground = False + d2d.DrawMolecule(Chem.MolFromSmiles(smiles)) + d2d.FinishDrawing() + img_str = d2d.GetDrawingText() + buffered.write(str.encode(img_str)) + img_str = base64.b64encode(buffered.getvalue()) + img_str = "data:image/svg+xml;base64,{}".format(repr(img_str)[2:-1]) + # img_str = df_data.query(f"{col} == @smiles")[f"{col}_img"].values[0] - img_str = "data:image/svg+xml;base64,{}".format(repr(img_str)[2:-1]) - - hoverbox_elements.append( - html.Img( - src=img_str, - style={ - "width": "100%", - "background-color": f"rgba(255,255,255,{mol_alpha})", - }, + if len(smiles_col) > 1: + hoverbox_elements.append( + html.H2( + f"{col}", + style={ + "color": colors[curve_num], + "font-family": fontfamily, + "fontSize": fontsize + 2, + }, + ) + ) + hoverbox_elements.append( + html.Img( + src=img_str, + style={ + "width": "100%", + "background-color": f"rgba(255,255,255,{mol_alpha})", + }, + ) ) - ) if title_col is not None: title = df_row[title_col] @@ -170,12 +198,12 @@ def display_hover(hoverData, value): else: title = title[:wraplen] + "..." hoverbox_elements.append( - html.H2( + html.H4( f"{title}", style={ "color": colors[curve_num], "font-family": fontfamily, - "fontSize": fontsize + 2, + "fontSize": fontsize, }, ) )