#!/usr/bin/env ccp4-python
'''
Created on 3 Mar 2015
@author: jmht
Notes on pyrvapi from Eugene
remove_widget() may result in an unexpected unless you put flush() immediately before _and_ immediately after calling them, e.g.:
rvapi_flush()
for i in range():
rvapi_remove_widget(..i..)
rvapi_flush()
This is because chronology of rvapi calls between flushes() is not necessarily the same as chronology of making/changing widgets in the page. E.g. in sequence of calls:
rvapi_flush()
rvapi_action1()
rvapi_action2()
rvapi_action3()
rvapi_flush()
rvapi_action4()
rvapi_action5()
rvapi_action6()
rvapi_flush()
it is guaranteed that results of actions 4-6 will appear after results from 1-3, but there is no guarantee that results from 1-3 and 4-6 groups will appear in exactly that order. E.g., the page may perform actions like 3-1-2-5-4-6, but never like 6-4-1-2-3-5.
'''
import cPickle
import logging
import os
import subprocess
import urlparse
import uuid
from ample.ensembler import ensembler_util
from ample.util import ample_util
from ample.util import mrbump_util
try: import pyrvapi
except: pyrvapi = None
class AmpleOutput(object):
"""Display the output of an AMPLE job
"""
_ensemble_tooltips = {
"Name" : "Ensemble name - used to name the pdb file and the directory where mrbump carries out molecular replacement.",
"Cluster" : "The SPICKER cluster that this ensemble was derived from.",
"Truncation Level" : "Percentage of the model remaining after the varying residues were pruned away",
"Variance Threshold (A^2)" : "THESEUS variance score for the most variable residue that remains in this ensemble",
"No. Residues" : "Number of residues for each model in the ensemble",
"Radius Threshold (A)" : "Radius threshold (1,2 or 3 A) used for subclustering the models in a truncation level",
"No. Decoys" : "Number of models within this ensemble",
"Number of Atoms" : "Number of atoms for each model in the ensemble",
"Sidechain Treatment" : "allatom - all sidechains were retained, reliable - MET, ASP, PRO, GLN, LYS, ARG, GLU, SER were retained, polyAla - all sidechains were stripped back to polyalanine",
}
_mrbump_tooltips = {
"ensemble_name" : "The identifier of the AMPLE ensemble search model",
"MR_program" : "Molecular replacement program",
"Solution_Type" : "MRBUMP categorisation of the solution",
"PHASER_LLG" : "PHASER Log-likelihood gain for the Molecular Replacement solution",
"PHASER_TFZ" : "PHASER Translation Function Z-score for the Molecular Replacement solution",
"REFMAC_Rfact" : "Rfact score for REFMAC refinement of the Molecular Replacement solution",
"REFMAC_Rfree" : "Rfree score for REFMAC refinement of the Molecular Replacement solution",
"BUCC_final_Rfact" : "Rfact score for BUCCANEER rebuild of the Molecular Replacement solution",
"BUCC_final_Rfree" : "Rfree score for BUCCANEER rebuild of the Molecular Replacement solution",
"ARP_final_Rfact" : "Rfact score for ARPWARP rebuild of the Molecular Replacement solution",
"ARP_final_Rfree" : "Rfree score for ARPWARP rebuild of the Molecular Replacement solution",
"SHELXE_CC" : "SHELXE Correlation Coefficient score after C-alpha trace",
"SHELXE_ACL" : "Average Chain Length of the fragments of the SHELXE C-alpha trace",
"SXRBUCC_final_Rfact" : "Rfact score for BUCCANEER rebuild of the SHELXE C-alpha trace",
"SXRBUCC_final_Rfree" : "Rfree score for BUCCANEER rebuild of the SHELXE C-alpha trace",
"SXRARP_final_Rfact" : "Rfact score for ARPWARP rebuild of the SHELXE C-alpha trace",
"SXRAP_final_Rfree" : "Rfree score for ARPWARP rebuild of the SHELXE C-alpha trace",
}
def __init__(self):
self.running = None
self.webserver_uri = None
self.wbeserver_start = None
self.log_tab_id = None
self.results_tab_id = None
self.results_tab_sections = []
self.summary_tab_id = None
self.summary_tab_ensemble_sec_id = None
self.summary_tab_results_sec_id = None
self.summary_tab_survey_sec_id = None
self.old_mrbump_results = None
return
def create_log_tab(self, results_dict):
if self.log_tab_id: return
logfile = results_dict['ample_log']
if not os.path.isfile(logfile): return False
self.log_tab_id = "log_tab"
logurl = self.fix_path(logfile)
pyrvapi.rvapi_add_tab(self.log_tab_id, "Log file", True) # Last arg is "open" - i.e. show or hide
# Add watched (updatable) content to the log tab.
pyrvapi.rvapi_append_content(logurl, True, self.log_tab_id)
# pyrvapi.rvapi_flush()
return self.log_tab_id
def create_results_tab(self, results_dict):
if not self.summary_tab_id: return
if not self._got_mrbump_results(results_dict): return
mrb_results = results_dict['mrbump_results']
if mrb_results == self.old_mrbump_results: return
self.old_mrbump_results = mrb_results
if not self.results_tab_id:
self.results_tab_id = "results_tab"
# Insert results tab before summary tab
pyrvapi.rvapi_insert_tab(self.results_tab_id, "Results", self.summary_tab_id, False) # Last arg is "open" - i.e. show or hide
# Delete old sections:
pyrvapi.rvapi_flush()
for section_id in self.results_tab_sections:
pyrvapi.rvapi_remove_widget(section_id)
pyrvapi.rvapi_flush()
self.results_tab_sections = []
ensemble_results = None
if self._got_ensemble_data(results_dict):
ensemble_results = results_dict['ensembles_data']
self.results_section(self.results_tab_id,
mrbump_util.ResultsSummary().sortResults(mrb_results,
prioritise="SHELXE_CC")[0:min(len(mrb_results),mrbump_util.TOP_KEEP)],
ensemble_results,
"Top {0} SHELXE Results".format(mrbump_util.TOP_KEEP))
self.results_section(self.results_tab_id,
mrbump_util.ResultsSummary().sortResults(mrb_results,
prioritise="PHASER_TFZ")[0:min(len(mrb_results),mrbump_util.TOP_KEEP)],
ensemble_results,
"Top {0} PHASER Results".format(mrbump_util.TOP_KEEP))
return self.results_tab_id
def _create_summary_tab(self):
if not self.summary_tab_id:
self.summary_tab_id = "summary_tab"
# Insert summary tab before log tab
pyrvapi.rvapi_insert_tab(self.summary_tab_id, "Summary", self.log_tab_id, False) # Last arg is "open" - i.e. show or hide
return
def create_summary_tab(self, results_dict):
#
# Summary Tab
#
if not self.log_tab_id: return
if not (results_dict['single_model_mode'] or results_dict['homologs'] or not self._got_ensemble_data(results_dict)):
ensembles_data = results_dict['ensembles_data']
self._create_summary_tab()
# Hack to cope with ideal helices and importing ensembles
def do_ensemble_sec(results_dict):
return not (results_dict['ideal_helices'] or results_dict['import_ensembles'] or results_dict['homologs'])
if not self.summary_tab_ensemble_sec_id and do_ensemble_sec(results_dict):
self.summary_tab_ensemble_sec_id = "ensembles"
pyrvapi.rvapi_add_section(self.summary_tab_ensemble_sec_id, "Ensembles", self.summary_tab_id, 0, 0, 1, 1, True)
# Get the ensembling data
clusters, cluster_method, truncation_method, percent_truncation, side_chain_treatments = ensembler_util.collate_cluster_data(ensembles_data)
rstr = ""
rstr += "Ensemble Results
"
rstr += "----------------
"
rstr += "Cluster method: {0}
".format(cluster_method)
rstr += "Truncation method: {0}
".format(truncation_method)
rstr += "Percent truncation: {0}
".format(percent_truncation)
rstr += "Side-chain treatments: {0}
".format(side_chain_treatments)
rstr += "Number of clusters: {0}
".format(len(clusters.keys()))
rstr += "Generated {0} ensembles
".format(len(ensembles_data))
pyrvapi.rvapi_add_text(rstr, self.summary_tab_ensemble_sec_id, 0, 0, 1, 1)
ensemble_table = "ensemble_table"
pyrvapi.rvapi_add_table1(self.summary_tab_ensemble_sec_id + "/" + ensemble_table, "Ensembling Results", 1, 0, 1, 1, True)
# for cluster_num in sorted(clusters.keys()):
# rstr += "\n"
# rstr += "Cluster {0}\n".format(cluster_num)
# rstr += "Number of models: {0}\n".format(clusters[cluster_num]['cluster_num_models'])
# rstr += "Cluster centroid: {0}\n".format(clusters[cluster_num]['cluster_centroid'])
# rstr += "\n"
# tdata = cluster_table_data(clusters, cluster_num)
# rstr += tableFormat.pprint_table(tdata)
#
cluster_num = 1
tdata = ensembler_util.cluster_table_data(clusters, cluster_num, side_chain_treatments)
self.fill_table(ensemble_table, tdata, tooltips=self._ensemble_tooltips)
#
# MRBUMP Results
#
if not self._got_mrbump_results(results_dict): return self.summary_tab_id
self._create_summary_tab()
if not self.summary_tab_results_sec_id:
# Only create the table once
self.summary_tab_results_sec_id = "mrbump"
pyrvapi.rvapi_add_section(self.summary_tab_results_sec_id, "MRBUMP", self.summary_tab_id, 0, 0, 1, 1, True)
self.summary_tab_results_sec_table_id = "mrbump_table"
pyrvapi.rvapi_add_table1(self.summary_tab_results_sec_id + "/" + self.summary_tab_results_sec_table_id, "MRBUMP Results", 1, 0, 1, 1, True)
mrb_results = results_dict['mrbump_results']
if not mrb_results == self.old_mrbump_results:
# We set old_mrbump_results when we create the results_tab
self.fill_table(self.summary_tab_results_sec_table_id,
mrbump_util.ResultsSummary().results_table(mrb_results),
tooltips=self._mrbump_tooltips)
#
# Survey section
#
if not self.summary_tab_survey_sec_id:
# Only create the table once
self.summary_tab_survey_sec_id = "survey"
pyrvapi.rvapi_add_section(self.summary_tab_survey_sec_id, "Feedback", self.summary_tab_id, 0, 0, 1, 1, True)
rstr = "