Skip to content

Commit 150ee19

Browse files
authored
Merge pull request #349 from lenatr99/cluster_analysis_bugfix
Cluster analysis: Fix bugs and use of Gene Selection Component
2 parents d78ea79 + 8d6aad8 commit 150ee19

File tree

2 files changed

+96
-96
lines changed

2 files changed

+96
-96
lines changed

orangecontrib/bioinformatics/widgets/OWClusterAnalysis.py

+94-95
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
""" OWClusterAnalysis """
2+
23
import sys
34
import itertools
45

@@ -36,7 +37,7 @@
3637
)
3738
from Orange.widgets.utils.signals import Input, Output
3839

39-
from orangecontrib.bioinformatics.geneset.utils import GeneSetException
40+
from orangecontrib.bioinformatics.geneset import GeneSets
4041
from orangecontrib.bioinformatics.cluster_analysis import (
4142
DISPLAY_GENE_SETS_COUNT,
4243
Cluster,
@@ -47,8 +48,8 @@
4748
from orangecontrib.bioinformatics.widgets.utils.gui import (
4849
HTMLDelegate,
4950
GeneScoringWidget,
50-
GeneSetsSelection,
5151
)
52+
from orangecontrib.bioinformatics.widgets.components import GeneSetSelection
5253
from orangecontrib.bioinformatics.widgets.utils.data import (
5354
TAX_ID,
5455
GENE_ID_COLUMN,
@@ -58,16 +59,16 @@
5859

5960

6061
class ClusterAnalysisContextHandler(PerfectDomainContextHandler):
61-
def encode_setting(self, context, setting, value):
62+
def encode_setting(self, context, setting, value, *args):
6263
if setting.name == 'cluster_indicators':
6364
value = [(var.name, 100 + vartype(var)) for var in value]
64-
return super().encode_setting(context, setting, value)
65+
return super().encode_setting(context, setting, value, *args)
6566

66-
def decode_setting(self, setting, value, domain=None):
67+
def decode_setting(self, setting, value, domain=None, *args):
6768
return (
6869
[domain[var[0]] for var in value]
6970
if setting.name == 'cluster_indicators'
70-
else super().decode_setting(setting, value, domain)
71+
else super().decode_setting(setting, value, domain, *args)
7172
)
7273

7374

@@ -107,6 +108,9 @@ class Error(OWWidget.Error):
107108
'Organism in input data and custom gene sets does not match'
108109
)
109110
cluster_batch_conflict = Msg('Cluster and batch must not be the same variable')
111+
custom_gene_sets_table_format = Msg(
112+
'Custom gene sets data must have genes represented as rows.'
113+
)
110114

111115
settingsHandler = ClusterAnalysisContextHandler()
112116
cluster_indicators = ContextSetting([])
@@ -215,31 +219,14 @@ def __init__(self):
215219
self.gene_scoring.set_method_design_area('scoring_method_design')
216220
self.gene_scoring.set_test_type('scoring_test_type')
217221

218-
# Gene Sets widget
219-
gene_sets_box = widgetBox(self.controlArea, "Gene Sets")
220-
self.gs_widget = GeneSetsSelection(
221-
gene_sets_box, self, 'stored_gene_sets_selection'
222+
box = vBox(self.controlArea, True, margin=0)
223+
self.gs_selection_component: GeneSetSelection = GeneSetSelection(self, box)
224+
self.gs_selection_component.selection_changed.connect(
225+
self._on_selection_changed
222226
)
223-
self.gs_widget.hierarchy_tree_widget.itemClicked.connect(
224-
self.__gene_sets_enrichment
225-
)
226-
227-
# custom gene sets area
228-
box = vBox(self.controlArea, "Custom Gene Sets")
229-
230-
if self.custom_gene_set_indicator not in self.feature_model:
231-
self.custom_gene_set_indicator = None
232-
233-
self.gs_label_combobox = comboBox(
234-
box,
235-
self,
236-
"custom_gene_set_indicator",
237-
sendSelectedValue=True,
238-
model=self.feature_model,
239-
callback=self.handle_custom_gene_sets,
240-
)
241-
self.gs_label_combobox.setDisabled(True)
242-
227+
self.gs_selection_component.sample_column_combo.hide()
228+
self.gs_selection_component.sample_column_combo.parent().hide()
229+
self.gs_selection_component._update_tree_widget()
243230
# main area
244231
splitter = QSplitter(Qt.Horizontal, self.mainArea)
245232
self.mainArea.layout().addWidget(splitter)
@@ -386,7 +373,7 @@ def __create_temp_class_var(self):
386373
row_profile = None
387374
new_cluster_values = []
388375
var_index_lookup = {
389-
val: idx
376+
(var.name, str(val)): idx
390377
for var in self.cluster_indicators
391378
for idx, val in enumerate(var.values)
392379
}
@@ -396,7 +383,12 @@ def __create_temp_class_var(self):
396383
)
397384
for comb in cart_prod:
398385
new_cluster_values.append(', '.join(list(comb)))
399-
self.new_cluster_profile.append([var_index_lookup[val] for val in comb])
386+
self.new_cluster_profile.append(
387+
[
388+
var_index_lookup[(var.name, str(val))]
389+
for var, val in zip(self.cluster_indicators, comb)
390+
]
391+
)
400392

401393
row_profile_lookup = {
402394
tuple(profile): indx
@@ -418,13 +410,15 @@ def __create_temp_class_var(self):
418410
ca_ind = DiscreteVariable.make(
419411
cluster_indicator_name,
420412
values=list(new_cluster_values),
421-
ordered=True,
422413
)
423-
424414
domain = Domain(
425415
self.input_data.domain.attributes,
426416
self.input_data.domain.class_vars,
427-
self.input_data.domain.metas + (ca_ind,),
417+
(
418+
self.input_data.domain.metas[:-1] + (ca_ind,)
419+
if ca_ind in self.input_data.domain
420+
else self.input_data.domain.metas + (ca_ind,)
421+
),
428422
)
429423

430424
table = self.input_data.transform(domain)
@@ -512,6 +506,8 @@ def filter_gene_sets(self):
512506
# call sizeHint function
513507
self.cluster_info_view.resizeRowsToContents()
514508

509+
self.commit()
510+
515511
def __gene_enrichment(self):
516512
design = bool(
517513
self.gene_scoring.get_selected_desig()
@@ -538,8 +534,8 @@ def __gene_enrichment(self):
538534
def __gene_sets_enrichment(self):
539535
if self.input_data:
540536
self.Warning.no_selected_gene_sets.clear()
541-
all_sets = self.gs_widget.get_hierarchies()
542-
selected_sets = self.gs_widget.get_hierarchies(only_selected=True)
537+
selected_sets = self.gs_selection_component.selection
538+
all_sets = self.gs_selection_component.gene_sets.hierarchies()
543539

544540
if len(selected_sets) == 0 and len(all_sets) > 0:
545541
self.Warning.no_selected_gene_sets()
@@ -550,7 +546,7 @@ def __gene_sets_enrichment(self):
550546

551547
try:
552548
self.cluster_info_model.gene_sets_enrichment(
553-
self.gs_widget.gs_object, selected_sets, ref_genes
549+
self.gs_selection_component.gene_sets, selected_sets, ref_genes
554550
)
555551
except Exception as e:
556552
# TODO: possible exceptions?
@@ -580,6 +576,34 @@ def invalidate(self, cluster_init=True):
580576
def batch_indicator_changed(self):
581577
self.invalidate(cluster_init=False)
582578

579+
def _on_selection_changed(self):
580+
if not self.input_data or not self.gs_selection_component:
581+
return
582+
self.num_of_custom_sets = self.gs_selection_component.num_of_custom_sets
583+
584+
selected_sets = self.gs_selection_component.selection
585+
all_sets = self.gs_selection_component.gene_sets.hierarchies()
586+
587+
self.Warning.no_selected_gene_sets.clear()
588+
if not selected_sets and all_sets:
589+
self.Warning.no_selected_gene_sets()
590+
591+
self.stored_gene_sets_selection = tuple(selected_sets)
592+
ref_genes = set(self.input_genes_ids)
593+
594+
if not self.cluster_info_model or len(ref_genes) == 0:
595+
return
596+
try:
597+
self.cluster_info_model.gene_sets_enrichment(
598+
self.gs_selection_component.gene_sets, selected_sets, ref_genes
599+
)
600+
except Exception as e:
601+
raise e
602+
603+
self.filter_gene_sets()
604+
self.__update_info_box()
605+
self.cluster_info_view.resizeRowsToContents()
606+
583607
@Inputs.data_table
584608
def handle_input(self, data):
585609
self.closeContext()
@@ -596,8 +620,6 @@ def handle_input(self, data):
596620
self.gene_id_attribute = None
597621
self.clusters = None
598622

599-
self.gs_widget.clear()
600-
self.gs_widget.clear_gene_sets()
601623
self.cluster_info_view.setModel(None)
602624

603625
self.cluster_indicators = []
@@ -638,6 +660,9 @@ def handle_input(self, data):
638660
GENE_ID_ATTRIBUTE, None
639661
)
640662

663+
self.gs_selection_component.set_selected_organism_by_tax_id(self.tax_id)
664+
self.gs_selection_component._load_gene_sets()
665+
641666
if not self.cluster_indicator_model:
642667
self.Error.no_cluster_indicator()
643668
return
@@ -647,21 +672,17 @@ def handle_input(self, data):
647672

648673
self.openContext(self.input_data.domain)
649674

650-
self.gs_widget.load_gene_sets(self.tax_id)
651675
if self.cluster_indicator_model and len(self.cluster_indicators) < 1:
652676
self.cluster_indicators = [self.cluster_indicator_model[0]]
653677
if self.batch_indicator_model and self.batch_indicator is None:
654678
self.batch_indicator = self.batch_indicator_model[0]
655-
656679
self.invalidate()
657-
658-
if self.custom_data:
659-
self.refresh_custom_gene_sets()
660-
self._handle_future_model()
661-
self.handle_custom_gene_sets()
680+
else:
681+
self.gs_selection_component._gene_sets = GeneSets()
682+
self.handle_custom_gene_sets()
662683

663684
@Inputs.custom_sets
664-
def handle_custom_input(self, data):
685+
def handle_custom_input(self, custom_data):
665686
self.Error.clear()
666687
self.Warning.clear()
667688
self.closeContext()
@@ -672,9 +693,8 @@ def handle_custom_input(self, data):
672693
self.custom_gene_id_column = None
673694
self.num_of_custom_sets = None
674695
self.feature_model.set_domain(None)
675-
676-
if data:
677-
self.custom_data = data
696+
if custom_data:
697+
self.custom_data = custom_data
678698
self.feature_model.set_domain(self.custom_data.domain)
679699
self.custom_tax_id = str(self.custom_data.attributes.get(TAX_ID, None))
680700
self.custom_use_attr_names = self.custom_data.attributes.get(
@@ -686,15 +706,14 @@ def handle_custom_input(self, data):
686706
self.custom_gene_id_column = self.custom_data.attributes.get(
687707
GENE_ID_COLUMN, None
688708
)
689-
690-
self._handle_future_model()
691-
692-
if self.input_data:
693-
self.openContext(self.input_data.domain)
694-
695-
self.gs_label_combobox.setDisabled(True)
696-
self.refresh_custom_gene_sets()
709+
self.gs_selection_component.initialize_custom_gene_sets(custom_data)
710+
self.num_of_custom_sets = self.gs_selection_component.num_of_custom_sets
711+
else:
712+
self.stored_gene_sets_selection = ()
713+
self.gs_selection_component.selection = []
714+
self.gs_selection_component.initialize_custom_gene_sets(None)
697715
self.handle_custom_gene_sets(select_customs_flag=True)
716+
self.__update_info_box()
698717

699718
def __check_organism_mismatch(self):
700719
"""Check if organisms from different inputs match.
@@ -719,49 +738,21 @@ def handle_custom_gene_sets(self, select_customs_flag=False):
719738
if self.custom_gene_set_indicator:
720739
if self.custom_data is not None and self.custom_gene_id_column is not None:
721740
if self.__check_organism_mismatch():
722-
self.gs_label_combobox.setDisabled(True)
741+
self.gs_selection_component.initialize_custom_gene_sets(None)
723742
self.Error.organism_mismatch()
724-
self.gs_widget.update_gs_hierarchy()
725743
self.__gene_sets_enrichment()
726744
return
727-
728-
if isinstance(self.custom_gene_set_indicator, DiscreteVariable):
729-
labels = self.custom_gene_set_indicator.values
730-
gene_sets_names = [
731-
labels[int(idx)]
732-
for idx in self.custom_data.get_column(
733-
self.custom_gene_set_indicator
734-
)
735-
]
736-
else:
737-
gene_sets_names = self.custom_data.get_column(
738-
self.custom_gene_set_indicator
739-
)
740-
741-
self.num_of_custom_sets = len(set(gene_sets_names))
742-
gene_names = self.custom_data.get_column(self.custom_gene_id_column)
743-
hierarchy_title = (
744-
self.custom_data.name if self.custom_data.name else 'Custom sets',
745-
)
746-
try:
747-
self.gs_widget.add_custom_sets(
748-
gene_sets_names,
749-
gene_names,
750-
hierarchy_title=hierarchy_title,
751-
select_customs_flag=select_customs_flag,
752-
)
753-
except GeneSetException:
754-
pass
755-
self.gs_label_combobox.setDisabled(False)
756745
else:
757-
self.gs_widget.update_gs_hierarchy()
758-
746+
self.gs_selection_component._update_tree_widget()
759747
self.__gene_sets_enrichment()
760748
self.__update_info_box()
761749

762750
def refresh_custom_gene_sets(self):
763-
self.gs_widget.clear_custom_sets()
764-
# self.gs_widget.update_gs_hierarchy()
751+
self.gs_selection_component._gene_sets.delete_sets_by_hierarchy(
752+
self.gs_selection_component.custom_gene_set_hierarchy
753+
)
754+
self.gs_selection_component.custom_gene_set_hierarchy = None
755+
self.gs_selection_component._update_tree_widget()
765756

766757
def gene_scores_output(self, selected_clusters):
767758
metas = [
@@ -856,7 +847,15 @@ def commit(self):
856847
selected_cluster_indexes = set()
857848
selected_cluster_genes = set()
858849

859-
if not self.input_data or not selected_rows:
850+
if self.input_data and not selected_rows:
851+
selected_rows = [
852+
self.cluster_info_model.index(row, 0)
853+
for row in range(self.cluster_info_model.rowCount())
854+
]
855+
856+
if not self.input_data:
857+
self.Outputs.gene_scores.send(None)
858+
self.Outputs.gene_set_scores.send(None)
860859
self.Outputs.selected_data.send(None)
861860
return
862861

orangecontrib/bioinformatics/widgets/utils/gui/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
""" GUI utils for widgets """
2+
23
from numbers import Real, Integral
34
from collections import namedtuple
45

@@ -135,7 +136,7 @@ def sizeHint(self, option, index):
135136
doc.setHtml(gene_obj.to_html())
136137
doc.setTextWidth(options.rect.width() - 10)
137138

138-
return QSize(doc.idealWidth(), doc.size().height())
139+
return QSize(int(doc.idealWidth()), int(doc.size().height()))
139140

140141
def paint(self, painter, option, index):
141142
options = QStyleOptionViewItem(option)

0 commit comments

Comments
 (0)