filter special characters..
[sgn.git] / js / source / legacy / solGS / cluster.js
blob70dafde2fc9906e619ee43e96492341c0bbaccfa
1 /** 
2 * K-means cluster analysis and vizualization 
3 * Isaak Y Tecle <iyt2@cornell.edu>
5 */
8 var solGS = solGS || function solGS () {};
10 solGS.cluster = {
12     checkClusterResult: function() {
14         var listId = jQuery('#list_id').val();
16         var clusterOpts = solGS.cluster.clusteringOptions('cluster_options');
17         var clusterType = clusterOpts.cluster_type;
18         var dataType = clusterOpts.data_type;
19         
20         var popDetails = solGS. getPopulationDetails();
21         
22         var comboPopsId = jQuery('#combo_pops_id').val();
23         
24         var trainingTraitsIds = jQuery('#training_traits_ids').val();
25         if (trainingTraitsIds) {
26             trainingTraitsIds = trainingTraitsIds.split(',');
27         }
28         
29         jQuery.ajax({
30             type: 'POST',
31             dataType: 'json',
32             data: {'list_id': listId,
33                    'combo_pops_id': comboPopsId,
34                    'training_pop_id': popDetails.training_pop_id,
35                    'selection_pop_id': popDetails.selection_pop_id,
36                    'training_traits_ids': trainingTraitsIds,
37                    'cluster_type': clusterType,
38                    'data_type': dataType
39                   },
40             url: '/cluster/check/result/',
41             success: function(res) {
42                 if (res.result) {
43                    
44                     solGS.cluster.plotClusterOutput(res);                                   
45                     jQuery("#cluster_message").empty();             
46                     jQuery("#run_cluster").hide();
47                    
48                 } else {                    
49                     jQuery("#run_cluster").show();      
50                 }
51             },
52             
53         });
54         
55     },
57     
58     loadClusterGenotypesList: function(selectId, selectName, dataStr) {     
60         if ( selectId.length === 0) {       
61             alert('The list is empty. Please select a list with content.' );
62         } else {
63             
64             var tableId = "list_cluster_populations_table";
65             var clusterTable = jQuery('#' + tableId).doesExist();
66             
67             if (clusterTable == false) {
68                 clusterTable = this.getClusterPopsTable(tableId);
69                 jQuery("#list_cluster_populations").append(clusterTable).show();                
70             }
71                     
72             var addRow = this.selectRow(selectId, selectName, dataStr);
73             var tdId = '#list_cluster_page_' + selectId;
74             var addedRow = jQuery(tdId).doesExist();
75             
76             if (addedRow == false) {
77                 jQuery('#' + tableId + ' tr:last').after(addRow);
78             }                          
79                    
80         }
81     },
83     selectRowId: function (selectId) {
84         
85         var rowId = 'cluster_row_select_' + selectId;
86         return rowId;
87     },
89     createClusterTypeSelect: function() {
90         // + '<option value="heirarchical">Heirarchical</option>'
91         var clusterTypeGroup  = '<select class="form-control" id="cluster_type_select">'
92             + '<option value="k-means">K-Means</option>'                
93             +  '</select>';
95         return clusterTypeGroup;
96         
97     },
99     createDataTypeSelect: function(opts) {
100         var dataTypeGroup = '<select class="form-control" id="cluster_data_type_select">';
102         for (var i=0; i < opts.length; i++) {
103             
104             dataTypeGroup += '<option value="'
105                 + opts[i] + '">'
106                 + opts[i]
107                 + '</option>';
108         }
109           dataTypeGroup +=  '</select>';
110         
111         return dataTypeGroup;
112      },
113     
114     
115     selectRow: function(selectId, selectName, dataStr) {
117         var rowId = this.selectRowId(selectId);
118         var clusterTypeOpts = this.createClusterTypeSelect();
120         var dataTypeOpts;
121         var url = document.URL;
122         var pagesTr = '/breeders/trial/'
123             + '|cluster/analysis'
124             + '|solgs/trait/\d+/population\/' 
125             + '|solgs/model/combined/populations/';
127         var pagesMultiModels = '/solgs/traits/all/population/'
128             + '|solgs/models/combined/trials\/';
129         
130         if (url.match(pagesTr)) {
131             dataTypeOpts = ['Genotype', 'Phenotype'];
132         } else if (url.match(pagesMultiModels)) {
133             dataTypeOpts = ['Genotype', 'GEBV', 'Phenotype'];
134         }
135         
136         var dataTypeOpts=  this.createDataTypeSelect(dataTypeOpts);
137         
138         var kNum = '<input class="form-control" type="text" placeholder="No. of clusters?" id="k_number" />';
140         var onClickVal =  '<a href="#" onclick="solGS.cluster.runCluster('
141             + selectId + ",'" + selectName + "'" +  ",'" + dataStr
142             + "'" + ');return false;">';
144         
145         var row = '<tr name="' + dataStr + '"' + ' id="' + rowId +  '">'
146             + '<td>'
147             + onClickVal
148             + selectName + '</a>'
149             + '</td>'
150             + '<td>' + dataStr + '</td>'
151             + '<td>' + clusterTypeOpts + '</td>'
152             + '<td>' + dataTypeOpts + '</td>'
153             + '<td>' + kNum + '</td>'
154             + '<td id="list_cluster_page_' + selectId +  '">'
155             + onClickVal
156             + '[ Run Cluster ] </a>'                                     
157             + '</td>'
158             + '<tr>';
159         
160         return row;
161     },
164     createTable: function(tableId) {
166         var table ='<table class="table table-striped" id="' + tableId + '">'
167             + '<thead>'
168             + '<tr>'
169             + '<th>Name</th>'
170             + '<th>Data Structure</th>'
171             + '<th>Cluster type</th>'
172             + '<th>Data type</th>'
173             + '<th>No. of  Clusters</th>'
174             + '<th>Run</th>'
175             + '</tr>'
176             + '</thead></table>';
178         return table;
179         
180     },
182     clusterResult: function(clusterArgs) {
184         var clusterType = clusterArgs.cluster_type;
185         var kNumber     = clusterArgs.k_number;
186         var dataType    = clusterArgs.data_type;
187         var selectionProp = clusterArgs.selection_proportion;
188         var selectId     = clusterArgs.select_id;
189         var selectName    = clusterArgs.select_name;
190         var dataStr      = clusterArgs.data_structure;
192         var trainingTraitsIds = jQuery('#training_traits_ids').val();
194         if (trainingTraitsIds) {
195             trainingTraitsIds = trainingTraitsIds.split(',');
196         }
197         
198         var popDetails  = solGS.getPopulationDetails();
199         if (popDetails == undefined) {
200             popDetails = {};
201         }
202         
203         var popId   = jQuery("#cluster_selected_population_id").val();
204         var popType = jQuery("#cluster_selected_population_type").val();
205         var popName = jQuery("#cluster_selected_population_name").val();
206         
207         if(!selectName) {
208             selectName = popName;
209         }
211         if (!selectId) {
212             selectId = popId;
213         }
215         var validateArgs =  {
216             'data_id': selectId,
217             'data_structure': dataStr,
218             'data_type': dataType,
219             'selection_proportion': selectionProp,
220             'pop_type': popType
221         };
223         var message = this.validateClusterParams(validateArgs);
225         if (message != undefined) {
226             
227             jQuery("#cluster_message").html(message)
228                 .show().fadeOut(9400);
229             
230         } else {
231         
232             if (document.URL.match(/solgs\/traits\/all\/population\//)) {
233                 if (popType.match(/training/)) {
234                     popDetails['training_pop_id'] = popId;      
235                 } else if (popType.match(/selection/)) {
236                     popDetails['selection_pop_id'] = popId;
237                 }
238             }
240             if (document.URL.match(/solgs\/models\/combined\/trials\//)) {
241                 if (popType.match(/training/)) {
242                     popDetails['combo_pops_id'] = popId;
243                 } else if (popType.match(/selection/)) {
244                     popDetails['selection_pop_id'] = popId;
245                 }           
246             }
247                     
248             var listId;
249             var datasetId;
250             var datasetName;
251             var sIndexName;
252             var clusterPopId;
253             
254             if (dataStr == 'list') {       
255                 if (isNaN(selectId)) {
256                     listId = selectId.replace('list_', '');
257                            
258                 } else {
259                     listId = selectId;  
260                 }
261                 
262                 clusterPopId = 'list_' + listId;
263                 
264             } else if (dataStr == 'dataset') {
266                 if (isNaN(selectId)) {
267                      datasetId = selectId.replace('dataset_', '');                         
268                 } else {
269                      datasetId = selectId;      
270                 }
271                 
272                 clusterPopId = 'dataset_' + datasetId;
273                 datasetName = selectName;
274             } else {
275                 clusterPopId = selectId || popId;
276             }
278             // if (!clusterPopId) {
279             //  clusterPopId = popId;
280             // }
281                     
282             if (popType == 'selection_index') {
283                 sIndexName = selectName;
284             }
286             var clusterArgs =  {'training_pop_id': popDetails.training_pop_id,
287                                 'selection_pop_id': popDetails.selection_pop_id,
288                                 'combo_pops_id': popDetails.combo_pops_id,
289                                 'training_traits_ids': trainingTraitsIds,
290                                 'cluster_pop_id': clusterPopId,
291                                 'list_id': listId, 
292                                 'cluster_type': clusterType,
293                                 'data_structure': dataStr,
294                                 'dataset_id': datasetId,
295                                 'dataset_name': datasetName,
296                                 'data_type': dataType,
297                                 'k_number' : kNumber,
298                                 'selection_proportion': selectionProp,
299                                 'sindex_name': sIndexName
300                                };
301             
302             this.runClusterAnalysis(clusterArgs);
303         }
304             
305     },
307     runClusterAnalysis: function(clusterArgs) {
309         if (clusterArgs) {
311             jQuery("#cluster_canvas .multi-spinner-container").show();
312             jQuery("#cluster_message")
313                 .html("Running K-means clustering... please wait...it may take minutes")
314                 .show();
315                 
316             jQuery("#run_cluster").hide();
317             
318             jQuery.ajax({
319                 type: 'POST',
320                 dataType: 'json',
321                 data: clusterArgs,
322                 url: '/cluster/result',
323                 success: function(res) {
324                     if (res.result == 'success') {
325                         jQuery("#cluster_canvas .multi-spinner-container").hide();
326                         
327                         solGS.cluster.plotClusterOutput(res);
328                         
329                         jQuery("#cluster_message").empty();
330                         
331                         var pages = '/solgs/traits/all/population/'
332                             + '|solgs/models/combined/trials/'
333                             + '|/breeders/trial\/'
334                             + '|solgs/trait/\\d+/population/'
335                             + '|solgs/model/combined/populations/';
336                         
337                         if (document.URL.match(pages)) {
338                             jQuery("#run_cluster").show();
339                         }
341                     } else {                
342                         jQuery("#cluster_message").html(res.result);
343                         jQuery("#cluster_canvas .multi-spinner-container").hide();
344                         jQuery("#run_cluster").show();              
345                     }
346                 },
347                 error: function(res) {
348                     jQuery("#cluster_message").html('Error occured running the clustering.');
349                     jQuery("#cluster_canvas .multi-spinner-container").hide();
350                     jQuery("#run_cluster").show();
351                 }  
352             });
353         } else {
354             jQuery("#cluster_message").html('Missing cluster parameters.')
355                 .show().fadeOut(8400); 
356         }
357         
358     },  
360     validateClusterParams: function(valArgs) {
362         var popType  = valArgs.pop_type;
363         var dataType = valArgs.data_type;
364         var selectionProp = valArgs.selection_proportion;
365         var dataStr = valArgs.data_structure;
366         var dataId = valArgs.data_id;
367         
368         var msg;
369         
370         if (popType == 'selection_index') {
371           
372             if (dataType.match(/genotype/i) == null) {
373                 msg = 'K-means clustering for selection index type'
374                     + ' data works with genotype data only.';   
375             } 
377             if (dataType.match(/genotype/i) != null
378                 && !selectionProp) {
379                 
380                 msg = 'The selection proportion value is empty.'
381                     + ' You need to define the fraction of the'
382                     +' population you want to select.';
383             }
385         }
387         if (dataStr == 'list') {
388             var list = new CXGN.List();
389            
390             if (isNaN(dataId)) {
391                 dataId= dataId.replace(/list_/, '');
392             }
393           
394             var listType = list.getListType(dataId);
395            
396             if (listType == 'accessions'
397                 && dataType.match(/phenotype/i)) {
398                 msg = 'With list of clones, you can only cluster based on <em>genotype</em>.';          
399             }
400             
401             if (listType == 'plots'
402                 && dataType.match(/genotype/i)) {
403                 msg = 'With list of plots, you can only cluster based on <em>phenotype</em>.';          
404             }
405             
406         }
408         return msg;
409     },
411     plotClusterOutput: function(res) {
413         var resultName = res.result_name; 
414         var plotId;
416         if (resultName != undefined) {
417              plotId = resultName.replace(/\s/g, '-');
418         } else {
419             plotId = res.cluster_pop_id;
420         }
421         
422         var imageId = 'k-means-plot-'  + plotId + '-'
423             + res.data_type + '-'+ res.k_number;
425         if (res.selection_proportion) {
426             imageId = imageId + '-' + res.selection_proportion;
427         }
428         
429         imageId = 'id="' + imageId + '"';       
430         var plot = '<img '+ imageId + ' src="' + res.kcluster_plot + '">';
431         var filePlot  = res.kcluster_plot.split('/').pop();
432         var plotType = 'K-means plot';  
433         var plotLink = "<a href=\""
434             + res.kcluster_plot
435             +  "\" download="
436             + filePlot + ">["
437             + plotType +  "]</a>";
438         
439         var clustersFile = res.clusters;
440         var fileClusters  = clustersFile.split('/').pop();
441                     
442         var clustersLink = "<a href=\""
443             + clustersFile
444             +  "\" download="
445             + fileClusters
446             + ">[Clusters]</a>";
448         var reportFile = res.cluster_report;
449         var report  = reportFile.split('/').pop();
450         
451         var reportLink = "<a href=\""
452             + reportFile
453             +  "\" download="
454             + report
455             + ">[Analysis Report]</a>";
457         var downloadLinks = ' <strong>Download '
458             + resultName + ' </strong>: '
459             + plotLink + ' | '
460             + clustersLink + ' | '
461             + reportLink;
462         
463         jQuery('#cluster_plot').prepend('<p>' + downloadLinks + '</p>');
464         jQuery('#cluster_plot').prepend(plot);
465         
466     },
468     getClusterPopsTable: function(tableId) {
470         var clusterTable  = this.createTable(tableId);
471         return clusterTable;
472     },
474     runCluster: function(selectId, selectName, dataStr) {
476         var clusterOpts = solGS.cluster.clusteringOptions(selectId);
477         var clusterType = clusterOpts.cluster_type;
478         var kNumber     = clusterOpts.k_number;
479         var dataType    = clusterOpts.data_type;
481         var clusterArgs = { 'select_id': selectId,
482                             'select_name': selectName,
483                             'data_structure':  dataStr,
484                             'cluster_type':  clusterType,
485                             'data_type': dataType,
486                             'k_number':  kNumber            
487                           }
489         this.clusterResult(clusterArgs);
490     },
492     registerClusterType: function(selectId) {
493         var analysisRowId = this.selectRowId(selectId);
494         var clusterType = jQuery('input[name=analysis_select]:checked', '#' + analysisRowId).val();
495         return clusterType;
496     },
498     clusteringOptions: function(selectId) {
500         var url = document.URL;
501         if(url.match(/cluster\/analysis/)) {
502             selectId = this.selectRowId(selectId);
503         }
504         
505         var dataType    = jQuery('#'+selectId + ' #cluster_data_type_select').val();
506         var clusterType = jQuery('#'+selectId + ' #cluster_type_select').val();
507         var kNumber     = jQuery('#'+selectId + ' #k_number').val();
508         var selectionProp = jQuery('#'+selectId + ' #selection_proportion').val()
510         selectionProp = selectionProp.replace(/%/, '');
511         selectionProp = selectionProp.replace(/\s+/g, '');
512         kNumber = kNumber.replace(/\s+/g, '');
513         
514         return {'data_type' : dataType,
515                 'cluster_type': clusterType,
516                 'k_number': kNumber,
517                 'selection_proportion': selectionProp
518                };
519         
520     },
522     getClusterGenotypesListData: function(listId) {   
523         
524         var list = new CXGN.List();
526         if (listId) {
527            
528             var listName = list.listNameById(listId);
529             var listType = list.getListType(listId);
530             
531             return {'name'     : listName,
532                     'listType' : listType,
533                    };
534         } else {
535             return;
536         }       
537     },
540     listClusterPopulations: function()  {
541         var modelData = solGS.sIndex.getTrainingPopulationData();
542         
543         var trainingPopIdName = JSON.stringify(modelData);
544         
545         var  popsList =  '<dl id="cluster_selected_population" class="cluster_dropdown">'
546             + '<dt> <a href="#"><span>Choose a population</span></a></dt>'
547             + '<dd><ul>'
548             + '<li>'
549             + '<a href="#">' + modelData.name + '<span class=value>' + trainingPopIdName + '</span></a>'
550             + '</li>'
551             + '</ul></dd></dl>'; 
552         
553         jQuery("#cluster_select_a_population_div").empty().append(popsList).show();
554         
555         var dbSelPopsList;
556         if (modelData.id.match(/list/) == null) {
557             dbSelPopsList = solGS.sIndex.addSelectionPopulations();
558         }
560         if (dbSelPopsList) {
561             jQuery("#cluster_select_a_population_div ul").append(dbSelPopsList); 
562         }
563         
564         var listTypeSelPops = jQuery("#list_type_selection_pops_table").length;
566         if (listTypeSelPops) {
567             var selPopsList = solGS.sIndex.getListTypeSelPopulations();
568             if (selPopsList) {
569                 jQuery("#cluster_select_a_population_div ul").append(selPopsList);  
570             }
571         }
573         var sIndexPops = solGS.sIndex.addIndexedClustering();
574         if (sIndexPops) {
575             jQuery("#cluster_select_a_population_div ul").append(sIndexPops);  
576         }
577         
578         jQuery(".cluster_dropdown dt a").click(function() {
579             jQuery(".cluster_dropdown dd ul").toggle();
580         });
581       
582         jQuery(".cluster_dropdown dd ul li a").click(function() {
583            
584             var text = jQuery(this).html();
585             jQuery(".cluster_dropdown dt a span").html(text);
586             jQuery(".cluster_dropdown dd ul").hide();
587             
588             var idPopName = jQuery("#cluster_selected_population").find("dt a span.value").html();
589             idPopName     = JSON.parse(idPopName);
590             modelId       = jQuery("#model_id").val();
591        
592             var selectedPopId   = idPopName.id;
593             var selectedPopName = idPopName.name;
594             var selectedPopType = idPopName.pop_type; 
596             jQuery("#cluster_selected_population_name").val(selectedPopName);
597             jQuery("#cluster_selected_population_id").val(selectedPopId);
598             jQuery("#cluster_selected_population_type").val(selectedPopType);
600             if (selectedPopType.match(/selection_index/)) {
601                 jQuery('#cluster_canvas #cluster_options #selection_proportion_div').show();
602             } else {
603                 jQuery('#cluster_canvas #cluster_options #selection_proportion_div').hide();    
604             }
605             
606         });
607         
608         jQuery(".cluster_dropdown").bind('click', function(e) {
609             var clicked = jQuery(e.target);
610             
611             if (!clicked.parents().hasClass("cluster_dropdown")) 
612                 jQuery(".cluster_dropdown dd ul").hide();
614             e.preventDefault();
616         });           
617     },
619    
620     // plotKCluster: function(plotData){
622     // },
627 jQuery.fn.doesExist = function(){
629         return jQuery(this).length > 0;
631  };
633     
634 jQuery(document).ready( function() {
635     
636     var url = document.URL;
638     if (url.match(/cluster\/analysis/)) {
639     
640         var list = new CXGN.List();
641         
642         var listMenu = list.listSelect("cluster_genotypes", ['accessions','plots', 'trials'], undefined, undefined, undefined);
644         var dType = ['accessions', 'trials'];
645         
646         var dMenu = solGS.dataset.getDatasetsMenu(dType);
647         
648         if (listMenu.match(/option/) != null) {         
649             jQuery("#cluster_genotypes_list").append(listMenu);
650             jQuery("#cluster_genotypes_list_select").append(dMenu);
651         } else {            
652             jQuery("#cluster_genotypes_list").append("<select><option>no lists found - Log in</option></select>");
653         }
654     }
655                
659 jQuery(document).ready( function() { 
660      
661     var url = document.URL;
662     
663     if (url.match(/cluster\/analysis/)) {  
664         
665         jQuery("<option>", {value: '', selected: true}).prependTo("#cluster_genotypes_list_select");
666      
667         jQuery("#cluster_genotypes_list_select").change(function() {        
668             var selectId = jQuery(this).find("option:selected").val();
669             var selectName = jQuery(this).find("option:selected").text();
670             var dataStr  = jQuery(this).find("option:selected").attr('name');
672             if (dataStr == undefined) {
673                 dataStr = 'list';
674             } 
675             
676             if (selectId) {                
677                 jQuery("#cluster_go_btn").click(function() {
678                     solGS.cluster.loadClusterGenotypesList(selectId, selectName, dataStr);
679                 });
680             }
681         });
683         //checkClusterResult();
684     }      
688 jQuery(document).ready( function() { 
690     jQuery("#run_cluster").click(function() {
691         var dataStr = jQuery('#data_structure').val();
692         var selectId;
693         var selectName; 
694         if (dataStr == 'dataset') {
695             selectId = jQuery('#dataset_id').val();
696         } else if (dataStr == 'list') {
697              selectId = jQuery('#list_id').val();
698         }
700         if (!dataStr) {
701             var popType = jQuery("#cluster_selected_population_type").val();
702          
703             if (popType == 'list') {
704                 dataStr = 'list';
705             } else if (popType == 'dataset') {
706                 dataStr = 'dataset';
707             }
708         }
710         if (selectId == undefined) {
711             selectId = jQuery("#cluster_selected_population_id").val(); 
712         }
714         if (document.URL.match(/breeders\/trial\//)) {
715             selectId = jQuery("#trial_id").val();
716             selectName = jQuery("#trial_name").val();
717         }
719         if (selectName == undefined) {
720             selectName = jQuery("#cluster_selected_population_name").val(); 
721         }
722         
723         var clusterOptsId = 'cluster_options';
724         var clusterOpts = solGS.cluster.clusteringOptions(clusterOptsId);
725         
726         var clusterArgs = { 'select_id': selectId,
727                             'select_name': selectName,
728                             'data_structure':  dataStr,
729                             'cluster_type':  clusterOpts.cluster_type,
730                             'data_type': clusterOpts.data_type,
731                             'k_number': clusterOpts.k_number,                       
732                             'selection_proportion': clusterOpts.selection_proportion
733                           };
734         
735         solGS.cluster.clusterResult(clusterArgs);
736     }); 
737   
741 jQuery(document).ready( function() { 
742     var page = document.URL;
743   
744     if (page.match(/solgs\/traits\/all\/|solgs\/models\/combined\/trials\//) != null) {
745         
746         setTimeout(function() {solGS.cluster.listClusterPopulations()}, 5000);
748         var dataTypeOpts = ['Genotype', 'GEBV', 'Phenotype'];   
749         dataTypeOpts =   solGS.cluster.createDataTypeSelect(dataTypeOpts);
751         var clusterTypeOpts =   solGS.cluster.createClusterTypeSelect();
753         jQuery(document).ready(checkClusterPop);
755         function checkClusterPop() {
756             if(jQuery('#cluster_canvas #cluster_select_a_population_div').is(':visible')) {
757                 jQuery('#cluster_canvas #cluster_options #cluster_data_type_opts').html(dataTypeOpts);
758                 jQuery('#cluster_canvas #cluster_options #cluster_type_opts').html(clusterTypeOpts);
759                 jQuery('#cluster_canvas #cluster_options').show();
760             } else {
761                 setTimeout(checkClusterPop, 6000);
762             }
763         } 
764                                                                 
765     } else if (page.match(/breeders\/trial\/|solgs\/trait\/\d+\/population\/|solgs\/model\/combined\/populations\//)) {
767         var dataTypeOpts = ['Genotype', 'Phenotype'];
768         dataTypeOpts =   solGS.cluster.createDataTypeSelect(dataTypeOpts);
769         var clusterTypeOpts =   solGS.cluster.createClusterTypeSelect();
770         
771         jQuery('#cluster_canvas #cluster_options #cluster_data_type_opts').html(dataTypeOpts);
772         jQuery('#cluster_canvas #cluster_options #cluster_type_opts').html(clusterTypeOpts);
773         jQuery("#cluster_canvas #cluster_options").show();
774         
775     }