2 * K-means cluster analysis and vizualization
3 * Isaak Y Tecle <iyt2@cornell.edu>
8 var solGS = solGS || function solGS () {};
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;
20 var popDetails = solGS. getPopulationDetails();
22 var comboPopsId = jQuery('#combo_pops_id').val();
24 var trainingTraitsIds = jQuery('#training_traits_ids').val();
25 if (trainingTraitsIds) {
26 trainingTraitsIds = trainingTraitsIds.split(',');
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,
40 url: '/cluster/check/result/',
41 success: function(res) {
44 solGS.cluster.plotClusterOutput(res);
45 jQuery("#cluster_message").empty();
46 jQuery("#run_cluster").hide();
49 jQuery("#run_cluster").show();
58 loadClusterGenotypesList: function(selectId, selectName, dataStr) {
60 if ( selectId.length === 0) {
61 alert('The list is empty. Please select a list with content.' );
64 var tableId = "list_cluster_populations_table";
65 var clusterTable = jQuery('#' + tableId).doesExist();
67 if (clusterTable == false) {
68 clusterTable = this.getClusterPopsTable(tableId);
69 jQuery("#list_cluster_populations").append(clusterTable).show();
72 var addRow = this.selectRow(selectId, selectName, dataStr);
73 var tdId = '#list_cluster_page_' + selectId;
74 var addedRow = jQuery(tdId).doesExist();
76 if (addedRow == false) {
77 jQuery('#' + tableId + ' tr:last').after(addRow);
83 selectRowId: function (selectId) {
85 var rowId = 'cluster_row_select_' + selectId;
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>'
95 return clusterTypeGroup;
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++) {
104 dataTypeGroup += '<option value="'
109 dataTypeGroup += '</select>';
111 return dataTypeGroup;
115 selectRow: function(selectId, selectName, dataStr) {
117 var rowId = this.selectRowId(selectId);
118 var clusterTypeOpts = this.createClusterTypeSelect();
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\/';
130 if (url.match(pagesTr)) {
131 dataTypeOpts = ['Genotype', 'Phenotype'];
132 } else if (url.match(pagesMultiModels)) {
133 dataTypeOpts = ['Genotype', 'GEBV', 'Phenotype'];
136 var dataTypeOpts= this.createDataTypeSelect(dataTypeOpts);
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;">';
145 var row = '<tr name="' + dataStr + '"' + ' id="' + rowId + '">'
148 + selectName + '</a>'
150 + '<td>' + dataStr + '</td>'
151 + '<td>' + clusterTypeOpts + '</td>'
152 + '<td>' + dataTypeOpts + '</td>'
153 + '<td>' + kNum + '</td>'
154 + '<td id="list_cluster_page_' + selectId + '">'
156 + '[ Run Cluster ] </a>'
164 createTable: function(tableId) {
166 var table ='<table class="table table-striped" id="' + tableId + '">'
170 + '<th>Data Structure</th>'
171 + '<th>Cluster type</th>'
172 + '<th>Data type</th>'
173 + '<th>No. of Clusters</th>'
176 + '</thead></table>';
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(',');
198 var popDetails = solGS.getPopulationDetails();
199 if (popDetails == undefined) {
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();
208 selectName = popName;
217 'data_structure': dataStr,
218 'data_type': dataType,
219 'selection_proportion': selectionProp,
223 var message = this.validateClusterParams(validateArgs);
225 if (message != undefined) {
227 jQuery("#cluster_message").html(message)
228 .show().fadeOut(9400);
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;
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;
254 if (dataStr == 'list') {
255 if (isNaN(selectId)) {
256 listId = selectId.replace('list_', '');
262 clusterPopId = 'list_' + listId;
264 } else if (dataStr == 'dataset') {
266 if (isNaN(selectId)) {
267 datasetId = selectId.replace('dataset_', '');
269 datasetId = selectId;
272 clusterPopId = 'dataset_' + datasetId;
273 datasetName = selectName;
275 clusterPopId = selectId || popId;
278 // if (!clusterPopId) {
279 // clusterPopId = popId;
282 if (popType == 'selection_index') {
283 sIndexName = selectName;
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,
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
302 this.runClusterAnalysis(clusterArgs);
307 runClusterAnalysis: function(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")
316 jQuery("#run_cluster").hide();
322 url: '/cluster/result',
323 success: function(res) {
324 if (res.result == 'success') {
325 jQuery("#cluster_canvas .multi-spinner-container").hide();
327 solGS.cluster.plotClusterOutput(res);
329 jQuery("#cluster_message").empty();
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/';
337 if (document.URL.match(pages)) {
338 jQuery("#run_cluster").show();
342 jQuery("#cluster_message").html(res.result);
343 jQuery("#cluster_canvas .multi-spinner-container").hide();
344 jQuery("#run_cluster").show();
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();
354 jQuery("#cluster_message").html('Missing cluster parameters.')
355 .show().fadeOut(8400);
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;
370 if (popType == 'selection_index') {
372 if (dataType.match(/genotype/i) == null) {
373 msg = 'K-means clustering for selection index type'
374 + ' data works with genotype data only.';
377 if (dataType.match(/genotype/i) != null
380 msg = 'The selection proportion value is empty.'
381 + ' You need to define the fraction of the'
382 +' population you want to select.';
387 if (dataStr == 'list') {
388 var list = new CXGN.List();
391 dataId= dataId.replace(/list_/, '');
394 var listType = list.getListType(dataId);
396 if (listType == 'accessions'
397 && dataType.match(/phenotype/i)) {
398 msg = 'With list of clones, you can only cluster based on <em>genotype</em>.';
401 if (listType == 'plots'
402 && dataType.match(/genotype/i)) {
403 msg = 'With list of plots, you can only cluster based on <em>phenotype</em>.';
411 plotClusterOutput: function(res) {
413 var resultName = res.result_name;
416 if (resultName != undefined) {
417 plotId = resultName.replace(/\s/g, '-');
419 plotId = res.cluster_pop_id;
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;
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=\""
437 + plotType + "]</a>";
439 var clustersFile = res.clusters;
440 var fileClusters = clustersFile.split('/').pop();
442 var clustersLink = "<a href=\""
448 var reportFile = res.cluster_report;
449 var report = reportFile.split('/').pop();
451 var reportLink = "<a href=\""
455 + ">[Analysis Report]</a>";
457 var downloadLinks = ' <strong>Download '
458 + resultName + ' </strong>: '
460 + clustersLink + ' | '
463 jQuery('#cluster_plot').prepend('<p>' + downloadLinks + '</p>');
464 jQuery('#cluster_plot').prepend(plot);
468 getClusterPopsTable: function(tableId) {
470 var clusterTable = this.createTable(tableId);
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,
489 this.clusterResult(clusterArgs);
492 registerClusterType: function(selectId) {
493 var analysisRowId = this.selectRowId(selectId);
494 var clusterType = jQuery('input[name=analysis_select]:checked', '#' + analysisRowId).val();
498 clusteringOptions: function(selectId) {
500 var url = document.URL;
501 if(url.match(/cluster\/analysis/)) {
502 selectId = this.selectRowId(selectId);
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, '');
514 return {'data_type' : dataType,
515 'cluster_type': clusterType,
517 'selection_proportion': selectionProp
522 getClusterGenotypesListData: function(listId) {
524 var list = new CXGN.List();
528 var listName = list.listNameById(listId);
529 var listType = list.getListType(listId);
531 return {'name' : listName,
532 'listType' : listType,
540 listClusterPopulations: function() {
541 var modelData = solGS.sIndex.getTrainingPopulationData();
543 var trainingPopIdName = JSON.stringify(modelData);
545 var popsList = '<dl id="cluster_selected_population" class="cluster_dropdown">'
546 + '<dt> <a href="#"><span>Choose a population</span></a></dt>'
549 + '<a href="#">' + modelData.name + '<span class=value>' + trainingPopIdName + '</span></a>'
553 jQuery("#cluster_select_a_population_div").empty().append(popsList).show();
556 if (modelData.id.match(/list/) == null) {
557 dbSelPopsList = solGS.sIndex.addSelectionPopulations();
561 jQuery("#cluster_select_a_population_div ul").append(dbSelPopsList);
564 var listTypeSelPops = jQuery("#list_type_selection_pops_table").length;
566 if (listTypeSelPops) {
567 var selPopsList = solGS.sIndex.getListTypeSelPopulations();
569 jQuery("#cluster_select_a_population_div ul").append(selPopsList);
573 var sIndexPops = solGS.sIndex.addIndexedClustering();
575 jQuery("#cluster_select_a_population_div ul").append(sIndexPops);
578 jQuery(".cluster_dropdown dt a").click(function() {
579 jQuery(".cluster_dropdown dd ul").toggle();
582 jQuery(".cluster_dropdown dd ul li a").click(function() {
584 var text = jQuery(this).html();
585 jQuery(".cluster_dropdown dt a span").html(text);
586 jQuery(".cluster_dropdown dd ul").hide();
588 var idPopName = jQuery("#cluster_selected_population").find("dt a span.value").html();
589 idPopName = JSON.parse(idPopName);
590 modelId = jQuery("#model_id").val();
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();
603 jQuery('#cluster_canvas #cluster_options #selection_proportion_div').hide();
608 jQuery(".cluster_dropdown").bind('click', function(e) {
609 var clicked = jQuery(e.target);
611 if (!clicked.parents().hasClass("cluster_dropdown"))
612 jQuery(".cluster_dropdown dd ul").hide();
620 // plotKCluster: function(plotData){
627 jQuery.fn.doesExist = function(){
629 return jQuery(this).length > 0;
634 jQuery(document).ready( function() {
636 var url = document.URL;
638 if (url.match(/cluster\/analysis/)) {
640 var list = new CXGN.List();
642 var listMenu = list.listSelect("cluster_genotypes", ['accessions','plots', 'trials'], undefined, undefined, undefined);
644 var dType = ['accessions', 'trials'];
646 var dMenu = solGS.dataset.getDatasetsMenu(dType);
648 if (listMenu.match(/option/) != null) {
649 jQuery("#cluster_genotypes_list").append(listMenu);
650 jQuery("#cluster_genotypes_list_select").append(dMenu);
652 jQuery("#cluster_genotypes_list").append("<select><option>no lists found - Log in</option></select>");
659 jQuery(document).ready( function() {
661 var url = document.URL;
663 if (url.match(/cluster\/analysis/)) {
665 jQuery("<option>", {value: '', selected: true}).prependTo("#cluster_genotypes_list_select");
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) {
677 jQuery("#cluster_go_btn").click(function() {
678 solGS.cluster.loadClusterGenotypesList(selectId, selectName, dataStr);
683 //checkClusterResult();
688 jQuery(document).ready( function() {
690 jQuery("#run_cluster").click(function() {
691 var dataStr = jQuery('#data_structure').val();
694 if (dataStr == 'dataset') {
695 selectId = jQuery('#dataset_id').val();
696 } else if (dataStr == 'list') {
697 selectId = jQuery('#list_id').val();
701 var popType = jQuery("#cluster_selected_population_type").val();
703 if (popType == 'list') {
705 } else if (popType == 'dataset') {
710 if (selectId == undefined) {
711 selectId = jQuery("#cluster_selected_population_id").val();
714 if (document.URL.match(/breeders\/trial\//)) {
715 selectId = jQuery("#trial_id").val();
716 selectName = jQuery("#trial_name").val();
719 if (selectName == undefined) {
720 selectName = jQuery("#cluster_selected_population_name").val();
723 var clusterOptsId = 'cluster_options';
724 var clusterOpts = solGS.cluster.clusteringOptions(clusterOptsId);
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
735 solGS.cluster.clusterResult(clusterArgs);
741 jQuery(document).ready( function() {
742 var page = document.URL;
744 if (page.match(/solgs\/traits\/all\/|solgs\/models\/combined\/trials\//) != null) {
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();
761 setTimeout(checkClusterPop, 6000);
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();
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();