@@ -98,29 +98,35 @@ def publish_data(self, name, data_source_obj):
9898
9999class PyHDXController (MainController ):
100100 """
101- Main controller for PyHDX web application
101+ Main controller for PyHDX web application.
102102
103103 """
104- fit_results = param .Dict ({}, doc = 'Dictionary of fit results' )
105- peptides = param .ClassSelector (PeptideMasterTable , doc = 'Master list of all peptides' )
106- series = param .ClassSelector (KineticsSeries , doc = 'KineticsSeries object with current selected and corrected peptides' )
104+ fit_results = param .Dict ({}, doc = 'Dictionary of fit results' , precedence = - 1 )
105+ peptides = param .ClassSelector (PeptideMasterTable , doc = 'Master list of all peptides' , precedence = - 1 )
106+ series = param .ClassSelector (KineticsSeries ,
107+ doc = 'KineticsSeries object with current selected and corrected peptides' , precedence = - 1 )
107108
108109 def __init__ (self , * args , ** kwargs ):
109110 super (PyHDXController , self ).__init__ (* args , ** kwargs )
110- #setup options #todo automate figure out cross dependencies (via parent?)
111- self .control_panels ['OptionsControl' ].link_xrange = True
112111
113112
114113class ComparisonController (MainController ):
115114 """
116- Main controller for binary comparison web application
115+ Main controller for binary comparison web application.
117116 """
118117
119- datasets = param .Dict (default = {}, doc = 'Dictionary for all datasets' ) #todo refactor
118+ datasets = param .Dict (default = {}, doc = 'Dictionary for all datasets' )
120119 comparisons = param .Dict (default = {}, doc = 'Dictionary for all comparisons (should be in sources)' )
121120
122121
123122class MappingFileInputControl (ControlPanel ):
123+ """
124+ This controller allows users to upload *.txt files where quantities (protection factors, Gibbs free energy, etc) are
125+ mapped to a linear sequence.
126+
127+ The column should be tab separated with on the last header line (starts with '#') the names of the columns. Columns
128+ should be tab-delimited.
129+ """
124130 header = 'File Input'
125131
126132 input_file = param .Parameter (default = None , doc = 'Input file to add to available datasets' )
@@ -143,7 +149,6 @@ def _input_file_updated(self):
143149 self .dataset_name = self .dataset_name or Path (self ._widget_dict ['input_file' ].filename ).stem
144150
145151 def _action_add_dataset (self ):
146- print ('action add' )
147152 if self .dataset_name in self .parent .datasets .keys ():
148153 self .parent .logger .info (f'Dataset { self .dataset_name } already added' )
149154 elif not self .input_file :
@@ -173,19 +178,26 @@ def _datasets_updated(self, events):
173178
174179
175180class DifferenceControl (ControlPanel ):
181+ """
182+ This controller allows users to select two datasets from available datasets, choose a quantity to compare between,
183+ and choose the type of operation between quantities (Subtract/Divide).
184+
185+ """
176186 header = 'Differences'
177187
178- dataset_1 = param .Selector (doc = 'ds1 ' )
179- dataset_2 = param .Selector (doc = 'ds2 ' )
188+ dataset_1 = param .Selector (doc = 'First dataset to compare ' )
189+ dataset_2 = param .Selector (doc = 'Second dataset to compare ' )
180190
181191 comparison_name = param .String ()
182- operation = param .Selector (default = 'Subtract' , objects = ['Subtract' , 'Divide' ])
192+ operation = param .Selector (default = 'Subtract' , objects = ['Subtract' , 'Divide' ],
193+ doc = 'Select the operation to perform between the two datasets' )
183194
184195 comparison_quantity = param .Selector (doc = "Select a quantity to compare (column from input txt file)" )
185196 add_comparison = param .Action (lambda self : self ._action_add_comparison (),
186197 doc = 'Click to add this comparison to available comparisons' )
187198 comparison_list = param .ListSelector (doc = 'Lists available comparisons' )
188- remove_comparison = param .Action (lambda self : self ._action_remove_comparison ())
199+ remove_comparison = param .Action (lambda self : self ._action_remove_comparison (),
200+ doc = 'Remove selected comparisons from the list' )
189201
190202 def __init__ (self , parent , ** params ):
191203 super (DifferenceControl , self ).__init__ (parent , ** params )
@@ -207,6 +219,7 @@ def _selection_updated(self):
207219 datasets = (self .parent .datasets [self .dataset_1 ], self .parent .datasets [self .dataset_2 ]) # property?
208220 unique_names = set .intersection (* [{name for name in array .dtype .names } for array in datasets ])
209221
222+ #todo check for scalar-type dtype
210223 objects = [name for name in unique_names if name != 'r_number' ]
211224 self .param ['comparison_quantity' ].objects = objects
212225 if self .comparison_quantity is None :
@@ -255,21 +268,20 @@ def _update_comparison_list(self):
255268 self .param ['comparison_list' ].objects = objects
256269
257270
258- # def _action_remove_comparison(self):
259- # for comparison_name in self.comparison_list:
260- # self.parent.comparisons.pop(comparison_name)
261- # self.parent.param.trigger('comparisons')
262-
263-
264271class PeptideFileInputControl (ControlPanel ):
272+ """
273+ This controller allows users to input .csv file (Currently only DynamX format) of 'state' peptide uptake data.
274+ Users can then choose how to correct for back-exchange and which 'state' and exposure times should be used for
275+ analysis.
276+
277+ """
265278 header = 'Peptide Input'
266279
267280 add_button = param .Action (lambda self : self ._action_add (), doc = 'Add File' , label = 'Add File' )
268281 clear_button = param .Action (lambda self : self ._action_clear (), doc = 'Clear files' , label = 'Clear Files' )
269- drop_first = param .Integer (1 , bounds = (0 , None ))
270- ignore_prolines = param .Boolean (True , constant = True , doc = 'Set to True to ignore Prolines in the sequence' )
271- load_button = param .Action (lambda self : self ._action_load (), doc = 'Load Files' , label = 'Load Files' )
272-
282+ drop_first = param .Integer (1 , bounds = (0 , None ), doc = 'Select the number of N-terminal residues to ignore.' )
283+ ignore_prolines = param .Boolean (True , constant = True , doc = 'Prolines are ignored as they do not exchange D.' )
284+ load_button = param .Action (lambda self : self ._action_load (), doc = 'Load the selected files' , label = 'Load Files' )
273285 norm_mode = param .Selector (doc = 'Select method of normalization' , label = 'Norm mode' , objects = ['Exp' , 'Theory' ])
274286 norm_state = param .Selector (doc = 'State used to normalize uptake' , label = 'Norm State' )
275287 norm_exposure = param .Selector (doc = 'Exposure used to normalize uptake' , label = 'Norm exposure' )
@@ -285,7 +297,8 @@ class PeptideFileInputControl(ControlPanel):
285297 exp_exposures = param .ListSelector (default = [], objects = ['' ], label = 'Experiment Exposures'
286298 , doc = 'Selected exposure time to use' )
287299
288- parse_button = param .Action (lambda self : self ._action_parse (), doc = 'Parse' , label = 'Parse' )
300+ parse_button = param .Action (lambda self : self ._action_parse (), label = 'Parse' ,
301+ doc = 'Parse selected peptides for further analysis and apply back-exchange correction' )
289302
290303 def __init__ (self , parent , ** params ):
291304 self .file_selectors = [pn .widgets .FileInput (accept = '.csv' )]
@@ -440,7 +453,7 @@ def __init__(self, parent, **params):
440453
441454 def make_list (self ):
442455 lst = super (CoverageControl , self ).make_list ()
443- return lst + [self .exposure_str ]#, self.color_bar]
456+ return lst + [self .exposure_str ]#\ , self.color_bar]
444457
445458 def make_dict (self ):
446459 return self .generate_widgets (index = pn .widgets .IntSlider )
@@ -452,7 +465,9 @@ def _update_cbar(self):
452465 self .color_mapper .palette = pal
453466
454467 def get_color_bar (self ):
455- """pn.pane.Bokeh: bokeh pane with empty figure and only a color bar"""
468+ """pn.pane.Bokeh: bokeh pane with empty figure and only a color bar
469+ Currently is buggy when added in ``make_list``
470+ """
456471 # f5f5f5
457472 # from default value in panel css
458473 #https://github.com/holoviz/panel/blob/67bf192ea4138825ab9682c8f38bfe2d696a4e9b/panel/_styles/widgets.css
@@ -470,7 +485,7 @@ def get_color_bar(self):
470485
471486 @property
472487 def palette (self ):
473- """"""
488+ """`obj`:tuple: Tuple of hex colors """
474489 cmap = mpl .cm .get_cmap (self .color_map )
475490 pal = tuple (mpl .colors .to_hex (cmap (value )) for value in np .linspace (0 , 1 , 1024 , endpoint = True ))
476491 return pal
@@ -520,7 +535,7 @@ def _series_updated(self, event): #todo refactor
520535 def _update_wrap (self ):
521536 y = list (itertools .islice (itertools .cycle (range (self .wrap , 0 , - 1 )), len (self .coverage )))
522537 try :
523- self .parent .sources ['coverage' ].data .update (y = y )
538+ self .parent .sources ['coverage' ].source . data .update (y = y )
524539 except KeyError :
525540 pass
526541
@@ -536,6 +551,12 @@ def _update_colors(self):
536551
537552
538553class InitialGuessControl (ControlPanel ):
554+ """
555+ This controller allows users to derive initial guesses for D-exchange rate from peptide uptake data
556+
557+ """
558+
559+ #todo remove lambda symbol although its really really funny
539560 header = 'Initial Guesses'
540561 fitting_model = param .Selector (default = 'Half-life (λ)' , objects = ['Half-life (λ)' , 'Association' ],
541562 doc = 'Choose method for determining initial guesses.' )
@@ -571,9 +592,6 @@ async def _fit1_async(self):
571592 data_source = DataSource (dic , x = 'r_number' , y = 'rate' , tags = ['mapping' , 'rate' ],
572593 renderer = 'circle' , size = 10 )
573594
574- # callback = partial(self.parent.param.trigger, 'sources')
575- # self.parent.doc.add_next_tick_callback(callback)
576-
577595 #trigger plot update
578596 callback = partial (self .parent .publish_data , 'fit1' , data_source )
579597 self .parent .doc .add_next_tick_callback (callback )
@@ -636,9 +654,15 @@ def _action_fit(self):
636654
637655
638656class FitControl (ControlPanel ):
657+ """
658+ This controller allows users to execute TensorFlow fitting of the global data set.
659+
660+ Currently, repeated fitting overrides the old result.
661+
662+ """
663+
639664 header = 'Fitting'
640665 initial_guess = param .Selector (doc = 'Name of dataset to use for initial guesses.' )
641-
642666 c_term = param .Integer (None , doc = 'Residue number to which the last amino acid in the sequence corresponds.' ) # remove
643667 temperature = param .Number (293.15 , doc = 'Deuterium labelling temperature in Kelvin' )
644668 pH = param .Number (8. , doc = 'Deuterium labelling pH' , label = 'pH' )
@@ -699,12 +723,10 @@ def _do_fitting(self):
699723 output_dict ['color' ] = np .full_like (result .output , fill_value = DEFAULT_COLORS ['pfact' ], dtype = '<U7' )
700724
701725 # output_dict[f'{var_name}_full'] = output_dict[var_name].copy()
702- # #todo this should be moved to TFFitresults object (or shoud it?) -> DataObject class (see base) (does coloring)
703726 # output_dict[var_name][~self.parent.series.tf_cov.has_coverage] = np.nan # set no coverage sections to nan
704727
705728 #todo update when changing to fitting deltaG directly
706729 output_dict ['pfact' ] = 10 ** output_dict [var_name ]
707- # if self.fitting_type == 'Protection Factors':
708730 deltaG = constants .R * self .temperature * np .log (output_dict ['pfact' ])
709731 output_dict ['deltaG' ] = deltaG
710732
@@ -718,10 +740,14 @@ def _do_fitting(self):
718740 self .parent .param .trigger ('fit_results' )
719741
720742 self .parent .logger .debug ('Finished TensorFlow fit' )
721- self .parent .logger .info (f'Finished fitting in { len (result .loss )} epochs' )
743+ self .parent .logger .info (f'Finished fitting in { len (result .loss [ 0 ] )} epochs' )
722744
723745
724746class FitResultControl (ControlPanel ):
747+ """
748+ This controller allows users to view to fit result and how it describes the uptake of every peptide.
749+ """
750+
725751 header = 'Fit Results'
726752
727753 peptide_index = param .Number (0 , bounds = (0 , None ),
@@ -781,10 +807,18 @@ def _update_sources(self):
781807
782808
783809class ClassificationControl (ControlPanel ):
810+ """
811+ This controller allows users classify 'mapping' datasets and assign them colors.
812+
813+ Coloring can be either in discrete categories or as a continuous custom color map.
814+ """
815+
784816 header = 'Classification'
785817 # format ['tag1', ('tag2a', 'tag2b') ] = tag1 OR (tag2a AND tag2b)
786- accepted_tags = ['mapping' ] #todo add 'comparison' for compare app
818+ accepted_tags = ['mapping' ]
787819
820+ # todo unify name for target field (target_data set)
821+ # When coupling param with the same name together there should be an option to exclude this behaviour
788822 target = param .Selector (label = 'Target' )
789823
790824 mode = param .Selector (default = 'Discrete' , objects = ['Discrete' , 'Continuous' ],
@@ -1006,6 +1040,16 @@ def _update_bounds(self):
10061040
10071041
10081042class FileExportControl (ControlPanel ):
1043+ # todo check if docstring is true
1044+ """
1045+ This controller allows users to export and download datasets.
1046+
1047+ All datasets can be exported as .txt tables.
1048+ 'Mappable' datasets (with r_number column) can be exporeted as .pml pymol script, which colors protein structures
1049+ based on their 'color' column.
1050+
1051+ """
1052+
10091053 header = "File Export"
10101054 target = param .Selector (label = 'Target dataset' , doc = 'Name of the dataset to export' )
10111055
@@ -1104,6 +1148,13 @@ def linear_export_callback(self):
11041148
11051149
11061150class ProteinViewControl (ControlPanel ):
1151+ """
1152+ This controller allows users control the Protein view figure.
1153+ Structures can be specified either by RCSB ID or uploading a .pdb file.
1154+
1155+ Colors are assigned according to 'color' column of the selected dataset.
1156+ """
1157+
11071158 header = 'Protein Viewer'
11081159 accepted_tags = ['mapping' ]
11091160
@@ -1151,17 +1202,18 @@ def _update_input_option(self):
11511202
11521203
11531204class OptionsControl (ControlPanel ):
1154- header = 'Options'
1205+ """The controller is used for various settings."""
11551206
1156- """panel for various options and settings"""
1207+ header = 'Options'
11571208
11581209 #todo this should be a component (mixin?) for apps who dont have these figures
1159- link_xrange = param .Boolean (False , doc = 'Link the X range of the coverage figure and other linear mapping figures.' )
1210+ link_xrange = param .Boolean (True , doc = 'Link the X range of the coverage figure and other linear mapping figures.' )
11601211 log_level = param .Selector (default = 'DEBUG' , objects = ['DEBUG' , 'INFO' , 'WARN' , 'ERROR' , 'FATAL' , 'OFF' , 'TRACE' ],
11611212 doc = 'Set the logging level.' )
11621213
11631214 def __init__ (self , parent , ** param ):
11641215 super (OptionsControl , self ).__init__ (parent , ** param )
1216+ self ._update_link ()
11651217
11661218 @property
11671219 def enabled (self ):
@@ -1203,6 +1255,8 @@ def _link(self):
12031255
12041256
12051257class DeveloperControl (ControlPanel ):
1258+ """Controller with debugging options"""
1259+
12061260 header = 'Developer Options'
12071261 test_logging = param .Action (lambda self : self ._action_test_logging ())
12081262 breakpoint_btn = param .Action (lambda self : self ._action_break ())
0 commit comments