1from AnyQt.QtWidgets import QTableView, QGridLayout, QWidget 2from AnyQt.QtCore import Qt, QSize 3 4from Orange.data import Table, Domain 5from Orange.widgets.settings import Setting, ContextSetting, PerfectDomainContextHandler 6from Orange.widgets.utils.itemmodels import TableModel 7from Orange.widgets.widget import OWWidget, Input, Output 8from Orange.widgets import gui 9from orangecontrib.datafusion.models import Relation 10from skfusion import fusion 11 12 13class OWTableToRelation(OWWidget): 14 name = "Table to Relation" 15 description = "Convert data table to relation matrix. Label matrix axis." 16 priority = 50000 17 icon = "icons/TableToRelation.svg" 18 19 class Inputs: 20 data = Input("Data", Table) 21 22 class Outputs: 23 relation = Output("Relation", Relation) 24 25 settingsHandler = PerfectDomainContextHandler() 26 27 data = None 28 29 relation_name = ContextSetting("") 30 transpose = ContextSetting(False) 31 32 row_type = ContextSetting("") 33 selected_meta = ContextSetting(0) 34 row_names = None 35 36 col_type = ContextSetting("") 37 col_names = None 38 39 auto_commit = Setting(True) 40 41 def __init__(self): 42 super().__init__() 43 44 self.model = None 45 self.view = None 46 self.row_names_combo = None 47 self.icons = gui.attributeIconDict 48 self.populate_control_area() 49 self.populate_main_area() 50 51 def populate_control_area(self): 52 rel = gui.widgetBox(self.controlArea, "Relation") 53 gui.lineEdit(rel, self, "relation_name", "Name", callbackOnType=True, callback=self.apply) 54 gui.checkBox(rel, self, "transpose", "Transpose", callback=self.apply) 55 56 col = gui.widgetBox(self.controlArea, "Column") 57 gui.lineEdit(col, self, "col_type", "Object Type", callbackOnType=True, callback=self.apply) 58 59 row = gui.widgetBox(self.controlArea, "Row") 60 gui.lineEdit(row, self, "row_type", "Object Type", callbackOnType=True, callback=self.apply) 61 self.row_names_combo = gui.comboBox(row, self, "selected_meta", label="Object Names", 62 callback=self.update_row_names) 63 64 gui.rubber(self.controlArea) 65 gui.auto_commit(self.controlArea, self, "auto_commit", "Send", 66 checkbox_label='Auto-send', 67 orientation='vertical') 68 69 def populate_main_area(self): 70 grid = QWidget() 71 grid.setLayout(QGridLayout(grid)) 72 self.mainArea.layout().addWidget(grid) 73 74 col_type = gui.label(None, self, '%(col_type)s') 75 76 grid.layout().addWidget(col_type, 0, 1) 77 grid.layout().setAlignment(col_type, Qt.AlignHCenter) 78 79 row_type = gui.label(None, self, '%(row_type)s') 80 grid.layout().addWidget(row_type, 1, 0) 81 grid.layout().setAlignment(row_type, Qt.AlignVCenter) 82 83 self.view = QTableView() 84 self.model = None 85 grid.layout().addWidget(self.view, 1, 1) 86 87 def sizeHint(self): 88 return QSize(800, 500) 89 90 @Inputs.data 91 def set_data(self, data): 92 self.closeContext() 93 self.data = data 94 if data is not None: 95 self.init_attr_values(data.domain.metas) 96 self.openContext(self.data) 97 self.col_names = [str(a.name) for a in data.domain.attributes] 98 if hasattr(data, 'col_type'): 99 self.col_type = data.col_type 100 else: 101 self.init_attr_values(()) 102 self.update_preview() 103 self.update_row_names() 104 self.unconditional_commit() 105 106 def init_attr_values(self, candidates): 107 self.col_type = "" 108 self.col_names = None 109 110 if candidates: 111 self.row_type = candidates[0].name 112 self.selected_meta = 1 113 else: 114 self.row_type = "" 115 self.selected_meta = 0 116 self.row_names = None 117 118 self.row_names_combo.clear() 119 self.row_names_combo.addItem('(None)') 120 for var in candidates: 121 self.row_names_combo.addItem(self.icons[var], var.name) 122 self.row_names_combo.setCurrentIndex(self.selected_meta) 123 124 def update_row_names(self): 125 if self.selected_meta: 126 self.row_names = list(self.data[:, -self.selected_meta].metas.flatten()) 127 else: 128 self.row_names = None 129 130 if self.model: 131 self.model.headerDataChanged.emit( 132 Qt.Vertical, 0, self.model.rowCount() - 1) 133 self.commit() 134 135 def update_preview(self): 136 this = self 137 138 class MyTableModel(TableModel): 139 def headerData(self, section, orientation, role): 140 if orientation == Qt.Vertical and role == Qt.DisplayRole: 141 if this.row_names: 142 return this.row_names[section] 143 else: 144 return super().headerData(section, orientation, role) 145 146 if self.data: 147 domain = Domain(self.data.domain.attributes) 148 preview_data = Table(domain, self.data) 149 self.model = MyTableModel(preview_data) 150 else: 151 self.model = None 152 self.view.setModel(self.model) 153 154 def apply(self): 155 self.commit() 156 157 def commit(self): 158 if self.data: 159 domain = self.data.domain 160 metadata_cols = list(domain.class_vars) + list(domain.metas) 161 metadata = [{var: var.to_val(value) for var, value in zip(metadata_cols, values.list)} 162 for values in self.data[:, metadata_cols]] 163 164 if self.transpose: 165 relation = fusion.Relation( 166 self.data.X.T, name=self.relation_name, 167 row_type=fusion.ObjectType(self.col_type or 'Unknown'), row_names=self.col_names, 168 col_type=fusion.ObjectType(self.row_type or 'Unknown'), col_names=self.row_names, 169 col_metadata=metadata) 170 else: 171 relation = fusion.Relation( 172 self.data.X, name=self.relation_name, 173 row_type=fusion.ObjectType(self.row_type or 'Unknown'), row_names=self.row_names, 174 row_metadata=metadata, 175 col_type=fusion.ObjectType(self.col_type or 'Unknown'), col_names=self.col_names, 176 ) 177 self.Outputs.relation.send(Relation(relation)) 178 179 180if __name__ == '__main__': 181 from AnyQt.QtWidgets import QApplication 182 app = QApplication([]) 183 ow = OWTableToRelation() 184 ow.set_data(Table('zoo')) 185 ow.show() 186 app.exec() 187 ow.saveSettings() 188