Welcome to VisuaLife’s documentation!

Installation

Including VisuaLife in your webpage

If you want to add Visualife script to you HTML page, just do the two simple steps:

  • download visualife.brython.js file
  • add the following line to your project (remember to enter relative to path to the file)
<script src="visualife.brython.js"></script>

Local installation

Install the latest released verion of visualife with this line:

pip install visualife

You can also clone raw VisuaLife repository from BitBucket website. Here is the command that you can copy, paste and run in a terminal:

git clone https://bioshell@bitbucket.org/dgront/visualife.git

Live demo

Here you can try VisuaLife library

How To

This section provides answers to frequent questions, that looks easy to answer, but that requires digging somewhat deeper into the documentation.

General issues

How to convert an SVG file produced by VL to another format?

The easiest way is to use Inkscape [1] program. The conversion can be done from command line:

# on MacOS
~/bin/Inkscape.app/Contents/MacOS/inkscape plot.svg --export-filename=plot.png -d 500

# on Windows
inkscape "C:\path\plot.svg" --export-filename="C:\path\plot.png"

# on Linux
inkscape -z -e plot.png -w 1000 -d 500 plot.svg

Questions regarding plotting

How to adjust data range on a plot?

Data range is set by Plot class constructor, e.g.

pl = Plot(drawing,200,1000,200,1000,0.0,110.0,0.0,150.0,axes_definition="UBLR")
pl.bars(x_data, y_data, adjust_range=False)

where the plotting area is a square 800x800 (from 200 to 1000 along each direction) and data range on X and Y axes are [0, 110.0] and [0.0, 150.0], respectively. These ranges can be also set after a Plot object has been constructed:

pl.axes["B"].min_data_value = 0
pl.axes["B"].max_data_value = 15

This will affect bottom axis (because of B). Remember to switch off automatic data range assignment by setting adjust_range=False kwarg argument when plotting.

Questions regarding widgets

How to download a PDB file?

Use AjaxCommunication widget for that purpose:

def receive_structure(evt = None):
    print(evt.text.split("\n")[:10])

AjaxCommunication("https://files.rcsb.org/view/%s.pdb" % pdb_code, receive_structure)()

pdb_code variable provides the code of a protein to be acquired (e.g. 2gb1) and receive_structure() is the callback method that is called when AjaxCommunication finally receives the data. The protein comes as text (in the PDB) format and it’s receive_structure() responsibility to process it further. Here it just breaks the text into lines and prints the top 10 lines of the file.

References

[1]https://inkscape.org

Tutorials

Quick start from template files

To start working with VisuaLife library you can use these two template files:

and VL library in binary format visualife.brython.js . The .html file is a web page with included VL library, and the .py file is a python code that will be executed in this web page.

You also need to have brython files in external_libs/ directory (brython.js and brython_stdlib.js)

Brython script from .py file needs to be loaded on the web page. For that you need to run HTTP server which will run the script. Simple opening in web browser won’t work here. To make these files to work use one from following solutions:

  • for PyCharm users: open .html file in PyCharm and then use function “run in a browser” - this option will appear in the rigth upper corner after mouseover on the .html text
  • for console users: in the directory with your files, run the command python3 -m http.server and then open the browser on the http://0.0.0.0:8000 adress. Choose .html file to display.

Plot tutorial

This page will guide you through your first script that makes a plot with VisuaLife

Choose your viewport: HTML or SVG?

Viewport is a class that is responsible for displaying your drawing. There are three viewports available:

  • SvgViewport: writes your drawing or a plot into an .svg file on your computer; you have to provide the name of the output file
  • HtmlViewport: draws or makes a plot on a web page. You have to provide the id string of a web element, the graphics will be added to that element as SVG elements.
  • CanvasViewport: it also draws or makes a plot on a web page, but uses pixels rather than SVG. It can draw much more objects (eg. data points in your plot), but the content is not interactive

SvgViewport and HtmlViewport behave in the same manner. They share the same set of methods and produces graphics that looks exactly the same. You should make your drawing in SvgViewport first and once it works as you expect, copy & paste your Python code into a web page. Just remember to replace SvgViewport with HtmlViewport.

Simplest SvgViewport example

Let’s begin with a very simple example that produces an SVG file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import sys
sys.path.append('../../')
from visualife.core import SvgViewport

drawing = SvgViewport("simplest.svg", 500, 500,"white")

for i in range(16):
    for j in range(16):
        circle_id = "c-%d-%d" % (i, j)
        drawing.circle(circle_id, i * 400 / 16.0 + 50, j * 400 / 16.0 + 50, 10, fill="pink")

drawing.close()

Simplest HtmlViewport example

Now the same example, but now as an HTML page:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<html>
<head>
    <script src="external_libs/brython.js"></script>
    <script src="external_libs/brython_stdlib.js"></script>
    <script src="visualife.brython.js"></script>
</head>

<body onload="brython()">

<script type="text/python">
from browser import document
from visualife.core import HtmlViewport

drawing = HtmlViewport(document['svg'],  500, 500,"white")

for i in range(16):
    for j in range(16):
        circle_id = "c-%d-%d" % (i, j)
        drawing.circle(circle_id, i * 400 / 16.0 + 50, j * 400 / 16.0 + 50, 10, fill="pink")
        	
drawing.close()
</script>

    <svg  id="svg" xmlns="http://www.w3.org/2000/svg" class="right" height="500" width="500"></svg>

</body>

</html>

As you can see there are few differences in this example comparing to the SvgViewport:

  • HTML tags that create a page
  • inlucing brython and visualife libraries in the <head> part
  • from browser import document that is a brython import which allows user to access webpage elements
  • importing and using HtmlViewport instead of SvgViewport

Simple plot in terminal - creating SVG

You can already make a simple drawing in both terminals so now it’s time for creating a plot. You can do it in SvgViewport using simple python script. Lets say you have a file co2emission.txt on your computer and it looks like this:

year	emission[K_tons]	emission_change[%]
2016	775752 				1.28
2015	765922 				0.06
2014	765489 				-5.04
2013	806144 				2.39
2012	787320 				1.00
2011	779506 				-2.49
2010	799376 				5.31
2009	759093 				-7.39
2008	819698 				1.30
2007	809186 				-3.24
2006	836310 				1.54
2005	823601 				-3.79
2004	856087 				0.76
2003	849643 				-1.02
2002	858391 				-1.67

To make a plot you will simply run:

python3 plot_from_file.py co2emission.txt

This command will make a plot from first column as X and second column as Y by default. If you want to make a plot from year (1st column) and emission_change(3rd column) you can run:

python3 plot_from_file.py co2emission.txt 1 3

Script also takes first row as axis labels. Below you can see how the script looks like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import sys
sys.path.append('../../')
from visualife.core import Plot, SvgViewport
from visualife.core.styles import make_darker
from random import random

if len(sys.argv) <2 :
  print("USAGE: python3 plot_from_file.py ../inputs/phi_psi.results [1 2]")
  exit()
filename = sys.argv[1]
col_x = 1
col_y = 2
if len(sys.argv)>2:
  col_x = int(sys.argv[2])
  col_y = int(sys.argv[3])
data_x =[]
data_y = []

with open(filename) as file:
	data = file.readlines()
	x_label = data[0].strip().split()[col_x-1]
	y_label = data[0].strip().split()[col_y-1]
	for line in data[1:]:
		tokens = line.strip().split()
		data_x.append(float(tokens[col_x-1]))
		data_y.append(float(tokens[col_y-1]))

drawing = SvgViewport(filename.split(".")[0]+".svg",1200, 1200,"white")
pl = Plot(drawing,200,1000,200,1000,min(data_x)-1,max(data_x)+1,min(data_y)-1,max(data_y)+1,axes_definition="UBLR")

stroke_color = make_darker("SteelBlue", 0.3)
pl.axes["B"].label = x_label
pl.axes["L"].label = y_label
for key,ax in pl.axes.items() :
  ax.fill, ax.stroke, ax.stroke_width = stroke_color, stroke_color, 3.0
  ax.tics(0,5)

pl.scatter(data_x,data_y,markersize=6, markerstyle='c', title="serie-1",colors=0)
pl.line(data_x,data_y, colors=0)

pl.draw(grid=True)
drawing.close()

First twenty lines is responsible for loading a file and packing data into lists. Then from line 25th SvgViewport and Plot objects are created. Finally method Plot.scatter and Plot.line are called to draw both dots and line for this plot that will look like this:

_images/co2emission.svg

How to make plots online?

Simple plot in a web-browser

Now we will do the same plot as in previous example but using HtmlViewport so it is going to be display in a browser on a HTML page. We will use brython in a <script> tag to make it work. One difference is that you need to have your file already in a script, because brython will not read file from your computer in the same way as python. Other differences were already discussed earlier in first part of these tutorial.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<html>
<head>
    <script src="brython.js"></script>
    <script src="brython_stdlib.js"></script>
    <script src="visualife.brython.js"></script>
</head>

<body onload="brython()">

<script type="text/python">
from browser import document
from visualife.core import Plot, HtmlViewport
from visualife.core.styles import make_darker
from random import random

file = """year	emission[K_tons]	emission_change[%]
2016	775752 				1.28
2015	765922 				0.06
2014	765489 				-5.04
2013	806144 				2.39
2012	787320 				1.00
2011	779506 				-2.49
2010	799376 				5.31
2009	759093 				-7.39
2008	819698 				1.30
2007	809186 				-3.24
2006	836310 				1.54
2005	823601 				-3.79
2004	856087 				0.76
2003	849643 				-1.02
2002	858391 				-1.67"""

data_x=[]
data_y=[]
data = file.split("\n")
x_label = data[0].strip().split()[0]
y_label = data[0].strip().split()[1]
for line in data[1:]:
	tokens = line.strip().split()
	data_x.append(float(tokens[0]))
	data_y.append(float(tokens[1]))

drawing = HtmlViewport(document["svg"], 0, 0, 600, 600,"white")
pl = Plot(drawing,100,500,100,500,min(data_x)-1,max(data_x)+1,min(data_y)-1,max(data_y)+1,axes_definition="UBLR")

stroke_color = make_darker("SteelBlue", 0.3)
pl.axes["B"].label = x_label
pl.axes["L"].label = y_label
for key,ax in pl.axes.items() :
  ax.fill, ax.stroke, ax.stroke_width = stroke_color, stroke_color, 3.0
  ax.tics(0,5)

pl.scatter(data_x,data_y,markersize=3, markerstyle='c', title="serie-1",colors=0)
pl.line(data_x,data_y, colors=0)

pl.draw(grid=True)
drawing.close()


</script>

    <svg  id="svg" xmlns="http://www.w3.org/2000/svg" class="right" height="600" width="600"></svg>

</body>

</html>

The plot will look exactly the same.

Online plot from REST data

Sometimes there is a need to download data from the Internet. We created ../api/visualife.widget.AjaxSender to make it easier for VisuaLife users to download data. Using this class you can send POST or GET requestes and use recived data eg. for plotting. There is also a python library json that can code and decode JSON format that is used in this requestes. In this example JSON looks like this

In lines no. 38 (script below) the AjaxSender object is constructed. In the next line call operator is used to send a request. After reciving the respons method on_complete will be called. json.loads() change string variable to python object eg. list or dictionary. Then you can get your data and plot them as in the previous example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<html>
<head>
    <script src="brython.js"></script>
    <script src="brython_stdlib.js"></script>
    <script src="visualife.brython.js"></script>
</head>

<body onload="brython()">

<script type="text/python">
from browser import document
from visualife.core import Plot, HtmlViewport
from visualife.core.styles import make_darker
from visualife.widget import AjaxSender
from random import random
import json

def on_complete(evt):
	data = json.loads(evt.text)
	data_x,data_y=[],[]
	for i in range(0,len(data)):
		data_x.append(data[i]["x"])
		data_y.append(data[i]["y"])

	drawing = HtmlViewport(document["svg1"], 0, 0, 1200, 1200,"white")
	pl = Plot(drawing,200,1000,200,1000,min(data_x)-1,max(data_x)+1,min(data_y)-1,max(data_y)+1,axes_definition="UBLR")

	stroke_color = make_darker("SteelBlue", 0.3)
	for key,ax in pl.axes.items() :
	  ax.fill, ax.stroke, ax.stroke_width = stroke_color, stroke_color, 3.0
	  ax.tics(0,5)

	pl.scatter(data_x,data_y,markersize=6, markerstyle='c', title="serie-0",colors=1)
	pl.draw(grid=True)
	drawing.close()

link = "https://raw.githubusercontent.com/sgreben/jp/master/examples/mvrnorm.json"
a= AjaxSender(link,on_complete,"GET")
a()

</script>

    <svg  id="svg1" xmlns="http://www.w3.org/2000/svg" class="right" height="500" width="500"></svg>

</body>

</html>

Let’s make it interactive!

This is the last and probably the most interesting part in this tutorial. You are now going to add interactivity to your plot using only Python(Brython exactly)! It is very simple. All the points are in the SVG tag with id serie-1. To select these points you need to select this tag by id and take its children elements (line no. 42). Then iterate over all points and bind a function that will be called on event (line no. 44). All the events can be found here. Function needs to take one argument - fired event.

Now when you put your mouse over the point you can see that it’s id appears on the screen!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<html>
<head>
    <script src="brython.js"></script>
    <script src="brython_stdlib.js"></script>
    <script src="visualife.brython.js"></script>
</head>

<body onload="brython()">

<script type="text/python">
from browser import document
from visualife.core import Plot, HtmlViewport
from visualife.core.styles import make_darker
from visualife.widget import AjaxSender,TooltipWidget
from random import random
import json

ttw = TooltipWidget("ttw1","container","",150,20)

def show_tooltip(evt):
    ttw.tooltip_text = evt.target.id
    ttw.show(evt.clientX, evt.clientY)

def on_complete(evt):
	data = json.loads(evt.text)
	data_x,data_y=[],[]
	for i in range(0,len(data),4):
		data_x.append(data[i]["x"])
		data_y.append(data[i]["y"])

	drawing = HtmlViewport(document["svg2"], 0, 0, 1200, 1200,"white")
	pl = Plot(drawing,200,1000,200,1000,min(data_x)-1,max(data_x)+1,min(data_y)-1,max(data_y)+1,axes_definition="UBLR")

	stroke_color = make_darker("SteelBlue", 0.3)
	for key,ax in pl.axes.items() :
	  ax.fill, ax.stroke, ax.stroke_width = stroke_color, stroke_color, 3.0
	  ax.tics(0,5)

	pl.scatter(data_x,data_y,markersize=6, markerstyle='c', title="serie-1",colors=1)
	pl.draw(grid=True)
	drawing.close()
	points = document["serie-1"].children
	for p in points:
		p.bind("mouseover",show_tooltip)
		p.bind("mouseout",ttw.hide)

link = "https://raw.githubusercontent.com/sgreben/jp/master/examples/mvrnorm.json"
a= AjaxSender(link,on_complete,"GET")
a()

</script>
    <div id="container" style="width:500px"></div>

    <div class="tooltip" id="tooltip"></div>

    <svg  id="svg2" xmlns="http://www.w3.org/2000/svg" class="right" height="500" width="500"></svg>

</body>

</html>

Application tutorial

VisuaLife has a module named widget which contains components for creating applications for protein analysis. In this tutorial you will see how to display various type of protein data and how to ensure communication between widgets. Application described in this tutorial is availble here.

What data can VisuaLife display?

Today you will learn about first four widgets but if you would like to know more about MSAViewer don’t hesitate to look at its documentation.

Getting and parsing data

Use ../api/visualife.widget.AjaxSender to get the data that you need. This object takes URL as a first argument and a function to call after receiving the data. If you want to get file from your computer URL will be a path to this file:

            i_seq = msa_json[i]["sequence"]

“GET” is an optional argument that indicates request type. Default is “POST”. More about HTTP requests you can find here.

AjaxCommunication widget is often used to fetch a protein structure in the PDB format. This can be done by the following snippet:

def receive_structure(evt = None):
    print(evt.text.split("\n")[:10])

AjaxCommunication("https://files.rcsb.org/view/%s.pdb" % pdb_code, receive_structure)()

pdb_code variable provides the code of a protein to be acquired (e.g. 2gb1) and receive_structure() is the callback method that is called when AjaxCommunication finally receives the data. The protein comes as text (in the PDB format) format and it’s receive_structure() responsibility to process it further. Here it just breaks the text into lines and prints the top 10 lines of the file.

Presented application was made in a way that it can work from every computer so the data should be download from other websites. We use https://www.ebi.ac.uk and https://www.rcsb.org which allows to get their files with “GET” request and no CORS error. We wanted to analyse every possible PDB file, so we added input window where you can type your PDB code. Below there is a part of code responsible for getting this data.

    AjaxCommunication("https://www.ebi.ac.uk/pdbe/api/pdb/entry/residue_listing/%s" % pdb_name, set_first_res, "GET")()
    AjaxCommunication("https://www.ebi.ac.uk/pdbe/api/pdb/entry/molecules/%s" % pdb_name, receive_sequence, "GET")()
    AjaxCommunication("https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary/%s" % pdb_name, receive_protein_description, "GET")()

After receiving the respond, callback function from AjaxSender constructor is called. In this function you will need to decode the data with json.loads() function which converts JSON string to python structures as lists and dictionaries. Then you will parse the data and get the info that you need to eg. create widgets. In the below example the variable first_res_id is set from received data.

def set_first_res(req):
    """Sets the number of first residue in the chain"""
    global pdb_name, first_res_id
    data = json.loads(req.text)
    first_res_id = data[pdb_name]["molecules"][0]["chains"][0]["residues"][0]["author_residue_number"]

Creating widgets

One thing you need to be careful about is that the order of receiving all these responses is unknown, as well as the order of function calls. Sometimes you need to already have some variable set, before other function is called. If this is the case, then it is better to send some request later, not all at once.

In this application we need to know the number of residues to create secondary structure string. This is why we will call ss2_ajax() after setting N_res variable.

def receive_sequence(ajax):
    """Sets the sequence and calls download of binding site and secondary structure"""
    global N_res, sequence, resi_repr, pdb_name
    d = json.loads(ajax.text)
    sequence = d[pdb_name][0]["sequence"]
    N_res = len(sequence)
    resi_repr = [None for i in range(N_res)]
    binding = AjaxCommunication("https://www.ebi.ac.uk/pdbe/api/pdb/entry/binding_sites/%s" % pdb_name, binding_site, "GET")
    ss2_ajax()
    binding()

We already have a sequence but because we are going to mark binding sites on the SequenceViewer, we will also send a request about it. After receiving the data SequenceViewer will be created and we will be sure to have the right order of calls.

Let’s look on the binding_site() function (called after receiving the data - last line in the code above)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
def binding_site(req):
    """Gets info about binding sites and creates according regions on SequenceViewer"""
    global sequence, pdb_name, ss2_str, E, H
    seq = SequenceViewer("show_sequence", pdb_name, sequence, n_columns_of_ten=4, first_residue_id=first_res_id)
    seq.secondary_structure = ss2_str
    seq.set_event_callback("CLICK_ON_LETTER", click_on_aa)

    seq.regions_palette = "accent"
    output = json.loads(req.text)[pdb_name]
    for site in output:
        desc = site["details"].split()
        desc_str = ""
        for i in desc[:4]:
            desc_str += i.lower() + " "
        for i in desc[4:]:
            desc_str += i + " "
        i = 0
        if desc[-3] in ["GOL", "PO4", "SO4", "HOH"]: continue  # --- remove obvious buffer compounds from the list of ligands
        for res in site["site_residues"]:
            i += 1
            aa = res["author_residue_number"]

In the 4th line SequenceViewer widget is created. In the next line secondary structure is set (to make it possible to colour the sequence with this info). In the line no. 6 function click_on_aa() is set as a callback - this function will be called after clicking on the letter in the sequence (more about it in the next paragraph). In the next line colour pallete is set for colouring the regions. In lines 8-20 received data are parsed according to needs and finally in line no. 21 proper aminoacides from binding sites were added to the corresponding regions.

Communication between widgets

Now let’s go back to setting callback function in SequenceViewer. Function is called after clicking on an aminoacid. Every function which is called after firing an event - takes this event as an argument. From the event we can get event target’s id, which will be necessery to conclude which aminoacid was clicked. Having this information we can transfer it to StructureViewer and change style of this aminoacid in this widget. It allows for example to select every aminoacid from one binding site and see how it looks like in the 3D structure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def click_on_aa(evt):
    """Function called when you click on a letter in amino acid sequence"""
    global panel3d, sequence, resi_repr
    pos = int(evt.target.id.split("-")[3]) - 1 # evt.target.id is like: "ch-show_sequence-15" for pos 15
    if pos in residues_clicked:
        evt.target.style.backgroundColor = residues_clicked[pos]
        panel3d.remove_style("1",resi_repr[pos])
        del(residues_clicked[pos])
    else:
        resi_repr[pos] = panel3d.add_style("1", "licorice", {"color": "atomindex", "sele": "%d" % (pos + first_res_id)})
        residues_clicked[pos] = evt.target.style.backgroundColor
        evt.target.style.backgroundColor = "yellow"

Because we want to change the style back after second click we are storing style info about selected aminoacides in a dictionary. After second click we can go back to previous representation in StructureViewer and unselect aminoacid in SequenceViewer.

That’s all! If you need further information, please look at widget documentation and Examples gallery.

Brython tips

The main objective for the VisuaLife library is to move all the development of the client-side part of a web application to Python. Brython is the mean to achieve that goal. By translating Python code to JavaScript, it can make your data, plots and graphics interactive. This document provides a quick list of tips intended to help you building your own web application with VisuaLife and Brython. For a more elaborate documentation you should head to official Brython website [1]

Adding HTML page elements with Brython

The html module of Brython distribution provides classes that correspond to HTML elements. E.g. to add the new DIV element, use the following:

from browser import html, document
el = html.DIV("A text inside a div", id="id_of_this_div"):
document["outer_element"] <= el

Note how the newly created element el is inserted into the page.

Accessing HTML page elements

The easiest way to access an element of a page is to reach it by its ID, e.g. document["element_id"]. This way one can change element properties or alter its content:

document["a_div"].innerHTML = "The quick brown fox jumps over the lazy dog"
document["a_div"].style.

Binding Python code to HTML page elements

First define your function, e.g.:

def action(evt):
  print("user interacted with", evt.target.id)

The content printed with the print() method will show up in a browser’s console; that is the easiest way for debugging. Note, that the target element, i.e. the element user clicked, hovered with a mouse pointer, etc, can be accessed as a JS object as evt.target field. Moreover, ID of that element can be found as evt.target.id.

To bind this function to an element, just use:

document["my_element_id"].bind("event-name", action)

where action is the method to be called and "event-name" is the name of the event that should trigger that function. Here is a list of commonly used events:

  • input – user changes a form element, e.g. clicks on a radio button or enters a text to an input field
  • click – user clicks on an element, e.g. on a <DIV>
  • mouseover – user hoovers an element with a mouse pointer

Using Javascript libraries in Brython code

Brython can be seamlessly combined with Javascript libraries. Javascript and Python syntax for calling object’s methods and reaching its properties is basically the same. The differences however are in importing modules (import keyword) and in calling a constructor - Python doesn’t have new operator. Compare the two programs below; both use XMLHttpRequest [2] library to asynchronously download some content from a server.

from  browser import document, window, console

def req_listener():
    global request
    console.log(request.responseText)

request = window.XMLHttpRequest.new()
request.open('GET', "http://www.example.org/example.txt")
request.responseType = 'arraybuffer'
request.send()
request.onloadend = reqListener
function reqListener () {
  console.log(this.responseText);
}

var request = new XMLHttpRequest();
request.addEventListener("load", reqListener);
request.responseType = 'arraybuffer'
request.open("GET", "http://www.example.org/example.txt");
request.send();

The two codes looks very similar. Three thing are worth noticing:

  1. Javascript libraries are typically accessible from window module. Brython code must from browser import window,then window.XMLHttpRequest can be accessed.
  2. Brython offers new() function to a Javascript class that should be used to create a constructor of that class
  3. In this particular case a global request variable is used, which in Python must be explicitly marked as global

Styling with Brython

Every HTML (or SVG) element has a style property. That property behaves as an object with attributes corresponding to SVG styling properties. The list of supported properties can be found here for HTML [3] and here for SVG [4]. Note that CSS properties are spelled differently than their Brython counterparts. Since a dash character cannot appear in a Python variable name, Bryton uses camelCase, e.g. instead of background-color CSS property one must use backgroundColor.

from browser import html, document

el = document["button_to_be_styled"]  # the element
style = el.style
style.backgroundColor = "red"
style.color = "grey"

Change log

To be released in version 1.1

  • [core]: few drawing methods made significantly faster (#af08288)

Version 1.0

Date:May 7, 2021
  • VisuaLife has been published in Bioinformatics journal

Development

Web distribution

VisuaLife library also comes with a “package” version that is a single file that may be easily incorporated in a web page. The file must be updated after every change in the library, otherwise the changes will not affect any of HTML examples. SVG examples will work properly, as they use regular Python version of the library.

To build visualife.brython.js file make sure you have brython package installed on your machine, e.g.

pip3 install brython

then go to the distribution directory and simply run:

./make_vl_js.sh

New visualife.brython.js file will be created in distribution/ directory.

visualife.calc Package

Classes

DataBins2D(**kwargs) DataBins2D class is a kind of a 2D histograms that records all the data that has been inserted into it.
Histogram(**kwargs) Creates a new Histogram instance :param kwargs: see below :return: new Histogram instance
Histogram2D(**kwargs) Creates a new Histogram2D instance :param kwargs: see below :return: new Histogram2D instance

visualife.calc.math_utils Module

Functions

linspace(start, stop, **kwargs) Return evenly spaced numbers over a specified interval.
polar_to_cartesian(r, degrees[, x0, y0]) Converts polar coordinates r, degrees to Cartesian coordinates
regular_polygon(n[, r, cx, cy, phase]) Returns a list of vertices of a regular convex n-polygon, centered at (cx,cy) by default at (0,0)

visualife.core Package

Functions

clamp(val[, minimum, maximum]) Clamps color value to the given range, by default to [0, 255]
color_name_to_hex(name) Convert COLOR NAME to HEX format
hex_to_rgb(hex_str) Convert HEX string to RGB format
hsv_to_hex(hsv) Convert HSV tuple to HEX format
hsv_to_rgb(hsv) Convert HSV tuple to RGB tuple
is_hex(color) Checks if the color is in HEX format
make_brighter(color[, factor]) Creates color brighter with factor
make_darker(color[, factor]) Creates color darker with factor
mix_colors(color1, color2, fraction) Creates a color that is a mixture of two colors.
rgb_norm_to_hex(rgb) Convert normalised RGB tuple to HEX format
rgb_to_hex(rgb) Convert RGB tuple to HEX format
shade(color, factor) Creates color changed with factor

Classes

Axis(min_screen, max_screen, min_data, max_data) Represents an arbitrary axis of a plot.
AxisX(screen_y, min_screen, max_screen, …) Represents X axis of a plot.
AxisY(screen_x, min_screen, max_screen, …) Represents Y axis of a plot.
BarDataSet(converter, *args, **kwargs) Creates a BarDataSet object with X, Y and Z data (if given)
BubblesDataSet(converter, *args, **kwargs) Creates a BarDataSet object with X, Y and Z data (if given)
CachedColorMap(cmap, v_from, v_to, v_step) A class that uses pre-computed color indexes
CanvasViewport(canvas, width, height) Creates a Canvas drawing
DataConverter(plot, x_code, y_code) Converts plot data values to screen coordinates values
DataSet(converter, *args, **kwargs) Stores data for serie and its min and max values
DraggablePlot(viewport, min_screen_x, …[, …]) Represents a draggable plot object
HtmlViewport(div_element, svg_width, svg_height) Draws graphics on a WWW page, in a given <svg> element of a HTML page.
LineDataSet(converter, *args, **kwargs) Stores data for lineplot
Plot(viewport, min_screen_x, max_screen_x, …) Creates a plot object with axes
PlotLegend() Stores series data to draw a plot legend
ScatterDataSet(converter, *args, **kwargs) Stores data for scatterplot
SvgViewport(file_name, svg_width, svg_height) Defines a viewport that saves a drawing into an SVG file

visualife.core.styles Module

Functions

clamp(val[, minimum, maximum]) Clamps color value to the given range, by default to [0, 255]
color_name_to_hex(name) Convert COLOR NAME to HEX format
colormap_by_name(scale_name, min_val, max_val) Sets the real values for colors for given color map Returns ColorMap object
create_style(**kwargs) Creates a string encoding a style of a SVG element
get_font_size(x) Return a size from a real value argument
hex_to_rgb(hex_str) Convert HEX string to RGB format
hsv_to_hex(hsv) Convert HSV tuple to HEX format
hsv_to_rgb(hsv) Convert HSV tuple to RGB tuple
is_hex(color) Checks if the color is in HEX format
make_brighter(color[, factor]) Creates color brighter with factor
make_darker(color[, factor]) Creates color darker with factor
mix_colors(color1, color2, fraction) Creates a color that is a mixture of two colors.
rgb_norm_to_hex(rgb) Convert normalised RGB tuple to HEX format
rgb_to_hex(rgb) Convert RGB tuple to HEX format
shade(color, factor) Creates color changed with factor

Classes

CachedColorMap(cmap, v_from, v_to, v_step) A class that uses pre-computed color indexes
ColorMap(stops, **kwargs) A class that converts a real value into a color

visualife.core.shapes Module

Functions

arc(drawing, id_str, x0, y0, r, deg_from, …) Draws a circular arc sector
arrow(drawing, id_str, width, height, tip_width) Draws an arrow
circle_segment(drawing, id_str, x0, y0, …) Draws a circular sector
dots(viewport, id_str, x, y, w, h, r, c, …) Draws a dotted pattern.
grid(viewport, id_str, x, y, w, h, **kwargs) Draws a line grid.

visualife.core.three_d Package

Classes

DendrogramNode(id, value, distance, *nodes) Dendrogram node adds a distance value and a group_id properties to a TreeNode class
Face(id, verts, **kwargs) Represents a face for Svg3DPanel
Line(id, vb, ve, **kwargs) Represents a line for Svg3DPanel
MoleculePanel(svg_canvas[, width, height]) Represents a panel to display chemical molecules
Sphere(id, vertex, r, **kwargs) Represents a sphere for Svg3DPanel
SpheresGroup(id, vertices, radii, **kwargs) Represents a group of spheres for Svg3DPanel
Svg3DPanel(svg_canvas, width, height) Represents a panel for displaying 3D objects

visualife.data Package

Functions

combine_score_files(*args, **kwargs) Reads a number of score files and combines them by merging rows of the same tag
create_sequence(residues) Creates an amino acid sequence from a list of Residue objects.
detect_bonds(a_chain) Detects bonds between atoms of this chain
filter_score_file(scorefile, filter, column_name) Filters given column in scorefile with a given filtr
parse_mol_data(mol_as_txt) Reads a text in mol2 format and creates a Molecule object
parse_pdb_atom(atom_line) Parses an ATOM line of a PDB file and creates a new atom.
parse_pdb_data(pdb_as_text, **kwargs) Parses PDB data
read_clustal(input_text[, max_fields]) Reads a ClustalW file with Multiple Sequence Alignment
read_clustering_tree(fname_or_data[, …]) Read a clustering tree produced by BioShell package.
read_fasta(input_text) Reads a FASTA file that contains nucleic / amino acid sequences
read_msf(input_text) Reads a MSF file
read_newick_dictionary(newick[, if_read_file]) Reads a tree in the Newick format :param newick: (string) - a file name or the data itself :param if_read_file: (boolean) - if true, it’s assumed the input is a file name and the data must be loaded from a file.
secondary_structure_residues(pdb_as_text, …) Reads PDB header and extracts residues that belong to secondary structure elements (SSEs)
secondary_structure_string(pdb_as_text, residues) Reads PDB header and creates a secondary structure in FASTA format
tree_from_dictionary(dict_root[, node_class]) Transforms a tree from a dictionary representation into a “true” tree of DendrogramNode nodes :param node_dict: (string) - dictionary of nodes, e.g.
write_pdb_atom(atom[, res_name, chain_id]) Returns a string in PDB format that holds data for a given atom

Classes

Atom(args) Represents an atom, e.g.
Bond(atom1, atom2[, type]) Represents a single chemical bond between two atoms
Chain(chainid) Represents one chain from biomolecular structure
DendrogramNode(id, value, distance, *nodes) Dendrogram node adds a distance value and a group_id properties to a TreeNode class
HSSP(file_name_or_data) Reads HSSP files and stores the data
Molecule() Represents a molecule as a list of its atoms and bonds
Residue(rname, resid[, icode]) Represents a residue including its name, id, atoms, owner etc.
ScoreFile(input_file, **kwargs) Score file is a tabular data format, originally used by Rosetta to store energy values
Structure() Holds data for biomolecular structure, obtained eg from a PDB file

visualife.diagrams Package

Functions

average_point(points) Determines a Point that is an average of given Point objects.
balance_binary_tree(root) Balances a binary tree
clone_tree(node, n_levels) Creates a deep copy of a given tree, that might be limited in depth
deepcopy(x[, memo, _nil]) Deep copy operation on arbitrary Python objects.
repack_node_style_args(node_style_dict, …) Repacks drawing style for node and text
subtree_size(root) Calculates size of every subtree of a give tree

Classes

BTreeNode(id, value[, left, right]) Creates a binary tree node.
CircularDendrogram(id, viewport, …) Draws a binary tree using a circular dendrogram layout
Connector(id, *points, **attrs) Connector is a line path that connects two nodes of a diagram.
DendrogramLayout(id, viewport, max_screen_x, …) Draws a binary tree using a dendrogram layout
DendrogramNode(id, value, distance, *nodes) Dendrogram node adds a distance value and a group_id properties to a TreeNode class
Diagram(viewport, id, **kwargs) Diagrams made out of rectangular shapes, possibly connected with lines.
DiamondNode(id, text, xc, yc, w, **attrs) Draws a diamond node.
DotNode(id, x, y, r, **attrs) Creates a node that is dot.
InteractiveCondition(node, code_snippet, …)
InteractiveDiagram(viewport, id) Diagram that can execute code snippets
InteractiveNode(node, code_snippet, **params) Extends InteractiveNode with a code snipped.
NodeBase(id, x, y) A base class to all nodes.
Point(x, y) A simple data structure to hold X,Y coordinates on a screen.
RectNode(id, text, xc, yc, w, h, **attrs) Rectangular node of a diagram - a box with a text in it.
TreeLayout(id, viewport, max_screen_x, …) Base class for drawing a tree
TreeNode(id, value) Creates a tree node.
TriangularLayout(id, viewport, min_screen_x, …) Draws a binary tree using a triangular layout

visualife.serverside Package

Functions

scorefile_to_json_dictionary(…) Reads data in scorefile format and returns it as a dictionary

visualife.utils Package

Functions

consecutive_find(string[, …]) Detects ranges of identical characters in a given string.
create_tooltip(id_text, tooltip_text, width, …) Creates DIV with tooltip and returns it
detect_blocks(secondary_str) Detects secondary structure blocks (segments)
fix_python_code(python_text) Reformats Python source to correct some formatting issues.
from_string(text, first, last, default) Simple text extractor with a default value.
run_async_func(function[, url])
substitute_template(template, subst_dict) Simple text template replacement utility

Classes

MenuWidget(element_id[, dict_of_menu_items]) Creates a HTML menu

visualife.widget Package

The widgets package contains all the widgets provided by library, i.e. independent web-page components devised to display data in an interactive manner.

Classes

AbstractWidget(element_id) Abstract base class for VisuaLife widgets
AjaxCommunication(url[, on_complete, req_type]) Class that sends data with AJAX
DataStorageMap() Class that stores content in a Python dictionary
FileReaderWidget(drop_zone_id[, extensions, …]) Reads a file that has been dropped in a browser window
GLViewerWidget(div_id, **kwargs) Represents a viewer for biological molecules.
MSAViewer(element_id[, msa_header, msa]) Displays a Multiple Sequence Alignment (MSA)
ProcessData Interface for classes that are used by FileReaderWidget to process files that are loaded
SecondaryStructureViewer(element_id[, …]) Creates a widget that displays a protein secondary structure
SequenceFeaturesBar(viewport[, …]) Draws a sequence features widget.
SequenceViewer(element_id[, sequence_name, …]) Creates a widget that displays an amino acid or a nucleotide sequence
StructureViewer(div_id, **kwargs) Represents a viewer for biological molecules.
TableWidget(table_id, parent_id, **kwargs) Creates a new table
TooltipWidget(id_text, parent_id, …) Creates a new tooltip

Data formats

Multiple Sequence Alignment

Protein or nucleic sequences are accepted and returned as a JSON dictionary. In general, VisuaLife does not check if they are properly aligned, thus any sequence database may be stored in that format. The dictionary however has been devised to store data parsed from a format used to store a Multiple Sequence Alignment (MSA):

  • ALN (Clustal-W output)
  • FASTA
  • MSF

Sequences from a file are loaded into a JSON-like dictionary with the following keys:

  • sequence: the sequence itself, in the single-letter code
  • description: longer free-text description of a sequence
  • id: short string identifying a sequence in a database, e.g. PAHAL_7G158700

It’s not guaranteed that all the three keys will be present in an entry.

VisuaLife is a lightweight visualisation library implemented in Python. It’s intended to make impressive graphics in a web browsers as easily as possible - just with a few lines of Python. Yes, Python! The library uses Brython to run on the client side. The library can be also used in regular Python script, run on your local machine to produce output in SVG format. VisuaLife can help anyone who would like to quickly and easily make interactive plots, drawings and data applications.

The source code of VisuaLife is hosted on BitBucket. In order to use it however you don’t have to clone the package; just download the visualife.brython.js file, more details in installation section