We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
WordEnrichment Nans & BoW Features Only
<!--
This is an issue template. Please fill in the relevant details in the
sections below.
-->

##### Text version
<!-- From menu _Options→Add-ons→Orange3-Text_ or code `orangecontrib.text.version.full_version` -->
0.2.4.dev

##### WordEnrichment issues:
* WE takes all features. It should only consider BoW features. If none BoW features present raise an error.
* WE doesn't work if nans in sparse matrix. Probably cannot occur is we use only BoW features.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `orangecontrib/text/vectorization/base.py`
Content:
```
1 import numpy as np
2 from gensim import matutils
3 from gensim.corpora import Dictionary
4 
5 
6 class BaseVectorizer:
7     """Base class for vectorization objects. """
8     name = NotImplemented
9 
10     def transform(self, corpus, copy=True, source_dict=None):
11         """Transforms a corpus to a new one with additional attributes. """
12         if copy:
13             corpus = corpus.copy()
14 
15         if not len(corpus.dictionary):
16             return corpus
17         else:
18             return self._transform(corpus, source_dict)
19 
20     def _transform(self, corpus, source_dict):
21         raise NotImplementedError
22 
23     def report(self):
24         """Reports configuration items."""
25         raise NotImplementedError
26 
27     @staticmethod
28     def add_features(corpus, X, dictionary, compute_values=None):
29         order = np.argsort([dictionary[i] for i in range(len(dictionary))])
30         compute_values = np.array(compute_values)[order]
31         corpus.extend_attributes(X[:, order],
32                                  feature_names=(dictionary[i] for i in order),
33                                  var_attrs={'hidden': True, 'skip-normalization': True},
34                                  compute_values=compute_values)
35         corpus.ngrams_corpus = matutils.Sparse2Corpus(X.T)
36
```

Path: `orangecontrib/text/vectorization/bagofwords.py`
Content:
```
1 from collections import OrderedDict
2 from functools import partial
3 
4 import numpy as np
5 from gensim import corpora, models, matutils
6 from sklearn.preprocessing import normalize
7 
8 from Orange.data.util import SharedComputeValue
9 from orangecontrib.text.vectorization.base import BaseVectorizer
10 
11 
12 class BoWPreprocessTransform:
13     """
14     Shared computation for transforming new data set into the classifiers's BoW domain.
15     This will run preprocessing as well as BoW transformation itself.
16     """
17     def __init__(self, preprocessor, bow_vectorizer, dictionary):
18         self.preprocessor = preprocessor
19         self.bow_vectorizer = bow_vectorizer
20         self.dictionary = dictionary
21 
22     def __call__(self, new_corpus):
23         new_corpus = self.preprocessor(new_corpus)
24         bow_corpus = self.bow_vectorizer.transform(new_corpus, copy=True, source_dict=self.dictionary)
25         # store name to indices mapping so BoWComputeValue can run faster
26         bow_corpus.feature_name_to_index = {attr.name: i for i, attr in enumerate(bow_corpus.domain.attributes)}
27         return bow_corpus
28 
29 
30 class BoWComputeValue(SharedComputeValue):
31     """
32     Compute Value for Bow features. This enables applying a
33     classifier — that was trained on a BoW model — on new data.
34     """
35     def __init__(self, name, compute_shared):
36         super().__init__(compute_shared)
37         self.name = name
38 
39     def compute(self, data, shared_data):
40         ind = shared_data.feature_name_to_index[self.name]
41         return shared_data.X[:, ind]
42 
43 
44 class BowVectorizer(BaseVectorizer):
45     name = 'BoW Vectorizer'
46 
47     COUNT = 'Count'
48     BINARY = 'Binary'
49     SUBLINEAR = 'Sublinear'
50     NONE = '(None)'
51     IDF = 'IDF'
52     SMOOTH = 'Smooth IDF'
53     L1 = 'L1 (Sum of elements)'
54     L2 = 'L2 (Euclidean)'
55 
56     wlocals = OrderedDict((
57         (COUNT, lambda tf: tf),
58         (BINARY, lambda tf: int(tf > 0)),
59         (SUBLINEAR, lambda tf: 1 + np.log(tf)),
60     ))
61 
62     wglobals = OrderedDict((
63         (NONE, lambda df, N: 1),
64         (IDF, lambda df, N: np.log(N/df)),
65         (SMOOTH, lambda df, N: np.log(1 + N/df)),
66     ))
67 
68     norms = OrderedDict((
69         (NONE, None),
70         (L1, partial(normalize, norm='l1')),
71         (L2, partial(normalize, norm='l2')),
72     ))
73 
74     def __init__(self, norm=NONE, wlocal=COUNT, wglobal=NONE):
75         self.norm = norm
76         self.wlocal = wlocal
77         self.wglobal = wglobal
78 
79     def _transform(self, corpus, source_dict=None):
80         temp_corpus = list(corpus.ngrams_iterator(' ', include_postags=True))
81         dic = corpora.Dictionary(temp_corpus, prune_at=None) if not source_dict else source_dict
82         temp_corpus = [dic.doc2bow(doc) for doc in temp_corpus]
83         model = models.TfidfModel(temp_corpus, normalize=False,
84                                   wlocal=self.wlocals[self.wlocal],
85                                   wglobal=self.wglobals[self.wglobal])
86 
87         X = matutils.corpus2csc(model[temp_corpus], dtype=np.float, num_terms=len(dic)).T
88         norm = self.norms[self.norm]
89         if norm:
90             X = norm(X)
91 
92         # set compute values
93         shared_cv = BoWPreprocessTransform(corpus.used_preprocessor, self, dic)
94         cv = [BoWComputeValue(dic[i], shared_cv) for i in range(len(dic))]
95 
96         self.add_features(corpus, X, dic, cv)
97         return corpus
98 
99     def report(self):
100         return (('Term Frequency', self.wlocal),
101                 ('Document Frequency', self.wglobal),
102                 ('Regularization', self.norm),)
103
```

Path: `orangecontrib/text/widgets/owwordenrichment.py`
Content:
```
1 import math
2 
3 import numpy as np
4 from AnyQt.QtWidgets import QTreeWidget, QTreeView, QTreeWidgetItem
5 
6 from Orange.data import Table
7 from Orange.widgets import gui
8 from Orange.widgets.settings import Setting
9 from Orange.widgets.widget import OWWidget, Msg
10 from orangecontrib.text.util import np_sp_sum
11 from orangecontrib.text.stats import false_discovery_rate, hypergeom_p_values
12 
13 
14 class OWWordEnrichment(OWWidget):
15     # Basic widget info
16     name = "Word Enrichment"
17     description = "Word enrichment analysis for selected documents."
18     icon = "icons/SetEnrichment.svg"
19     priority = 60
20 
21     # Input/output
22     inputs = [("Selected Data", Table, "set_data_selected"),
23               ("Data", Table, "set_data"),]
24     want_main_area = True
25 
26     class Error(OWWidget.Error):
27         no_words_overlap = Msg('No words overlap!')
28         empty_selection = Msg('Selected data is empty!')
29         all_selected = Msg('All examples can not be selected!')
30 
31     # Settings
32     filter_by_p = Setting(False)
33     filter_p_value = Setting(0.01)
34     filter_by_fdr = Setting(True)
35     filter_fdr_value = Setting(0.2)
36 
37     def __init__(self):
38         super().__init__()
39 
40         # Init data
41         self.data = None
42         self.selected_data = None
43         self.selected_data_transformed = None   # used for transforming the 'selected data' into the 'data' domain
44 
45         self.words = []
46         self.p_values = []
47         self.fdr_values = []
48 
49         # Info section
50         fbox = gui.widgetBox(self.controlArea, "Info")
51         self.info_all = gui.label(fbox, self, 'Cluster words:')
52         self.info_sel = gui.label(fbox, self, 'Selected words:')
53         self.info_fil = gui.label(fbox, self, 'After filtering:')
54 
55         # Filtering settings
56         fbox = gui.widgetBox(self.controlArea, "Filter")
57         hbox = gui.widgetBox(fbox, orientation=0)
58 
59         self.chb_p = gui.checkBox(hbox, self, "filter_by_p", "p-value",
60                                   callback=self.filter_and_display,
61                                   tooltip="Filter by word p-value")
62         self.spin_p = gui.doubleSpin(hbox, self, 'filter_p_value',
63                                      1e-4, 1, step=1e-4, labelWidth=15,
64                                      callback=self.filter_and_display,
65                                      callbackOnReturn=True,
66                                      tooltip="Max p-value for word")
67         self.spin_p.setEnabled(self.filter_by_p)
68 
69         hbox = gui.widgetBox(fbox, orientation=0)
70         self.chb_fdr = gui.checkBox(hbox, self, "filter_by_fdr", "FDR",
71                                     callback=self.filter_and_display,
72                                     tooltip="Filter by word FDR")
73         self.spin_fdr = gui.doubleSpin(hbox, self, 'filter_fdr_value',
74                                        1e-4, 1, step=1e-4, labelWidth=15,
75                                        callback=self.filter_and_display,
76                                        callbackOnReturn=True,
77                                        tooltip="Max p-value for word")
78         self.spin_fdr.setEnabled(self.filter_by_fdr)
79         gui.rubber(self.controlArea)
80 
81         # Word's list view
82         self.cols = ['Word', 'p-value', 'FDR']
83         self.sig_words = QTreeWidget()
84         self.sig_words.setColumnCount(len(self.cols))
85         self.sig_words.setHeaderLabels(self.cols)
86         self.sig_words.setSortingEnabled(True)
87         self.sig_words.setSelectionMode(QTreeView.ExtendedSelection)
88         self.sig_words.sortByColumn(2, 0)   # 0 is ascending order
89         for i in range(len(self.cols)):
90             self.sig_words.resizeColumnToContents(i)
91         self.mainArea.layout().addWidget(self.sig_words)
92 
93     def set_data(self, data=None):
94         self.data = data
95 
96     def set_data_selected(self, data=None):
97         self.selected_data = data
98 
99     def handleNewSignals(self):
100         self.check_data()
101 
102     def check_data(self):
103         self.Error.clear()
104         if isinstance(self.data, Table) and \
105                 isinstance(self.selected_data, Table):
106             if len(self.selected_data) == 0:
107                 self.Error.empty_selection()
108                 self.clear()
109                 return
110 
111             self.selected_data_transformed = Table.from_table(
112                 self.data.domain, self.selected_data)
113 
114             sum_X = np_sp_sum(self.selected_data_transformed.X)
115             if sum_X == 0 or math.isnan(sum_X):
116                 self.Error.no_words_overlap()
117                 self.clear()
118             elif len(self.data) == len(self.selected_data):
119                 self.Error.all_selected()
120                 self.clear()
121             else:
122                 self.apply()
123         else:
124             self.clear()
125 
126     def clear(self):
127         self.sig_words.clear()
128         self.info_all.setText('Cluster words:')
129         self.info_sel.setText('Selected words:')
130         self.info_fil.setText('After filtering:')
131 
132     def filter_enabled(self, b):
133         self.chb_p.setEnabled(b)
134         self.chb_fdr.setEnabled(b)
135         self.spin_p.setEnabled(b)
136         self.spin_fdr.setEnabled(b)
137 
138     def filter_and_display(self):
139         self.spin_p.setEnabled(self.filter_by_p)
140         self.spin_fdr.setEnabled(self.filter_by_fdr)
141         self.sig_words.clear()
142 
143         if self.selected_data_transformed is None:  # do nothing when no Data
144             return
145 
146         count = 0
147         if self.words:
148             for word, pval, fval in zip(self.words, self.p_values, self.fdr_values):
149                 if (not self.filter_by_p or pval <= self.filter_p_value) and \
150                         (not self.filter_by_fdr or fval <= self.filter_fdr_value):
151                     it = EATreeWidgetItem(word, pval, fval, self.sig_words)
152                     self.sig_words.addTopLevelItem(it)
153                     count += 1
154 
155         for i in range(len(self.cols)):
156             self.sig_words.resizeColumnToContents(i)
157 
158         self.info_all.setText('Cluster words: {}'.format(len(self.selected_data_transformed.domain.attributes)))
159         self.info_sel.setText('Selected words: {}'.format(np.count_nonzero(np_sp_sum(self.selected_data_transformed.X, axis=0))))
160         if not self.filter_by_p and not self.filter_by_fdr:
161             self.info_fil.setText('After filtering:')
162             self.info_fil.setEnabled(False)
163         else:
164             self.info_fil.setEnabled(True)
165             self.info_fil.setText('After filtering: {}'.format(count))
166 
167     def progress(self, p):
168         self.progressBarSet(p)
169 
170     def apply(self):
171         self.clear()
172         self.progressBarInit()
173         self.filter_enabled(False)
174 
175         self.words = [i.name for i in self.selected_data_transformed.domain.attributes]
176         self.p_values = hypergeom_p_values(self.data.X,
177                                            self.selected_data_transformed.X,
178                                            callback=self.progress)
179         self.fdr_values = false_discovery_rate(self.p_values)
180         self.filter_and_display()
181         self.filter_enabled(True)
182         self.progressBarFinished()
183 
184 
185 fp = lambda score: "%0.5f" % score if score > 10e-3 else "%0.1e" % score
186 fpt = lambda score: "%0.9f" % score if score > 10e-3 else "%0.5e" % score
187 
188 
189 class EATreeWidgetItem(QTreeWidgetItem):
190     def __init__(self, word, p_value, f_value, parent):
191         super().__init__(parent)
192         self.data = [word, p_value, f_value]
193         self.setText(0, word)
194         self.setText(1, fp(p_value))
195         self.setToolTip(1, fpt(p_value))
196         self.setText(2, fp(f_value))
197         self.setToolTip(2, fpt(f_value))
198 
199     def __lt__(self, other):
200         col = self.treeWidget().sortColumn()
201         return self.data[col] < other.data[col]
202
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/orangecontrib/text/vectorization/bagofwords.py b/orangecontrib/text/vectorization/bagofwords.py
--- a/orangecontrib/text/vectorization/bagofwords.py
+++ b/orangecontrib/text/vectorization/bagofwords.py
@@ -93,7 +93,7 @@
         shared_cv = BoWPreprocessTransform(corpus.used_preprocessor, self, dic)
         cv = [BoWComputeValue(dic[i], shared_cv) for i in range(len(dic))]
 
-        self.add_features(corpus, X, dic, cv)
+        self.add_features(corpus, X, dic, cv, var_attrs={'bow-feature': True})
         return corpus
 
     def report(self):
diff --git a/orangecontrib/text/vectorization/base.py b/orangecontrib/text/vectorization/base.py
--- a/orangecontrib/text/vectorization/base.py
+++ b/orangecontrib/text/vectorization/base.py
@@ -25,11 +25,20 @@
         raise NotImplementedError
 
     @staticmethod
-    def add_features(corpus, X, dictionary, compute_values=None):
+    def add_features(corpus, X, dictionary, compute_values=None, var_attrs=None):
         order = np.argsort([dictionary[i] for i in range(len(dictionary))])
-        compute_values = np.array(compute_values)[order]
+        if compute_values is not None:
+            compute_values = np.array(compute_values)[order]
+
+        variable_attrs = {
+            'hidden': True,
+            'skip-normalization': True,
+        }
+        if isinstance(var_attrs, dict):
+            variable_attrs.update(var_attrs)
+
         corpus.extend_attributes(X[:, order],
                                  feature_names=(dictionary[i] for i in order),
-                                 var_attrs={'hidden': True, 'skip-normalization': True},
+                                 var_attrs=variable_attrs,
                                  compute_values=compute_values)
         corpus.ngrams_corpus = matutils.Sparse2Corpus(X.T)
diff --git a/orangecontrib/text/widgets/owwordenrichment.py b/orangecontrib/text/widgets/owwordenrichment.py
--- a/orangecontrib/text/widgets/owwordenrichment.py
+++ b/orangecontrib/text/widgets/owwordenrichment.py
@@ -1,12 +1,11 @@
-import math
-
 import numpy as np
 from AnyQt.QtWidgets import QTreeWidget, QTreeView, QTreeWidgetItem
 
-from Orange.data import Table
+from Orange.data import Table, Domain
 from Orange.widgets import gui
 from Orange.widgets.settings import Setting
 from Orange.widgets.widget import OWWidget, Msg
+from orangecontrib.text import Corpus
 from orangecontrib.text.util import np_sp_sum
 from orangecontrib.text.stats import false_discovery_rate, hypergeom_p_values
 
@@ -24,6 +23,7 @@
     want_main_area = True
 
     class Error(OWWidget.Error):
+        no_bow_features = Msg('No bag-of-words features!')
         no_words_overlap = Msg('No words overlap!')
         empty_selection = Msg('Selected data is empty!')
         all_selected = Msg('All examples can not be selected!')
@@ -99,6 +99,15 @@
     def handleNewSignals(self):
         self.check_data()
 
+    def get_bow_domain(self):
+        domain = self.data.domain
+        return Domain(
+            attributes=[a for a in domain.attributes
+                        if a.attributes.get('bow-feature', False)],
+            class_vars=domain.class_vars,
+            metas=domain.metas,
+            source=domain)
+
     def check_data(self):
         self.Error.clear()
         if isinstance(self.data, Table) and \
@@ -108,11 +117,16 @@
                 self.clear()
                 return
 
-            self.selected_data_transformed = Table.from_table(
-                self.data.domain, self.selected_data)
+            # keep only BoW features
+            bow_domain = self.get_bow_domain()
+            if len(bow_domain.attributes) == 0:
+                self.Error.no_bow_features()
+                self.clear()
+                return
+            self.data = Corpus.from_table(bow_domain, self.data)
+            self.selected_data_transformed = Corpus.from_table(bow_domain, self.selected_data)
 
-            sum_X = np_sp_sum(self.selected_data_transformed.X)
-            if sum_X == 0 or math.isnan(sum_X):
+            if np_sp_sum(self.selected_data_transformed.X) == 0:
                 self.Error.no_words_overlap()
                 self.clear()
             elif len(self.data) == len(self.selected_data):

{"golden_diff": "diff --git a/orangecontrib/text/vectorization/bagofwords.py b/orangecontrib/text/vectorization/bagofwords.py\n--- a/orangecontrib/text/vectorization/bagofwords.py\n+++ b/orangecontrib/text/vectorization/bagofwords.py\n@@ -93,7 +93,7 @@\n         shared_cv = BoWPreprocessTransform(corpus.used_preprocessor, self, dic)\n         cv = [BoWComputeValue(dic[i], shared_cv) for i in range(len(dic))]\n \n-        self.add_features(corpus, X, dic, cv)\n+        self.add_features(corpus, X, dic, cv, var_attrs={'bow-feature': True})\n         return corpus\n \n     def report(self):\ndiff --git a/orangecontrib/text/vectorization/base.py b/orangecontrib/text/vectorization/base.py\n--- a/orangecontrib/text/vectorization/base.py\n+++ b/orangecontrib/text/vectorization/base.py\n@@ -25,11 +25,20 @@\n         raise NotImplementedError\n \n     @staticmethod\n-    def add_features(corpus, X, dictionary, compute_values=None):\n+    def add_features(corpus, X, dictionary, compute_values=None, var_attrs=None):\n         order = np.argsort([dictionary[i] for i in range(len(dictionary))])\n-        compute_values = np.array(compute_values)[order]\n+        if compute_values is not None:\n+            compute_values = np.array(compute_values)[order]\n+\n+        variable_attrs = {\n+            'hidden': True,\n+            'skip-normalization': True,\n+        }\n+        if isinstance(var_attrs, dict):\n+            variable_attrs.update(var_attrs)\n+\n         corpus.extend_attributes(X[:, order],\n                                  feature_names=(dictionary[i] for i in order),\n-                                 var_attrs={'hidden': True, 'skip-normalization': True},\n+                                 var_attrs=variable_attrs,\n                                  compute_values=compute_values)\n         corpus.ngrams_corpus = matutils.Sparse2Corpus(X.T)\ndiff --git a/orangecontrib/text/widgets/owwordenrichment.py b/orangecontrib/text/widgets/owwordenrichment.py\n--- a/orangecontrib/text/widgets/owwordenrichment.py\n+++ b/orangecontrib/text/widgets/owwordenrichment.py\n@@ -1,12 +1,11 @@\n-import math\n-\n import numpy as np\n from AnyQt.QtWidgets import QTreeWidget, QTreeView, QTreeWidgetItem\n \n-from Orange.data import Table\n+from Orange.data import Table, Domain\n from Orange.widgets import gui\n from Orange.widgets.settings import Setting\n from Orange.widgets.widget import OWWidget, Msg\n+from orangecontrib.text import Corpus\n from orangecontrib.text.util import np_sp_sum\n from orangecontrib.text.stats import false_discovery_rate, hypergeom_p_values\n \n@@ -24,6 +23,7 @@\n     want_main_area = True\n \n     class Error(OWWidget.Error):\n+        no_bow_features = Msg('No bag-of-words features!')\n         no_words_overlap = Msg('No words overlap!')\n         empty_selection = Msg('Selected data is empty!')\n         all_selected = Msg('All examples can not be selected!')\n@@ -99,6 +99,15 @@\n     def handleNewSignals(self):\n         self.check_data()\n \n+    def get_bow_domain(self):\n+        domain = self.data.domain\n+        return Domain(\n+            attributes=[a for a in domain.attributes\n+                        if a.attributes.get('bow-feature', False)],\n+            class_vars=domain.class_vars,\n+            metas=domain.metas,\n+            source=domain)\n+\n     def check_data(self):\n         self.Error.clear()\n         if isinstance(self.data, Table) and \\\n@@ -108,11 +117,16 @@\n                 self.clear()\n                 return\n \n-            self.selected_data_transformed = Table.from_table(\n-                self.data.domain, self.selected_data)\n+            # keep only BoW features\n+            bow_domain = self.get_bow_domain()\n+            if len(bow_domain.attributes) == 0:\n+                self.Error.no_bow_features()\n+                self.clear()\n+                return\n+            self.data = Corpus.from_table(bow_domain, self.data)\n+            self.selected_data_transformed = Corpus.from_table(bow_domain, self.selected_data)\n \n-            sum_X = np_sp_sum(self.selected_data_transformed.X)\n-            if sum_X == 0 or math.isnan(sum_X):\n+            if np_sp_sum(self.selected_data_transformed.X) == 0:\n                 self.Error.no_words_overlap()\n                 self.clear()\n             elif len(self.data) == len(self.selected_data):\n", "issue": "WordEnrichment Nans & BoW Features Only\n<!--\r\nThis is an issue template. Please fill in the relevant details in the\r\nsections below.\r\n-->\r\n\r\n##### Text version\r\n<!-- From menu _Options\u2192Add-ons\u2192Orange3-Text_ or code `orangecontrib.text.version.full_version` -->\r\n0.2.4.dev\r\n\r\n##### WordEnrichment issues:\r\n* WE takes all features. It should only consider BoW features. If none BoW features present raise an error.\r\n* WE doesn't work if nans in sparse matrix. Probably cannot occur is we use only BoW features.\r\n\n", "before_files": [{"content": "import numpy as np\nfrom gensim import matutils\nfrom gensim.corpora import Dictionary\n\n\nclass BaseVectorizer:\n    \"\"\"Base class for vectorization objects. \"\"\"\n    name = NotImplemented\n\n    def transform(self, corpus, copy=True, source_dict=None):\n        \"\"\"Transforms a corpus to a new one with additional attributes. \"\"\"\n        if copy:\n            corpus = corpus.copy()\n\n        if not len(corpus.dictionary):\n            return corpus\n        else:\n            return self._transform(corpus, source_dict)\n\n    def _transform(self, corpus, source_dict):\n        raise NotImplementedError\n\n    def report(self):\n        \"\"\"Reports configuration items.\"\"\"\n        raise NotImplementedError\n\n    @staticmethod\n    def add_features(corpus, X, dictionary, compute_values=None):\n        order = np.argsort([dictionary[i] for i in range(len(dictionary))])\n        compute_values = np.array(compute_values)[order]\n        corpus.extend_attributes(X[:, order],\n                                 feature_names=(dictionary[i] for i in order),\n                                 var_attrs={'hidden': True, 'skip-normalization': True},\n                                 compute_values=compute_values)\n        corpus.ngrams_corpus = matutils.Sparse2Corpus(X.T)\n", "path": "orangecontrib/text/vectorization/base.py"}, {"content": "from collections import OrderedDict\nfrom functools import partial\n\nimport numpy as np\nfrom gensim import corpora, models, matutils\nfrom sklearn.preprocessing import normalize\n\nfrom Orange.data.util import SharedComputeValue\nfrom orangecontrib.text.vectorization.base import BaseVectorizer\n\n\nclass BoWPreprocessTransform:\n    \"\"\"\n    Shared computation for transforming new data set into the classifiers's BoW domain.\n    This will run preprocessing as well as BoW transformation itself.\n    \"\"\"\n    def __init__(self, preprocessor, bow_vectorizer, dictionary):\n        self.preprocessor = preprocessor\n        self.bow_vectorizer = bow_vectorizer\n        self.dictionary = dictionary\n\n    def __call__(self, new_corpus):\n        new_corpus = self.preprocessor(new_corpus)\n        bow_corpus = self.bow_vectorizer.transform(new_corpus, copy=True, source_dict=self.dictionary)\n        # store name to indices mapping so BoWComputeValue can run faster\n        bow_corpus.feature_name_to_index = {attr.name: i for i, attr in enumerate(bow_corpus.domain.attributes)}\n        return bow_corpus\n\n\nclass BoWComputeValue(SharedComputeValue):\n    \"\"\"\n    Compute Value for Bow features. This enables applying a\n    classifier \u2014 that was trained on a BoW model \u2014 on new data.\n    \"\"\"\n    def __init__(self, name, compute_shared):\n        super().__init__(compute_shared)\n        self.name = name\n\n    def compute(self, data, shared_data):\n        ind = shared_data.feature_name_to_index[self.name]\n        return shared_data.X[:, ind]\n\n\nclass BowVectorizer(BaseVectorizer):\n    name = 'BoW Vectorizer'\n\n    COUNT = 'Count'\n    BINARY = 'Binary'\n    SUBLINEAR = 'Sublinear'\n    NONE = '(None)'\n    IDF = 'IDF'\n    SMOOTH = 'Smooth IDF'\n    L1 = 'L1 (Sum of elements)'\n    L2 = 'L2 (Euclidean)'\n\n    wlocals = OrderedDict((\n        (COUNT, lambda tf: tf),\n        (BINARY, lambda tf: int(tf > 0)),\n        (SUBLINEAR, lambda tf: 1 + np.log(tf)),\n    ))\n\n    wglobals = OrderedDict((\n        (NONE, lambda df, N: 1),\n        (IDF, lambda df, N: np.log(N/df)),\n        (SMOOTH, lambda df, N: np.log(1 + N/df)),\n    ))\n\n    norms = OrderedDict((\n        (NONE, None),\n        (L1, partial(normalize, norm='l1')),\n        (L2, partial(normalize, norm='l2')),\n    ))\n\n    def __init__(self, norm=NONE, wlocal=COUNT, wglobal=NONE):\n        self.norm = norm\n        self.wlocal = wlocal\n        self.wglobal = wglobal\n\n    def _transform(self, corpus, source_dict=None):\n        temp_corpus = list(corpus.ngrams_iterator(' ', include_postags=True))\n        dic = corpora.Dictionary(temp_corpus, prune_at=None) if not source_dict else source_dict\n        temp_corpus = [dic.doc2bow(doc) for doc in temp_corpus]\n        model = models.TfidfModel(temp_corpus, normalize=False,\n                                  wlocal=self.wlocals[self.wlocal],\n                                  wglobal=self.wglobals[self.wglobal])\n\n        X = matutils.corpus2csc(model[temp_corpus], dtype=np.float, num_terms=len(dic)).T\n        norm = self.norms[self.norm]\n        if norm:\n            X = norm(X)\n\n        # set compute values\n        shared_cv = BoWPreprocessTransform(corpus.used_preprocessor, self, dic)\n        cv = [BoWComputeValue(dic[i], shared_cv) for i in range(len(dic))]\n\n        self.add_features(corpus, X, dic, cv)\n        return corpus\n\n    def report(self):\n        return (('Term Frequency', self.wlocal),\n                ('Document Frequency', self.wglobal),\n                ('Regularization', self.norm),)\n", "path": "orangecontrib/text/vectorization/bagofwords.py"}, {"content": "import math\n\nimport numpy as np\nfrom AnyQt.QtWidgets import QTreeWidget, QTreeView, QTreeWidgetItem\n\nfrom Orange.data import Table\nfrom Orange.widgets import gui\nfrom Orange.widgets.settings import Setting\nfrom Orange.widgets.widget import OWWidget, Msg\nfrom orangecontrib.text.util import np_sp_sum\nfrom orangecontrib.text.stats import false_discovery_rate, hypergeom_p_values\n\n\nclass OWWordEnrichment(OWWidget):\n    # Basic widget info\n    name = \"Word Enrichment\"\n    description = \"Word enrichment analysis for selected documents.\"\n    icon = \"icons/SetEnrichment.svg\"\n    priority = 60\n\n    # Input/output\n    inputs = [(\"Selected Data\", Table, \"set_data_selected\"),\n              (\"Data\", Table, \"set_data\"),]\n    want_main_area = True\n\n    class Error(OWWidget.Error):\n        no_words_overlap = Msg('No words overlap!')\n        empty_selection = Msg('Selected data is empty!')\n        all_selected = Msg('All examples can not be selected!')\n\n    # Settings\n    filter_by_p = Setting(False)\n    filter_p_value = Setting(0.01)\n    filter_by_fdr = Setting(True)\n    filter_fdr_value = Setting(0.2)\n\n    def __init__(self):\n        super().__init__()\n\n        # Init data\n        self.data = None\n        self.selected_data = None\n        self.selected_data_transformed = None   # used for transforming the 'selected data' into the 'data' domain\n\n        self.words = []\n        self.p_values = []\n        self.fdr_values = []\n\n        # Info section\n        fbox = gui.widgetBox(self.controlArea, \"Info\")\n        self.info_all = gui.label(fbox, self, 'Cluster words:')\n        self.info_sel = gui.label(fbox, self, 'Selected words:')\n        self.info_fil = gui.label(fbox, self, 'After filtering:')\n\n        # Filtering settings\n        fbox = gui.widgetBox(self.controlArea, \"Filter\")\n        hbox = gui.widgetBox(fbox, orientation=0)\n\n        self.chb_p = gui.checkBox(hbox, self, \"filter_by_p\", \"p-value\",\n                                  callback=self.filter_and_display,\n                                  tooltip=\"Filter by word p-value\")\n        self.spin_p = gui.doubleSpin(hbox, self, 'filter_p_value',\n                                     1e-4, 1, step=1e-4, labelWidth=15,\n                                     callback=self.filter_and_display,\n                                     callbackOnReturn=True,\n                                     tooltip=\"Max p-value for word\")\n        self.spin_p.setEnabled(self.filter_by_p)\n\n        hbox = gui.widgetBox(fbox, orientation=0)\n        self.chb_fdr = gui.checkBox(hbox, self, \"filter_by_fdr\", \"FDR\",\n                                    callback=self.filter_and_display,\n                                    tooltip=\"Filter by word FDR\")\n        self.spin_fdr = gui.doubleSpin(hbox, self, 'filter_fdr_value',\n                                       1e-4, 1, step=1e-4, labelWidth=15,\n                                       callback=self.filter_and_display,\n                                       callbackOnReturn=True,\n                                       tooltip=\"Max p-value for word\")\n        self.spin_fdr.setEnabled(self.filter_by_fdr)\n        gui.rubber(self.controlArea)\n\n        # Word's list view\n        self.cols = ['Word', 'p-value', 'FDR']\n        self.sig_words = QTreeWidget()\n        self.sig_words.setColumnCount(len(self.cols))\n        self.sig_words.setHeaderLabels(self.cols)\n        self.sig_words.setSortingEnabled(True)\n        self.sig_words.setSelectionMode(QTreeView.ExtendedSelection)\n        self.sig_words.sortByColumn(2, 0)   # 0 is ascending order\n        for i in range(len(self.cols)):\n            self.sig_words.resizeColumnToContents(i)\n        self.mainArea.layout().addWidget(self.sig_words)\n\n    def set_data(self, data=None):\n        self.data = data\n\n    def set_data_selected(self, data=None):\n        self.selected_data = data\n\n    def handleNewSignals(self):\n        self.check_data()\n\n    def check_data(self):\n        self.Error.clear()\n        if isinstance(self.data, Table) and \\\n                isinstance(self.selected_data, Table):\n            if len(self.selected_data) == 0:\n                self.Error.empty_selection()\n                self.clear()\n                return\n\n            self.selected_data_transformed = Table.from_table(\n                self.data.domain, self.selected_data)\n\n            sum_X = np_sp_sum(self.selected_data_transformed.X)\n            if sum_X == 0 or math.isnan(sum_X):\n                self.Error.no_words_overlap()\n                self.clear()\n            elif len(self.data) == len(self.selected_data):\n                self.Error.all_selected()\n                self.clear()\n            else:\n                self.apply()\n        else:\n            self.clear()\n\n    def clear(self):\n        self.sig_words.clear()\n        self.info_all.setText('Cluster words:')\n        self.info_sel.setText('Selected words:')\n        self.info_fil.setText('After filtering:')\n\n    def filter_enabled(self, b):\n        self.chb_p.setEnabled(b)\n        self.chb_fdr.setEnabled(b)\n        self.spin_p.setEnabled(b)\n        self.spin_fdr.setEnabled(b)\n\n    def filter_and_display(self):\n        self.spin_p.setEnabled(self.filter_by_p)\n        self.spin_fdr.setEnabled(self.filter_by_fdr)\n        self.sig_words.clear()\n\n        if self.selected_data_transformed is None:  # do nothing when no Data\n            return\n\n        count = 0\n        if self.words:\n            for word, pval, fval in zip(self.words, self.p_values, self.fdr_values):\n                if (not self.filter_by_p or pval <= self.filter_p_value) and \\\n                        (not self.filter_by_fdr or fval <= self.filter_fdr_value):\n                    it = EATreeWidgetItem(word, pval, fval, self.sig_words)\n                    self.sig_words.addTopLevelItem(it)\n                    count += 1\n\n        for i in range(len(self.cols)):\n            self.sig_words.resizeColumnToContents(i)\n\n        self.info_all.setText('Cluster words: {}'.format(len(self.selected_data_transformed.domain.attributes)))\n        self.info_sel.setText('Selected words: {}'.format(np.count_nonzero(np_sp_sum(self.selected_data_transformed.X, axis=0))))\n        if not self.filter_by_p and not self.filter_by_fdr:\n            self.info_fil.setText('After filtering:')\n            self.info_fil.setEnabled(False)\n        else:\n            self.info_fil.setEnabled(True)\n            self.info_fil.setText('After filtering: {}'.format(count))\n\n    def progress(self, p):\n        self.progressBarSet(p)\n\n    def apply(self):\n        self.clear()\n        self.progressBarInit()\n        self.filter_enabled(False)\n\n        self.words = [i.name for i in self.selected_data_transformed.domain.attributes]\n        self.p_values = hypergeom_p_values(self.data.X,\n                                           self.selected_data_transformed.X,\n                                           callback=self.progress)\n        self.fdr_values = false_discovery_rate(self.p_values)\n        self.filter_and_display()\n        self.filter_enabled(True)\n        self.progressBarFinished()\n\n\nfp = lambda score: \"%0.5f\" % score if score > 10e-3 else \"%0.1e\" % score\nfpt = lambda score: \"%0.9f\" % score if score > 10e-3 else \"%0.5e\" % score\n\n\nclass EATreeWidgetItem(QTreeWidgetItem):\n    def __init__(self, word, p_value, f_value, parent):\n        super().__init__(parent)\n        self.data = [word, p_value, f_value]\n        self.setText(0, word)\n        self.setText(1, fp(p_value))\n        self.setToolTip(1, fpt(p_value))\n        self.setText(2, fp(f_value))\n        self.setToolTip(2, fpt(f_value))\n\n    def __lt__(self, other):\n        col = self.treeWidget().sortColumn()\n        return self.data[col] < other.data[col]\n", "path": "orangecontrib/text/widgets/owwordenrichment.py"}], "after_files": [{"content": "import numpy as np\nfrom gensim import matutils\nfrom gensim.corpora import Dictionary\n\n\nclass BaseVectorizer:\n    \"\"\"Base class for vectorization objects. \"\"\"\n    name = NotImplemented\n\n    def transform(self, corpus, copy=True, source_dict=None):\n        \"\"\"Transforms a corpus to a new one with additional attributes. \"\"\"\n        if copy:\n            corpus = corpus.copy()\n\n        if not len(corpus.dictionary):\n            return corpus\n        else:\n            return self._transform(corpus, source_dict)\n\n    def _transform(self, corpus, source_dict):\n        raise NotImplementedError\n\n    def report(self):\n        \"\"\"Reports configuration items.\"\"\"\n        raise NotImplementedError\n\n    @staticmethod\n    def add_features(corpus, X, dictionary, compute_values=None, var_attrs=None):\n        order = np.argsort([dictionary[i] for i in range(len(dictionary))])\n        if compute_values is not None:\n            compute_values = np.array(compute_values)[order]\n\n        variable_attrs = {\n            'hidden': True,\n            'skip-normalization': True,\n        }\n        if isinstance(var_attrs, dict):\n            variable_attrs.update(var_attrs)\n\n        corpus.extend_attributes(X[:, order],\n                                 feature_names=(dictionary[i] for i in order),\n                                 var_attrs=variable_attrs,\n                                 compute_values=compute_values)\n        corpus.ngrams_corpus = matutils.Sparse2Corpus(X.T)\n", "path": "orangecontrib/text/vectorization/base.py"}, {"content": "from collections import OrderedDict\nfrom functools import partial\n\nimport numpy as np\nfrom gensim import corpora, models, matutils\nfrom sklearn.preprocessing import normalize\n\nfrom Orange.data.util import SharedComputeValue\nfrom orangecontrib.text.vectorization.base import BaseVectorizer\n\n\nclass BoWPreprocessTransform:\n    \"\"\"\n    Shared computation for transforming new data set into the classifiers's BoW domain.\n    This will run preprocessing as well as BoW transformation itself.\n    \"\"\"\n    def __init__(self, preprocessor, bow_vectorizer, dictionary):\n        self.preprocessor = preprocessor\n        self.bow_vectorizer = bow_vectorizer\n        self.dictionary = dictionary\n\n    def __call__(self, new_corpus):\n        new_corpus = self.preprocessor(new_corpus)\n        bow_corpus = self.bow_vectorizer.transform(new_corpus, copy=True, source_dict=self.dictionary)\n        # store name to indices mapping so BoWComputeValue can run faster\n        bow_corpus.feature_name_to_index = {attr.name: i for i, attr in enumerate(bow_corpus.domain.attributes)}\n        return bow_corpus\n\n\nclass BoWComputeValue(SharedComputeValue):\n    \"\"\"\n    Compute Value for Bow features. This enables applying a\n    classifier \u2014 that was trained on a BoW model \u2014 on new data.\n    \"\"\"\n    def __init__(self, name, compute_shared):\n        super().__init__(compute_shared)\n        self.name = name\n\n    def compute(self, data, shared_data):\n        ind = shared_data.feature_name_to_index[self.name]\n        return shared_data.X[:, ind]\n\n\nclass BowVectorizer(BaseVectorizer):\n    name = 'BoW Vectorizer'\n\n    COUNT = 'Count'\n    BINARY = 'Binary'\n    SUBLINEAR = 'Sublinear'\n    NONE = '(None)'\n    IDF = 'IDF'\n    SMOOTH = 'Smooth IDF'\n    L1 = 'L1 (Sum of elements)'\n    L2 = 'L2 (Euclidean)'\n\n    wlocals = OrderedDict((\n        (COUNT, lambda tf: tf),\n        (BINARY, lambda tf: int(tf > 0)),\n        (SUBLINEAR, lambda tf: 1 + np.log(tf)),\n    ))\n\n    wglobals = OrderedDict((\n        (NONE, lambda df, N: 1),\n        (IDF, lambda df, N: np.log(N/df)),\n        (SMOOTH, lambda df, N: np.log(1 + N/df)),\n    ))\n\n    norms = OrderedDict((\n        (NONE, None),\n        (L1, partial(normalize, norm='l1')),\n        (L2, partial(normalize, norm='l2')),\n    ))\n\n    def __init__(self, norm=NONE, wlocal=COUNT, wglobal=NONE):\n        self.norm = norm\n        self.wlocal = wlocal\n        self.wglobal = wglobal\n\n    def _transform(self, corpus, source_dict=None):\n        temp_corpus = list(corpus.ngrams_iterator(' ', include_postags=True))\n        dic = corpora.Dictionary(temp_corpus, prune_at=None) if not source_dict else source_dict\n        temp_corpus = [dic.doc2bow(doc) for doc in temp_corpus]\n        model = models.TfidfModel(temp_corpus, normalize=False,\n                                  wlocal=self.wlocals[self.wlocal],\n                                  wglobal=self.wglobals[self.wglobal])\n\n        X = matutils.corpus2csc(model[temp_corpus], dtype=np.float, num_terms=len(dic)).T\n        norm = self.norms[self.norm]\n        if norm:\n            X = norm(X)\n\n        # set compute values\n        shared_cv = BoWPreprocessTransform(corpus.used_preprocessor, self, dic)\n        cv = [BoWComputeValue(dic[i], shared_cv) for i in range(len(dic))]\n\n        self.add_features(corpus, X, dic, cv, var_attrs={'bow-feature': True})\n        return corpus\n\n    def report(self):\n        return (('Term Frequency', self.wlocal),\n                ('Document Frequency', self.wglobal),\n                ('Regularization', self.norm),)\n", "path": "orangecontrib/text/vectorization/bagofwords.py"}, {"content": "import numpy as np\nfrom AnyQt.QtWidgets import QTreeWidget, QTreeView, QTreeWidgetItem\n\nfrom Orange.data import Table, Domain\nfrom Orange.widgets import gui\nfrom Orange.widgets.settings import Setting\nfrom Orange.widgets.widget import OWWidget, Msg\nfrom orangecontrib.text import Corpus\nfrom orangecontrib.text.util import np_sp_sum\nfrom orangecontrib.text.stats import false_discovery_rate, hypergeom_p_values\n\n\nclass OWWordEnrichment(OWWidget):\n    # Basic widget info\n    name = \"Word Enrichment\"\n    description = \"Word enrichment analysis for selected documents.\"\n    icon = \"icons/SetEnrichment.svg\"\n    priority = 60\n\n    # Input/output\n    inputs = [(\"Selected Data\", Table, \"set_data_selected\"),\n              (\"Data\", Table, \"set_data\"),]\n    want_main_area = True\n\n    class Error(OWWidget.Error):\n        no_bow_features = Msg('No bag-of-words features!')\n        no_words_overlap = Msg('No words overlap!')\n        empty_selection = Msg('Selected data is empty!')\n        all_selected = Msg('All examples can not be selected!')\n\n    # Settings\n    filter_by_p = Setting(False)\n    filter_p_value = Setting(0.01)\n    filter_by_fdr = Setting(True)\n    filter_fdr_value = Setting(0.2)\n\n    def __init__(self):\n        super().__init__()\n\n        # Init data\n        self.data = None\n        self.selected_data = None\n        self.selected_data_transformed = None   # used for transforming the 'selected data' into the 'data' domain\n\n        self.words = []\n        self.p_values = []\n        self.fdr_values = []\n\n        # Info section\n        fbox = gui.widgetBox(self.controlArea, \"Info\")\n        self.info_all = gui.label(fbox, self, 'Cluster words:')\n        self.info_sel = gui.label(fbox, self, 'Selected words:')\n        self.info_fil = gui.label(fbox, self, 'After filtering:')\n\n        # Filtering settings\n        fbox = gui.widgetBox(self.controlArea, \"Filter\")\n        hbox = gui.widgetBox(fbox, orientation=0)\n\n        self.chb_p = gui.checkBox(hbox, self, \"filter_by_p\", \"p-value\",\n                                  callback=self.filter_and_display,\n                                  tooltip=\"Filter by word p-value\")\n        self.spin_p = gui.doubleSpin(hbox, self, 'filter_p_value',\n                                     1e-4, 1, step=1e-4, labelWidth=15,\n                                     callback=self.filter_and_display,\n                                     callbackOnReturn=True,\n                                     tooltip=\"Max p-value for word\")\n        self.spin_p.setEnabled(self.filter_by_p)\n\n        hbox = gui.widgetBox(fbox, orientation=0)\n        self.chb_fdr = gui.checkBox(hbox, self, \"filter_by_fdr\", \"FDR\",\n                                    callback=self.filter_and_display,\n                                    tooltip=\"Filter by word FDR\")\n        self.spin_fdr = gui.doubleSpin(hbox, self, 'filter_fdr_value',\n                                       1e-4, 1, step=1e-4, labelWidth=15,\n                                       callback=self.filter_and_display,\n                                       callbackOnReturn=True,\n                                       tooltip=\"Max p-value for word\")\n        self.spin_fdr.setEnabled(self.filter_by_fdr)\n        gui.rubber(self.controlArea)\n\n        # Word's list view\n        self.cols = ['Word', 'p-value', 'FDR']\n        self.sig_words = QTreeWidget()\n        self.sig_words.setColumnCount(len(self.cols))\n        self.sig_words.setHeaderLabels(self.cols)\n        self.sig_words.setSortingEnabled(True)\n        self.sig_words.setSelectionMode(QTreeView.ExtendedSelection)\n        self.sig_words.sortByColumn(2, 0)   # 0 is ascending order\n        for i in range(len(self.cols)):\n            self.sig_words.resizeColumnToContents(i)\n        self.mainArea.layout().addWidget(self.sig_words)\n\n    def set_data(self, data=None):\n        self.data = data\n\n    def set_data_selected(self, data=None):\n        self.selected_data = data\n\n    def handleNewSignals(self):\n        self.check_data()\n\n    def get_bow_domain(self):\n        domain = self.data.domain\n        return Domain(\n            attributes=[a for a in domain.attributes\n                        if a.attributes.get('bow-feature', False)],\n            class_vars=domain.class_vars,\n            metas=domain.metas,\n            source=domain)\n\n    def check_data(self):\n        self.Error.clear()\n        if isinstance(self.data, Table) and \\\n                isinstance(self.selected_data, Table):\n            if len(self.selected_data) == 0:\n                self.Error.empty_selection()\n                self.clear()\n                return\n\n            # keep only BoW features\n            bow_domain = self.get_bow_domain()\n            if len(bow_domain.attributes) == 0:\n                self.Error.no_bow_features()\n                self.clear()\n                return\n            self.data = Corpus.from_table(bow_domain, self.data)\n            self.selected_data_transformed = Corpus.from_table(bow_domain, self.selected_data)\n\n            if np_sp_sum(self.selected_data_transformed.X) == 0:\n                self.Error.no_words_overlap()\n                self.clear()\n            elif len(self.data) == len(self.selected_data):\n                self.Error.all_selected()\n                self.clear()\n            else:\n                self.apply()\n        else:\n            self.clear()\n\n    def clear(self):\n        self.sig_words.clear()\n        self.info_all.setText('Cluster words:')\n        self.info_sel.setText('Selected words:')\n        self.info_fil.setText('After filtering:')\n\n    def filter_enabled(self, b):\n        self.chb_p.setEnabled(b)\n        self.chb_fdr.setEnabled(b)\n        self.spin_p.setEnabled(b)\n        self.spin_fdr.setEnabled(b)\n\n    def filter_and_display(self):\n        self.spin_p.setEnabled(self.filter_by_p)\n        self.spin_fdr.setEnabled(self.filter_by_fdr)\n        self.sig_words.clear()\n\n        if self.selected_data_transformed is None:  # do nothing when no Data\n            return\n\n        count = 0\n        if self.words:\n            for word, pval, fval in zip(self.words, self.p_values, self.fdr_values):\n                if (not self.filter_by_p or pval <= self.filter_p_value) and \\\n                        (not self.filter_by_fdr or fval <= self.filter_fdr_value):\n                    it = EATreeWidgetItem(word, pval, fval, self.sig_words)\n                    self.sig_words.addTopLevelItem(it)\n                    count += 1\n\n        for i in range(len(self.cols)):\n            self.sig_words.resizeColumnToContents(i)\n\n        self.info_all.setText('Cluster words: {}'.format(len(self.selected_data_transformed.domain.attributes)))\n        self.info_sel.setText('Selected words: {}'.format(np.count_nonzero(np_sp_sum(self.selected_data_transformed.X, axis=0))))\n        if not self.filter_by_p and not self.filter_by_fdr:\n            self.info_fil.setText('After filtering:')\n            self.info_fil.setEnabled(False)\n        else:\n            self.info_fil.setEnabled(True)\n            self.info_fil.setText('After filtering: {}'.format(count))\n\n    def progress(self, p):\n        self.progressBarSet(p)\n\n    def apply(self):\n        self.clear()\n        self.progressBarInit()\n        self.filter_enabled(False)\n\n        self.words = [i.name for i in self.selected_data_transformed.domain.attributes]\n        self.p_values = hypergeom_p_values(self.data.X,\n                                           self.selected_data_transformed.X,\n                                           callback=self.progress)\n        self.fdr_values = false_discovery_rate(self.p_values)\n        self.filter_and_display()\n        self.filter_enabled(True)\n        self.progressBarFinished()\n\n\nfp = lambda score: \"%0.5f\" % score if score > 10e-3 else \"%0.1e\" % score\nfpt = lambda score: \"%0.9f\" % score if score > 10e-3 else \"%0.5e\" % score\n\n\nclass EATreeWidgetItem(QTreeWidgetItem):\n    def __init__(self, word, p_value, f_value, parent):\n        super().__init__(parent)\n        self.data = [word, p_value, f_value]\n        self.setText(0, word)\n        self.setText(1, fp(p_value))\n        self.setToolTip(1, fpt(p_value))\n        self.setText(2, fp(f_value))\n        self.setToolTip(2, fpt(f_value))\n\n    def __lt__(self, other):\n        col = self.treeWidget().sortColumn()\n        return self.data[col] < other.data[col]\n", "path": "orangecontrib/text/widgets/owwordenrichment.py"}]}