VuePdbInput#

Download this notebook from GitHub (right-click to download).


Custom PDB Input Component using Vue.js#

Panel makes it easy to build data apps in Python using a wide range of built in components. Sometimes you want to go beyond those built in components and build custom components instead.

The lessons below will build on each other, culminating in a Panel+Vue.js custom component inspired by medicinal chemistry. It’ll look like this:

Panel Vue.js Component

This guide is heavily inspired by Web Development with Python and Vue.js Components.

What is a Vue Component?#

Vue components are self-contained elements that can render HTML/CSS, store data within Javascript variables, and much more. Once defined, they are callable as HTML tags. For example, within existing HTML a Vue component can be rendered like below:

Vue Component

Here, the Vue component tags <v-component></v-component> are responsible for rendering a part of the frontend that takes user input.

The components are usually defined in a .vue file and require Webpack to serve.

With Panel you can take a simpler approach, there is no need to configure, learn and maintain an advanced javascript build tool chain to utilize Vue.js. We will show you how this is done below using Panels ReactiveHTML.

Lets Get Started#

In order to ensure that all the resources we need (such as Vue.js) are loaded appropriately we need to declare baseclasses which declare these dependencies before we run the panel.extension:

import panel as pn
import param
import requests

class BasicVueComponent(pn.reactive.ReactiveHTML):
    _template = """
    <div id="container" style="height:100%; width:100%; background:#0072B5; border-radius:4px; padding:6px; color:white">
      <vue-component></vue-component>
    </div>
    """
    
    _scripts = {
        "render": """
    const template = "<div>Hello Panel + Vue.js World!</div>"
    const vue_component = {template: template}
    el=new Vue({
        el: container,
        components: {
            'vue-component' : vue_component
        } 
    })
    """
    }
        
    __javascript__=[
        "https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"
    ]
    
class BootstrapVueComponent(BasicVueComponent):
    
    __javascript__=[
        "https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js",
        "https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js",
    ]
    __css__=[
        "https://unpkg.com/bootstrap/dist/css/bootstrap.min.css",
        "https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css",
    ]

Now that we have declared the components we run the extension:

pn.extension(sizing_mode="stretch_width")

Basic Vue Component#

Let’s start by rendering the BasicVueComponent which simply renders a Hello World template using Vue.js:

BasicVueComponent(height=40, width=190)

What are PDBs?#

This example will build a little example based on fetching and rendering so called PDBs. A PDB is a file format that stores 3-D structural information about a protein. This information is useful for example when designing drugs that inhibit disease-causing proteins. We will use the KLIFS open source database of PDBs.

You can find more information about PDBs here.

Getting PDBs#

We can get PDBs using KLIFS structured_pdb_list rest endpoint.

URL = "https://klifs.net/api/structures_pdb_list"

def get_pdb_data_from_klifs(pdb_id):
    if not pdb_id:
        return "Please specify a PDB ID."
    
    params = {'pdb-codes': pdb_id}
    res = requests.get(url = URL, params = params)
    data = res.json()
    
    if res.status_code == 400:
        return f"Error 400, Could not get PDB {pdb_id}", data[1]
        
    return data[0]

Lets test the function:

get_pdb_data_from_klifs("4WSQ") # Examples: 2xyu, 4WSQ

PDBInput Component#

Now we will build a Vue.js component containing an input field and a button that will update the value parameter of the PDBInput component:

class PDBInput(BootstrapVueComponent):
    
    value = param.String()
    
    _template = """
    <div id="container" style="height:100%; width:100%">
      <vue-component></vue-component>
    </div>
    """
    
    _scripts = {
        "render": """
    const template = `
    <div>
      <b-form v-on:keydown.enter.prevent>
        <b-form-input v-model="pdb_id" placeholder="Enter PDB ID" required></b-form-input>
        <b-button variant="secondary" size="sm" v-on:click="setPDBId" style="margin-top:10px;width:100%">
            Retrieve PDB metadata
        </b-button>
      </b-form>
    </div>`
    const vue_component = {
      template: template,
      delimiters: ['[[', ']]'],
      data: function () {
        return {
          pdb_id: data.value,
        }
      },
      methods: {
        setPDBId() {
          data.value = this.pdb_id
        }
      }
    }
    const el = new Vue({
        el: container,
        components: {
            'vue-component': vue_component
        } 
    })
    """
    }
pdb_input = PDBInput(height=90, max_width=800)
pdb_input

Please note how we get and set the value of the Parameterized python class using data.value.

Display the PDB Response#

Next we will bind the get_pdb_data_from_klifs function to the value parameter of the pdb_input component:

iget_klifs_data = pn.bind(get_pdb_data_from_klifs, pdb_id=pdb_input.param.value)
component = pn.Column(
    pdb_input, 
    pn.panel(iget_klifs_data, theme="light")
)
component

Lets wrap it up in a nice app#

ACCENT = "#0072B5"
INFO = """# Featurize Protein Structure

Use the Vue component below to retrieve PDB metadata from [KLIFS](https://klifs.net/). For example for `2xyu` or `4WSQ`"""
pn.template.BootstrapTemplate(
        site="Awesome Panel", title="Custom PDB Input Component using Vue.js", main=[INFO, component], header_background=ACCENT
).servable();

You can serve the app via panel serve VuePdbInput.ipynb and find it at https://localhost:5006/VuePdbInput.

If you want to use Panel for Chemistry and Molecular Biology checkout panel-chemistry.

This web page was generated from a Jupyter notebook and not all interactivity will work on this website. Right click to download and run locally for full Python-backed interactivity.

Download this notebook from GitHub (right-click to download).