#!/usr/bin/env python """ Dashboard app with Bokeh/Panel for epitopepredict Created Sep 2019 Copyright (C) Damien Farrell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ import os import numpy as np import pandas as pd from epitopepredict import plotting, base, peptutils, web, config from epitopepredict import __version__ #from IPython.display import HTML import panel as pn import panel.widgets as pnw helppage = 'http://epitopepredict.readthedocs.io/en/latest/webapp.html' css_file=(os.path.join(base.module_path,'static/custom.css')) js_files = {'sortable': os.path.join(base.module_path,'static/sorttable.js')} css=''.join(open(css_file,'r').readlines()) pn.extension(raw_css=[css]) pn.config.js_files=js_files def predictions_dashboard(path): """Dashboard for viewing results from epitopepredict runs.""" #folder_input = pn.widgets.TextInput(name='path', value='../zaire_test', width=400,width_policy='fit') #reload_btn = pn.widgets.Button(name='reload',width=100,button_type='primary') names = web.get_file_lists(path) if names is None: return preds = web.get_predictors(path,name=names[0]) print (preds) seqname = pnw.Select(name='name', value=names[0], options=names) cutoff_slider = pnw.FloatSlider(name='cutoff', value=.95,start=.75,end=.99,step=0.01) cutoff_method = pnw.Select(name='cutoff method', value='default', options=['default','rank']) n_select = pnw.FloatSlider(name='n',value=1,start=1,end=8,step=1) plot_select = pnw.Select(name='plot view', value='tracks', options=['tracks', 'sequence']) table_select = pnw.Select(name='table view', value='promiscuous', options=['promiscuous','binders']) colorseq_box = pnw.Checkbox(name='color sequences', value=False) header = pn.pane.Markdown('__total sequences: %s__' %len(names), css_classes=['main']) tables = pn.Tabs(width=900) plot = pn.pane.Bokeh(width=800) debug = pn.pane.Markdown('test',style={'font-size': '10pt','background-color':'yellow'}) summary_plot = pn.pane.Bokeh() summary_table_tabs = pn.Tabs() recalc_button = pnw.Button(name='recalculate',width=200) def update_banner(): """Update the banner""" fullpath = os.path.abspath(path) banner = pn.Row(pn.pane.Markdown('<h4>epitopepredict: %s</h4> [help](%s) version %s' %(fullpath,helppage,__version__), css_classes=['divheader'], sizing_mode='stretch_width')) return banner def update_header(target, event): names = web.get_file_lists(event.new) target.object = "_total sequences: %s_" %str(len(names)) return def callback_getpath(event): path = os.path.getcwd() folder.value = path def update_plot(preds,name,cutoff,n,kind): """Plot data view""" if kind == 'tracks': p = plotting.bokeh_plot_tracks(preds,name=name,cutoff=cutoff,n=n,width=1000,title=name) plot.object = p elif kind == 'sequence': p = plotting.bokeh_plot_sequence(preds,name=name,cutoff=cutoff,n=n,width=1000, title=name,color_sequence=colorseq_box.value) plot.object = p return p def update_tables(preds,name,n): """Tabular views of results""" P = preds[0] view = table_select.value tables.clear() for P in preds: if view == 'promiscuous': df = P.promiscuous_binders(n=n,name=name) else: df = P.get_binders(name=name) res = df.to_html(classes="tinytable sortable") div = '<div class="scrollingArea">%s</div>' %res tables.append((P.name, div)) #tables.append((P.name,pn.pane.HTML('<p>hddsadsadsasda</p>',width=700))) return def update(event): """Update all elements""" name = seqname.value n = n_select.value cutoff = cutoff_slider.value kind = plot_select.value debug.object = name preds = web.get_predictors(path,name=name) update_plot(preds,name=name,cutoff=cutoff,n=n,kind=kind) update_tables(preds,name,n) return def update_summary(path): """Summary info for folder""" data = web.get_summary_tables(path) df = pd.concat(data, sort=True).reset_index() #plot = plotting.bokeh_summary_plot(df) #summary_plot.object = plot summary_table_tabs.clear() a = web.aggregate_summary(data) div = web.get_scrollable_table(a) summary_table_tabs.append(('all', div)) names = list(data.keys()) for n in names: df = data[n] res = df.to_html(classes="tinytable sortable") div = '<div class="scrollingArea">%s</div>' %res summary_table_tabs.append((n, div)) return @pn.depends(seqname.param.value,n_select.param.value) def download_link(name,n): if preds is None: return df = preds[0].promiscuous_binders(n=n,name=name) df.to_csv() return pn.Pane(HTML('<a>download</a>'),width=700) info = pn.pane.Markdown(web.get_readme()) banner = update_banner() update_summary(path) #reload_btn.param.watch(load_predictors, 'clicks') #reload_btn.param.trigger() seqname.param.watch(update, 'value') cutoff_slider.param.watch(update, 'value') n_select.param.watch(update, 'value') table_select.param.watch(update, 'value') plot_select.param.watch(update, 'value') seqname.param.trigger('options', 'value') top = pn.Row(header)#,download_link) left = pn.Column(plot,tables,margin=10,sizing_mode='stretch_width') right = pn.Column(seqname,cutoff_slider,cutoff_method,n_select,plot_select, table_select,colorseq_box,css_classes=['widget-box'],width=200) center = pn.Row(left,right) #bottom = pn.Row(table) main = pn.Column(top,center) summarypane = pn.Column(recalc_button,(pn.Row(summary_table_tabs))) tabs = pn.Tabs(('summary', summarypane),('sequence',main),('about',info)) #tabs.append() app = pn.Column(banner,tabs, sizing_mode='stretch_width') return app def run_server(path, port): if path == None: print ('provide a folder') return app = predictions_dashboard(path) from bokeh.server.server import Server def modify_doc(doc): return app.server_doc(doc=doc, title='epitopepredict: %s' %path) print('Opening application on http://localhost:%s/' %port) server = Server({'/': modify_doc}, port=port) server.start() server.show('/') server.run_until_shutdown() return if __name__ == '__main__': import sys, os from optparse import OptionParser parser = OptionParser() parser.add_option("-i", "--results", dest="results", help="Results folder", metavar="FILE") parser.add_option("-x", "--port", dest="port", default=8000, help="Port for web app, default 8000") opts, remainder = parser.parse_args() if opts.results == None: print ('please provide a results folder') sys.exit() run_server(opts.results, opts.port)