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
Examples gallery¶
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 thehttp://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:
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?¶
- protein sequence by SequenceViewer
- protein 3D structure by StructureViewer
- protein secondary structure by SecondaryStructureViewer
- binding sites by SequenceViewer or SequenceFeaturesBar
- Multiple Sequence Alignment by MSAViewer
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:
- Javascript libraries are typically accessible from
window
module. Brython code mustfrom browser import window
,thenwindow.XMLHttpRequest
can be accessed.- Brython offers
new()
function to a Javascript class that should be used to create a constructor of that class- In this particular case a global
request
variable is used, which in Python must be explicitly marked asglobal
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"
Parallel execution in threads¶
Brython implements WebWorkers API [5] in the worker [6] module. This however requires extraction of the congruent part of the code into a separate block of code.
References
[1] | https://brython.info |
[2] | https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest |
[3] | https://developer.mozilla.org/en-US/docs/Web/CSS/Reference |
[4] | https://css-tricks.com/svg-properties-and-css/ |
[5] | https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API |
[6] | https://brython.info/static_doc/en/worker.html |
Change log¶
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