Interface to other libraries

Hi, I am quite amazed about the variety and the visibility of the plots generated by this library.

I hope my message explains well about the situation.

My idea is to link plots to a molecular viewer, e.g. nglview, to show up molecules related to the plot. Along the project, I am demanded to output the location of the file path of the coordinate file of the molecule. I have already managed to integrate the information into the hover view, but I am still struggling on finding the way to link the events on the plot to the molecular viewer.

Within holoviews and the related libraries, the interfaces are well equipped.
Thus, switching elements and plots are quite easy.
However, when I tried to output the information used to communicate between plots to conjugate events on holoview plots to other functions, I couldn’t find the method to extract the information shown up on, for instance, the hover object in stream.
To do this, I guess the program should either continue running on the local machine or require real-time generation of output files triggered by clicking plots to monitoring the events happened on the plot.

If there is any solution with the current version, and if you could share that, I would really appreciate that.

Currently, I’m working on the plot as follows:

import pandas as pd
import holoviews as hv
from bokeh.models import HoverTool
hv.extension('bokeh')

data = {"a": [1.0, 1.0, "path1"], "b": [2.0, 2.0, "path2"], "c": [3.0, 3.0, "path3"]}

# Transformation into Pandas DataFrame objects
df = pd.DataFrame(data, index=["x", "y", "file_path"])

df = df.T

# Which parameter to hover
TOOLTIPS = [("x","@x"), 
            ("y","@y"), 
            ("file_path","@file_path"), 
           ]

# color setting
color_dict = "tab10"

hover = HoverTool(tooltips=TOOLTIPS)

renderer = hv.renderer('bokeh')

# plot setup
plot = hv.Scatter(df,kdims=["x"],vdims=["y"])
plot = plot.add_dimension("file_path",dim_pos=2,vdim=True,dim_val = "file_path")

plot = plot.opts(plot=dict(tools=[hover]))

plot
1 Like

Hi @Ikajiro

I think there are two ways to go.

  • You can use a stream as shown below to react to mouse interaction with your plot.
  • You can embed the nglview inside the tooltip by creating a custom html tooltip as demonstrated in this example

An example of using a stream would be something like this.

import holoviews as hv
import pandas as pd
import panel as pn
from bokeh.models import HoverTool
from holoviews import streams

hv.extension('bokeh')

df = pd.DataFrame({
  "x": [1,2,3], "y": [1,2,3], "file_path": ["path1", "path2", "path3"]
})

TOOLTIPS = [("x","@x"), 
            ("y","@y"), 
            ("file_path","@file_path"), 
           ]

hover = HoverTool(tooltips=TOOLTIPS)

plot = hv.Scatter(df,kdims=["x"],vdims=["y"])
plot = plot.add_dimension("file_path",dim_pos=2,vdim=True,dim_val = "file_path")
plot = plot.opts(plot=dict(tools=[hover]))

pointer = streams.PointerXY(source=plot)


@pn.depends(pointer.param.x, pointer.param.y)
def file_view(x,y):
  if not x or not y:
    return "hover over a point"
  return (x,y)

pn.Column(
  plot, file_view
).servable()
1 Like

Hi @Ikajiro

For example you can create an application using the PointerXY stream like this.

panel-chemistry-app

import hvplot.pandas
import pandas as pd
import panel as pn
import param
from bokeh.models import HoverTool
from holoviews import streams
from panel_chemistry.pane import (
    NGLViewer,  # panel_chemistry needs to be imported before you run pn.extension()
)

pn.extension("ngl_viewer", sizing_mode="stretch_width")

DIST=0.005
HEIGHT=400
ACCENT="#0072b5"

TOOLTIPS = [("x","@x"), 
            ("y","@y"), 
            ("Molecule","@file_path"), 
           ]

df = pd.DataFrame({
  "x": [1,2,3], "y": [1,2,3], "file_path": ["1CRN", "1NKT", "3pqr"]
})

hover = HoverTool(tooltips=TOOLTIPS)

plot = df.hvplot.scatter(x="x", y="y", tools=[hover], color=ACCENT, size=100)
plot = plot.add_dimension("file_path",dim_pos=2,vdim=True,dim_val = "file_path")

pointer = streams.PointerXY(source=plot)
streams.MouseEnter()

molecule_text = pn.pane.Markdown("# Molecule: 1CRN")
ngl_viewer = NGLViewer("1CRN", background="white", height=HEIGHT)

class App(param.Parameterized):
  """Keeps track of the application state"""
  file = param.String(doc="The selected molecule")

app = App()

@pn.depends(pointer.param.x, pointer.param.y, watch=True)
def set_file(x,y, app=app):
  df["dist"]=((df["x"]-x)**2+(df["y"]-y)**2)**1/2
  idxmin = df["dist"].idxmin()
  closest = df.iloc[idxmin,:]
  dist = closest.dist
  if dist<DIST:
    app.file=closest.file_path

@pn.depends(file=app.param.file, watch=True)
def file_view(file):
  if not file:
    return
  molecule_text.object = f"# Molecule: {file}"
  ngl_viewer.object=file

settings = pn.Param(ngl_viewer, parameters=["representation"])
main = pn.Column(plot, molecule_text, ngl_viewer)

pn.template.FastListTemplate(
    site="Awesome Panel",
    site_url="https://awesome-panel.org/sharing",
    favicon="https://raw.githubusercontent.com/MarcSkovMadsen/awesome-panel-assets/320297ccb92773da099f6b97d267cc0433b67c23/favicon/ap-1f77b4.ico",
    title="Chemistry Data Exploration",
    sidebar=[settings], main=[main]
).servable()

I you like the example and would like to help Panel get more know please like or repost this tweet. Thanks.

1 Like

I would like to take the opportunity to highlight that sharing these apps is now super simple because they can be converted to webassembly and shared on github pages, s3, azure blob storage or similar.

And with Awesome Panel Sharing its even simpler:

Try out the app Chemistry Data Exploration

Check out the code https://awesome-panel.org/sharing?app=MarcSkovMadsen%2Fchemistry-data-exploration

chemistry-data-exploration-examp

2 Likes

Hi @Marc,

Thank you for your prompt reply. That’s exactly what I would like to do.

Actually, I was preparing a reply struggling to implement these functions you have already implemented here.
Since I had some troubles on making it, I referred your post and I realized that everything is there!

What a awesome job! Thank you!

1 Like

Thanks @Ikajiro

Please keep us updated and share some of your work. It helps our community build a knowledge base and grow. Thanks.

1 Like