Commit caf353b5 authored by Ninjani's avatar Ninjani
Browse files

first commit

parents
# Turterra
A portal for protein families
## Installation
```sh
conda install -c bioconda epa-ng hmmer muscle fasttree
git clone https://github.com/TurtleTools/turterra.git
cd turterra
pip install .
bin/turterra
```
html {
font-size: 62.5%; }
body {
font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
line-height: 1.6;
font-weight: 400;
font-family: "Fira Sans", Helvetica, Arial, sans-serif;
color: #222; }
/* Typography
–––––––––––––––––––––––––––––––––––––––––––––––––– */
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 2rem;
font-weight: 300; }
h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
/* Larger than phablet */
@media (min-width: 550px) {
h1 { font-size: 5.0rem; }
h2 { font-size: 4.2rem; }
h3 { font-size: 3.6rem; }
h4 { font-size: 3.0rem; }
h5 { font-size: 2.4rem; }
h6 { font-size: 1.5rem; }
}
p {
margin-top: 0; }
/* Links
–––––––––––––––––––––––––––––––––––––––––––––––––– */
a {
color: #1EAEDB; }
a:hover {
color: #0FA0CE; }
\ No newline at end of file
#!/usr/bin/env python3
from turterra.app_layout import get_layout
from turterra.app_callbacks import register_callbacks
from pathlib import Path
from dash_extensions.enrich import (
DashProxy,
TriggerTransform,
MultiplexerTransform,
ServersideOutputTransform,
)
import typer
STATIC = Path("static")
if not STATIC.exists():
STATIC.mkdir()
external_stylesheets = [
"https://unpkg.com/purecss@1.0.1/build/base-min.css",
"https://unpkg.com/purecss@2.0.6/build/pure-min.css",
"https://unpkg.com/purecss@2.0.6/build/grids-responsive-min.css",
"https://fonts.googleapis.com/css?family=Fira+Code:wght@500|Fira+Sans+Condensed|Cantarell|VT323&display=swap",
]
def run(
host: str = typer.Argument("0.0.0.0", help="host IP to serve the app"),
port: int = typer.Argument(8888, help="port"),
):
app = DashProxy(
__name__,
transforms=[
TriggerTransform(), # enable use of Trigger objects
MultiplexerTransform(), # makes it possible to target an output multiple times in callbacks
ServersideOutputTransform(),
],
external_stylesheets=external_stylesheets,
assets_url_path="bin/assets",
url_base_pathname="/",
prevent_initial_callbacks=True,
)
app.config.suppress_callback_exceptions = True
app.layout = get_layout()
register_callbacks(app)
app.run_server(host=host, port=port, debug=True)
if __name__ == "__main__":
typer.run(run)
#!/usr/bin/env python3
from pathlib import Path
import inspect
import os
from shutil import copyfile
import subprocess
import prody as pd
import typer
import turterra.dependencies.modeller.homology_modelling as homology_modelling
import turterra.dependencies.modeller.parallel_modelling
from turterra.dependencies.modeller.make_modeller_files import make_modeller_files
from turterra.dependencies.modeller.move_best_models import copy_best_models
def make_directory(parent, dir_name):
dir = os.path.join(parent, dir_name)
if not os.path.exists(dir):
os.mkdir(dir)
return dir
def run(fasta: str, template_dir: str, num_threads: int):
parallel_modelling_file = inspect.getfile(
turterra.dependencies.modeller.parallel_modelling
)
homology_modelling_file = inspect.getfile(
turterra.dependencies.modeller.homology_modelling
)
print(parallel_modelling_file)
print(homology_modelling_file)
cwd = os.path.abspath(os.getcwd())
modeller_dir = make_directory(cwd, "turterra_models")
data_dir = make_directory(modeller_dir, ".data")
running_dir = make_directory(data_dir, "running")
alignment_dir = make_directory(data_dir, "alignments")
fasta_dir = make_directory(data_dir, "fastas")
all_models_dir = make_directory(data_dir, "all_models")
running_script = os.path.join(running_dir, "parallel_modelling.py")
copyfile(parallel_modelling_file, running_script)
os.chdir(running_dir)
templates_fasta, key_file = make_modeller_files(
fasta, template_dir, alignment_dir, fasta_dir, data_dir
)
command = [
"python",
running_script,
homology_modelling_file,
template_dir,
templates_fasta,
alignment_dir,
all_models_dir,
key_file,
str(num_threads),
]
subprocess.run(command)
copy_best_models(all_models_dir, modeller_dir)
if __name__ == "__main__":
typer.run(run)
from distutils.core import setup
setup(
name="turterra",
version="1.0",
authors=["Barbara Terlouw", "Janani Durairaj"],
packages=[
"turterra",
"turterra/utils",
"turterra/dependencies",
"turterra/dependencies/pikachu",
"turterra/dependencies/modeller",
],
install_requires=[
"numpy",
"numba",
"scipy",
"prody",
"biopython",
"typer",
"pyparsing",
"dash",
"dash-bio==0.5.*",
"dash-daq",
"dash-bio-utils",
"cryptography",
"dash-cytoscape==0.2.0",
"dash-extensions",
"matplotlib",
"pandas",
],
extras_require={"model": ["modeller",]},
scripts=["bin/turterra", "bin/turterra-build"],
)
from turterra import app_callbacks, app_layout
from turterra.utils.compound_utility import Compound
__all__ = ["app_callbacks", "app_layout", "Compound"]
This diff is collapsed.
import dash_core_components as dcc
import dash_daq as daq
import dash_cytoscape
import dash_html_components as html
from dash_extensions import Download
from turterra.utils import tree_utility
INTRODUCTION_TEXT = """Folder needs to have:
* sequences.fasta
* alignment.fasta
* smiles.tsv - mapping name of compound to compound smiles
* tree.txt - newick representation of tree
* structures - folder with PDB files (*_model.pdb represent homology models)
* data.txt - tab-separated file with Accession, Species, Compounds as must-have columns, and other information as optional columns
"""
def get_layout():
return html.Div(
children=[
get_introduction_panel(),
html.Div(
className="pure-g", children=[get_input_panel(), get_tree_panel(), ]
),
html.Div(
className="pure-g",
children=[get_sequence_panel(), get_structure_panel(), ],
),
html.Div(
className="pure-g", children=[get_compound_panel(), get_upload_panel(), ]
),
]
)
BOX_STYLE = {
"border-width": "0.5%",
"border-style": "solid",
"border-color": "rgba(0,0,0,0.5)",
"border-radius": "10px",
"background-color": "#f9f7f7",
"width": "45.5%",
"padding": "2%",
}
BUTTON_STYLE = {
"text-align": "center",
"margin": "0 auto",
"display": "flex",
"justify-content": "center",
}
def get_introduction_panel():
return html.Div(
html.Div(
[
html.H1("Turterra", style={"text-align": "center"}),
html.H5(
"""A web portal to explore protein families""",
style={"text-align": "center"},
),
html.Br(),
# html.P(dcc.Markdown(INTRODUCTION_TEXT), style={"text-align": "left"}),
html.Div(
[
html.Button(
"Load data",
id="input-load-button",
className="pure-button pure-button-primary",
style=BUTTON_STYLE,
),
dcc.Loading(dcc.Store(id="input-turterra-data"), type="dot"),
html.Br(),
],
className="row",
),
],
),
)
def get_input_panel():
return html.Div(
id="input-panel",
children=[
html.H3("Filter", style={"text-align": "center"}),
html.Br(),
html.Div(
html.P(
"""Filter and select accessions below, or by clicking on nodes in the phylogenetic tree"""
),
),
html.Div(
[
dcc.Dropdown(
id="filter-species-dropdown",
options=[],
value=[],
placeholder="Filter by species",
multi=True,
),
dcc.Dropdown(
id="filter-compound-dropdown",
options=[],
value=[],
placeholder="Filter by specificity",
multi=True,
),
html.Br(),
html.Button(
"Filter",
id="filter-filter-button",
className="pure-button pure-button-primary",
style=BUTTON_STYLE,
),
html.Br(),
],
),
html.Div(
[
dcc.Dropdown(
id="filter-accession-dropdown",
options=[],
value=[],
placeholder="Select accessions",
multi=True,
className="eight columns",
style={'max-height': '30vh', 'overflow': 'auto'}
),
html.Br(),
html.Button(
children="Select all",
id="filter-select-all-button",
className="pure-button pure-button-primary",
style=BUTTON_STYLE,
),
html.Br(),
html.Div(
html.Button(
"Show results",
id="filter-show-button",
className="pure-button pure-button-primary",
style=BUTTON_STYLE,
),
),
html.Br(),
],
),
html.Br(),
],
className="pure-u-1 pure-u-md-1-2",
style=BOX_STYLE,
)
def get_tree_panel():
return html.Div(
id="phylogeny-panel",
children=[
html.H3("Phylogeny", style={"text-align": "center"}),
html.Br(),
html.Div(
html.P(
"""Inspect phylogeny below by dragging the tree and scrolling to zoom. Any selected entries
after running a search above are highlighted with a red star. Additionally, click any node in the tree
to add this accession to the selected entries."""
),
),
html.Br(),
html.Button(
"Download tree",
id="phylogeny-download-button",
className="pure-button pure-button-primary",
style=BUTTON_STYLE,
),
html.Br(),
Download(id="phylogeny-download-download"),
html.Br(),
html.Div(
dash_cytoscape.Cytoscape(
id="phylogeny-tree-viewer",
elements=[],
stylesheet=tree_utility.TREE_STYLESHEET,
layout={"name": "preset"},
minZoom=0.1,
maxZoom=1,
style={"height": "70vh", "width": "100%"},
),
id="phylogeny-tree-container",
),
html.Br(),
html.Br(),
],
className="pure-u-1 pure-u-md-1-2",
style=BOX_STYLE,
)
def get_sequence_panel():
return html.Div(
id="sequence-panel",
children=[
html.H3("Sequence and Alignments", style={"text-align": "center"}),
html.Br(),
html.Div(
[
dcc.RadioItems(
id="sequence-alignment-radio-select-button",
options=[
dict(label="Single Sequence", value="Single Sequence"),
dict(
label="Sequence Alignment", value="Sequence Alignment"
),
dict(
label="Structure Alignment", value="Structure Alignment"
),
],
labelStyle={"display": "inline-block"},
value="Single Sequence",
),
],
),
html.Br(),
html.Div(
[
dcc.Dropdown(
id="sequence-accession-select-dropdown",
options=[],
value=None,
clearable=False,
className="four columns",
)
],
),
html.Br(),
html.Br(),
html.Div(
children=[], id="sequence-sequence-viewer"
),
html.Br(),
html.Br(),
html.Div(
className="pure-g",
children=[
html.Button(
"Download sequence",
id="sequence-single-download-button",
className="pure-button pure-button-primary pure-u-1-3",
style=BUTTON_STYLE,
),
Download(id="sequence-single-download"),
html.Button(
"Download sequences",
id="sequence-multiple-download-button",
className="pure-button pure-button-primary pure-u-1-3",
style=BUTTON_STYLE,
),
Download(id="sequence-multiple-download"),
html.Button(
"Download alignment",
id="sequence-alignment-download-button",
className="pure-button pure-button-primary pure-u-1-3",
style=BUTTON_STYLE,
),
Download(id="sequence-alignment-download")])
],
className="pure-u-1 pure-u-md-1-2",
style=BOX_STYLE,
)
def get_structure_panel():
return html.Div(
id="structure-panel",
children=[
html.H3("Structure", style={"text-align": "center"}),
html.Br(),
html.Div(
[
html.Div(
[
dcc.Dropdown(
id="structure-accession-select-dropdown",
options=[],
value=None,
clearable=False,
placeholder="Select an accession"
),
dcc.Dropdown(
id="structure-visualisation-select-dropdown",
options=[
{"label": x, "value": x}
for x in ["cartoon", "stick", "sphere"]
],
value="cartoon",
clearable=False,
placeholder="Structure visualisation type",
),
dcc.Dropdown(
id="structure-color-scheme-select-dropdown",
options=[],
value=None,
clearable=False,
placeholder="Structure color scheme",
),
],
),
html.Br(),
html.Button(
"Load structure",
id="structure-refresh-button",
className="pure-button pure-button-primary",
style=BUTTON_STYLE,
),
html.Br(),
dcc.Loading(dcc.Store(id="structure-structure-data"), type="dot"),
dcc.Store(id="structure-selected-residue-indices-data"),
html.Br(),
html.Div(
[
html.Div(id="structure-structure-container"),
html.P("", id="structure-model-information"),
],
),
html.Br(),
html.Div(
className="pure-g",
children=[
daq.ColorPicker(
id='structure-residue-color-picker',
label='Selected residue color',
value=dict(hex='#119DFF'),
className="pure-u-1-2"
),
html.Div(className="pure-u-1-2", children=[dcc.Dropdown(
id="structure-residue-visualisation-select-dropdown",
options=[
{"label": x, "value": x}
for x in ["cartoon", "stick", "sphere"]
],
value="cartoon",
clearable=False,
placeholder="Selected residue visualisation type",
)]),
],
),
html.Br(),
html.Div(id="structure-residue-information", style={'max-height': '300px', 'overflow': 'auto'}),
html.Br(),
html.Div(
className="pure-g",
children=[
html.Button(
"Download structure",
id="structure-single-download-button",
className="pure-button pure-button-primary pure-u-1-2",
style=BUTTON_STYLE,
),
Download(id="structure-single-download"),
html.Button(
"Download structures",
id="structure-multiple-download-button",
className="pure-button pure-button-primary pure-u-1-2",
style=BUTTON_STYLE,
),
Download(id="structure-multiple-download"),
])
],
),
],
className="pure-u-1 pure-u-md-1-2",
style=BOX_STYLE,
)
def get_compound_panel():
return html.Div(
id="compound-panel",
children=[
html.H3("Compound structure", style={"text-align": "center"}),
html.Br(),
html.Div(
[
html.P("Select an accession to see its linked compounds"),
html.Br(),
dcc.Dropdown(
id="compound-accession-select-dropdown",
options=[],
value=None,
clearable=False,
),
html.Br(),
html.Div(id="compound-radio-select-button-container"),