def __show_model_learned(self, cv, bpt, lbda, a): dialog = InferenceDialog(self) dialog.setModal(True) self.connect(dialog, QtCore.SIGNAL("accepted()"), self.on_model_learned_accepted) dialog.show() model = ElectreTri(self.criteria, cv, bpt, lbda, self.cat_profiles) worst = self.pt.get_worst(self.criteria) best = self.pt.get_best(self.criteria) criteria_order = [c.id for c in self.criteria] graph = QGraphicsSceneEtri(model, worst, best, self.graph_plot.size(), criteria_order) dialog.graph_model.setScene(graph) dialog.label_lambda.setText("Lambda: %s" % str(lbda)) a_incomp = Alternatives([aref for aref in self.a_ref if aref.id not in a.keys()]) pt_incomp = PerformanceTable([ap for ap in self.pt_ref if ap.id in a_incomp.keys()]) pt_comp = PerformanceTable([ap for ap in self.pt_ref if ap.id in a.keys()]) dialog.table_comp.add_criteria(self.criteria) dialog.table_comp.add_pt(a, pt_comp) dialog.table_incomp.add_criteria(self.criteria) dialog.table_incomp.add_pt(a_incomp, pt_incomp)
def __generate_initial_model(self): crit_min = {} crit_max = {} for altp in self.pt: for crit in self.criteria: d = crit.direction if crit_min.has_key(crit.id) is False: crit_min[crit.id] = altp.performances[crit.id] elif crit_min[crit.id]*d > altp(crit.id)*d: crit_min[crit.id] = altp.performances[crit.id] if crit_max.has_key(crit.id) is False: crit_max[crit.id] = altp.performances[crit.id] elif crit_max[crit.id]*d < altp(crit.id)*d: crit_max[crit.id] = altp.performances[crit.id] self.cv = CriteriaValues() b1 = AlternativePerformances('b1', {}) for crit in self.criteria: b1.performances[crit.id] = (crit_max[crit.id] - crit_min[crit.id]) / 2 cv = CriterionValue(crit.id, 1) self.cv.append(cv) self.balternatives = Alternatives([Alternative('b1', 'b1')]) self.bpt = PerformanceTable([b1]) self.cbox_mrsort.setChecked(True) self.cbox_noveto.setChecked(True) # Categories Profiles self.categories = generate_categories(len(self.bpt) + 1, prefix = "") self.cat_profiles = generate_categories_profiles(self.categories) self.lbda = 0.75
class criteria_layer(QgsVectorLayer): def __init__(self, layer): self.layer = layer self.criteria = None self.alternatives = None self.pt = None self.get_criteria() self.get_alternatives_and_pt() def get_criteria(self): provider = self.layer.dataProvider() fields = provider.fields() self.criteria = Criteria([]) for field in fields: ftype = field.type() if (ftype != QVariant.Bool) and (ftype != QVariant.Double) \ and (ftype != QVariant.Int) \ and (ftype != QVariant.LongLong): continue name = str(field.name()) crit = Criterion(name, name) self.criteria.append(crit) def get_alternatives_and_pt(self): provider = self.layer.dataProvider() self.alternatives = Alternatives([]) self.pt = PerformanceTable([]) for feat in provider.getFeatures(): featid = str(feat.id()) perfs = {} for criterion in self.criteria: try: perfs[criterion.id] = float(feat[criterion.id]) except: perfs[criterion.id] = feat[criterion.id].toDouble()[0] self.alternatives.append(Alternative(featid, featid)) self.pt.append(AlternativePerformances(featid, perfs)) def get_features_ids(self, aids): provider = self.layer.dataProvider() self.alternatives = Alternatives([]) self.pt = PerformanceTable([]) features = [] for feat in provider.getFeatures(): featid = str(feat.id()) if featid in aids: features.append(feat.id()) return features
def get_features_ids(self, aids): provider = self.layer.dataProvider() self.alternatives = Alternatives([]) self.pt = PerformanceTable([]) features = [] for feat in provider.getFeatures(): featid = str(feat.id()) if featid in aids: features.append(feat.id()) return features
def on_button_chooseassign_pressed(self): items = [c.id for c in self.criteria if c.disabled is True] if len(items) < 1: QtGui.QMessageBox.information(None, "Error", "No assignment column") return item, ok = QtGui.QInputDialog.getItem(self, "Select assignments column", "Column:", items, 0, False) if ok is False: return try: cid = item.toString() except: cid = str(item) ncat = len(self.bpt) + 1 pt, aa = PerformanceTable(), AlternativesAssignments() for ap in self.pt: perf = int(ap.performances[cid]) if perf > 0 and perf < (ncat + 1): pt.append(ap) aa.append(AlternativeAssignment(ap.id, str(perf))) if len(pt) < 1: QtGui.QMessageBox.information(None, "Error", "No assignments examples found") return self.a_ref = Alternatives([Alternative(a.id) for a in aa]) self.pt_ref = pt self.aa_ref = aa a = Alternatives([Alternative(aid) for aid in pt.keys()]) self.table_refs.reset_table() self.table_refs.add_criteria(self.criteria) self.table_refs.add_pt(a, pt, False) self.__generate_category_colors() self.table_refs.add_assignments(aa, self.category_colors, True) self.button_zoom.setEnabled(True) self.button_show.setEnabled(True) self.button_infer.setEnabled(True)
def __fill_model_tables(self): self.layer_loaded = False self.table_criteria.add_criteria(self.criteria, self.cv) self.table_prof.add_criteria(self.criteria) self.table_indiff.add_criteria(self.criteria) self.table_pref.add_criteria(self.criteria) self.table_veto.add_criteria(self.criteria) self.table_prof.add_pt(self.balternatives, self.bpt) self.label_ncategories.setText("%d" % (len(self.bpt) + 1)) if self.same_pqv_thresholds_for_all_profiles() is True: self.cbox_samethresholds.setChecked(True) balternatives = Alternatives([Alternative('b')]) else: balternatives = self.balternatives if self.qpt is None and self.ppt is None: self.cbox_mrsort.setChecked(True) else: self.table_indiff.add_pt(balternatives, self.qpt) self.table_pref.add_pt(balternatives, self.ppt) if self.vpt is None: self.cbox_noveto.setChecked(True) else: self.table_veto.add_pt(balternatives, self.vpt) self.spinbox_cutlevel.setValue(self.lbda) self.__update_graph() self.layer_loaded = True
def get_alternatives_and_pt(self): provider = self.layer.dataProvider() self.alternatives = Alternatives([]) self.pt = PerformanceTable([]) for feat in provider.getFeatures(): featid = str(feat.id()) perfs = {} for criterion in self.criteria: try: perfs[criterion.id] = float(feat[criterion.id]) except: perfs[criterion.id] = feat[criterion.id].toDouble()[0] self.alternatives.append(Alternative(featid, featid)) self.pt.append(AlternativePerformances(featid, perfs))
class main_window(QtGui.QDialog, Ui_main_window): def __init__(self, iface = None, layer = None): QtGui.QDialog.__init__(self) Ui_main_window.__init__(self) self.setupUi(self) self.setWindowFlags(QtCore.Qt.Window) self.iface = iface if iface is not None: self.__update_layer_list(iface.mapCanvas()) elif layer: self.layer = criteria_layer(layer) self.__loadlayer() self.__reset_buttons() self.button_show.setVisible(False) self.button_zoom.setVisible(False) self.table_criteria.connect(self.table_criteria, QtCore.SIGNAL("criterion_state_changed"), self.__criterion_state_changed) def closeEvent(self, event): val = QtGui.QMessageBox.question(self, "ELECTRE TRI", "Close ELECTRE TRI?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if val == QtGui.QMessageBox.No: event.ignore() def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Escape: self.close() def __update_layer_list(self, map_canvas): if map_canvas == None: return for i in range(map_canvas.layerCount()): layer = map_canvas.layer(i) self.combo_layer.addItem(layer.name()) def __check_params_consistency(self, bpt, qpt, ppt, vpt): if len(bpt) < 1: raise Exception("Preference table has an invalid size") for i in range(1, len(bpt) + 1): altid = "b%d" % i if altid not in bpt.keys(): raise Exception("Invalid profiles performance table") if qpt and len(qpt) > 1 and altid not in qpt: raise Exception("Invalid indifference performance table") if ppt and len(ppt) > 1 and altid not in ppt: raise Exception("Invalid preference performance table") if vpt and len(vpt) > 1 and altid not in vpt: raise Exception("Invalid veto performance table") if qpt and len(qpt) == 1 and "b" not in qpt: raise Exception("Invalid indifference performance table") if ppt and len(ppt) == 1 and "b" not in ppt: raise Exception("Invalid preference performance table") if vpt and len(vpt) == 1 and "b" not in vpt: raise Exception("Invalid veto performance table") def __load_from_xmcda(self, xmcda_file): tree = ElementTree.parse(xmcda_file) root = tree.getroot() # ElementTree.dump(root) xmcda_formatversion = root.find('.//formatversion') xmcda_crit = root.find('.//criteria') xmcda_critval = root.find('.//criteriaValues') xmcda_b = root.find('.//alternatives') xmcda_pt = root.findall('.//performanceTable') xmcda_lbda = root.find('.//methodParameters/parameter/value/real') # Update criteria direction criteria = Criteria().from_xmcda(xmcda_crit) for c in criteria: if c.id in self.criteria: self.criteria[c.id].disabled = c.disabled self.criteria[c.id].direction = c.direction # Remove criteria values that are not in the vector layer cvs = CriteriaValues() cvs.from_xmcda(xmcda_critval) for cv in cvs: if cv.id not in self.criteria: cvs.remove(cv.id) for c in self.criteria: # Disable criteria for which there are no weights if c.id not in cvs: c.disabled = True cvs.append(CriterionValue(c.id, 0)) balternatives = Alternatives() balternatives.from_xmcda(xmcda_b) bpt = PerformanceTable() qpt, ppt, vpt = None, None, None for xmcda in xmcda_pt: if xmcda.get('id') is None: bpt.from_xmcda(xmcda) for bp, c in product(bpt, self.criteria.get_active()): perfs = bp.performances if c.id not in perfs or perfs[c.id] is None: perfs[c.id] = 0 elif xmcda.get('id') == 'q': qpt = PerformanceTable(id = 'q') qpt.from_xmcda(xmcda) elif xmcda.get('id') == 'p': ppt = PerformanceTable(id = 'p') ppt.from_xmcda(xmcda) elif xmcda.get('id') == 'v': vpt = PerformanceTable(id = 'v') vpt.from_xmcda(xmcda) if qpt is not None and len(qpt) == 0 and len(ppt) > 0: qpt = ppt.copy() qpt.id = "q" if ppt is not None and len(ppt) == 0 and len(qpt) > 0: ppt = qpt.copy() ppt.id = "p" lbda = float(xmcda_lbda.text) self.__check_params_consistency(bpt, qpt, ppt, vpt) # Everything is fine self.cv = cvs self.balternatives = balternatives self.bpt = bpt self.qpt = qpt self.ppt = ppt self.vpt = vpt self.lbda = lbda # Categories Profiles self.categories = generate_categories(len(self.bpt) + 1, prefix = "") self.cat_profiles = generate_categories_profiles(self.categories) def __generate_initial_model(self): crit_min = {} crit_max = {} for altp in self.pt: for crit in self.criteria: d = crit.direction if crit_min.has_key(crit.id) is False: crit_min[crit.id] = altp.performances[crit.id] elif crit_min[crit.id]*d > altp(crit.id)*d: crit_min[crit.id] = altp.performances[crit.id] if crit_max.has_key(crit.id) is False: crit_max[crit.id] = altp.performances[crit.id] elif crit_max[crit.id]*d < altp(crit.id)*d: crit_max[crit.id] = altp.performances[crit.id] self.cv = CriteriaValues() b1 = AlternativePerformances('b1', {}) for crit in self.criteria: b1.performances[crit.id] = (crit_max[crit.id] - crit_min[crit.id]) / 2 cv = CriterionValue(crit.id, 1) self.cv.append(cv) self.balternatives = Alternatives([Alternative('b1', 'b1')]) self.bpt = PerformanceTable([b1]) self.cbox_mrsort.setChecked(True) self.cbox_noveto.setChecked(True) # Categories Profiles self.categories = generate_categories(len(self.bpt) + 1, prefix = "") self.cat_profiles = generate_categories_profiles(self.categories) self.lbda = 0.75 def on_button_loadlayer_pressed(self): index = self.combo_layer.currentIndex() map_canvas = self.iface.mapCanvas() try: self.layer = criteria_layer(map_canvas.layer(index)) self.__clear_tables() self.button_zoom.setEnabled(False) self.button_show.setEnabled(False) self.button_infer.setEnabled(False) self.__loadlayer() self.__reset_buttons() except: traceback.print_exc(sys.stderr) QtGui.QMessageBox.information(None, "Error", "Cannot load specified layer") return def __clear_tables(self): self.table_criteria.reset_table() self.table_prof.reset_table() self.table_indiff.reset_table() self.table_pref.reset_table() self.table_veto.reset_table() self.table_refs.reset_table() def same_pqv_thresholds_for_all_profiles(self): if self.ppt is not None: p = set(self.ppt.values()) if len(p) > 1: return False if self.qpt is not None: q = set(self.qpt.values()) if len(q) > 1: return False if self.vpt is not None: v = set(self.vpt.values()) if len(v) > 1: return False return True def on_cbox_noveto_stateChanged(self, state): if state == QtCore.Qt.Checked: index = self.tab_thresholds.indexOf(self.tab_veto) self.tab_thresholds.removeTab(index) self.table_veto.remove_all() self.vpt = None else: self.tab_thresholds.insertTab(2, self.tab_veto, "Veto") self.vpt = PerformanceTable(id = 'v') if self.cbox_samethresholds.isChecked() is True: self.set_same_threshold_for_all_profiles(self.vpt, self.table_veto) else: self.set_one_threshold_per_profile(self.vpt, self.table_veto) def on_cbox_mrsort_stateChanged(self, state): if state == QtCore.Qt.Checked: index = self.tab_thresholds.indexOf(self.tab_indiff) self.tab_thresholds.removeTab(index) intex = self.tab_thresholds.indexOf(self.tab_pref) self.tab_thresholds.removeTab(index) self.table_indiff.remove_all() self.table_pref.remove_all() self.qpt = None self.ppt = None else: self.tab_thresholds.insertTab(0, self.tab_indiff, "Indifference") self.tab_thresholds.insertTab(1, self.tab_pref, "Preference") self.qpt = PerformanceTable(id = 'q') self.ppt = PerformanceTable(id = 'p') if self.cbox_samethresholds.isChecked() is True: self.set_same_threshold_for_all_profiles(self.qpt, self.table_indiff) self.set_same_threshold_for_all_profiles(self.ppt, self.table_pref) else: self.set_one_threshold_per_profile(self.qpt, self.table_indiff) self.set_one_threshold_per_profile(self.ppt, self.table_pref) def set_same_threshold_for_all_profiles(self, pt, table): if pt is None or self.layer_loaded is False: return table.remove_all() if pt and len(pt) > 0: bp = next(pt.itervalues()) else: bp = AlternativePerformances('b', {c.id: None \ for c in self.criteria}) bp.id = 'b' pt.clear() pt.append(bp) table.add(Alternative('b'), bp) def set_one_threshold_per_profile(self, pt, table): if pt is None or self.layer_loaded is False: return table.remove_all() if pt and len(pt) > 0: bp = next(pt.itervalues()) else: bp = AlternativePerformances('b', {c.id: None \ for c in self.criteria}) pt.clear() for b in self.balternatives: bp2 = bp.copy() bp2.id = b.id pt.append(bp2) table.add_pt(self.balternatives, pt) def on_cbox_samethresholds_stateChanged(self, state): if state == QtCore.Qt.Checked: self.set_same_threshold_for_all_profiles(self.qpt, self.table_indiff) self.set_same_threshold_for_all_profiles(self.ppt, self.table_pref) self.set_same_threshold_for_all_profiles(self.vpt, self.table_veto) else: self.set_one_threshold_per_profile(self.qpt, self.table_indiff) self.set_one_threshold_per_profile(self.ppt, self.table_pref) self.set_one_threshold_per_profile(self.vpt, self.table_veto) def __update_graph(self): lbda = self.spinbox_cutlevel.value() model = ElectreTri(self.criteria, self.cv, self.bpt, lbda, self.cat_profiles, self.vpt, self.qpt, self.ppt) worst = self.pt.get_worst(self.criteria) best = self.pt.get_best(self.criteria) criteria_order = [c.id for c in self.criteria] graph = QGraphicsSceneEtri(model, worst, best, self.graph_plot.size(), criteria_order) self.graph_plot.setScene(graph) self.graph_plot2.setScene(graph) def __loadlayer(self): # References to map criteria and alternatives self.criteria = self.layer.criteria self.alternatives = self.layer.alternatives self.pt = self.layer.pt try: xmcda_file = os.path.splitext(str(self.layer.layer.source()))[0] \ + ".xmcda" self.__load_from_xmcda(xmcda_file) except: traceback.print_exc(sys.stderr) self.__generate_initial_model() self.__fill_model_tables() def __fill_model_tables(self): self.layer_loaded = False self.table_criteria.add_criteria(self.criteria, self.cv) self.table_prof.add_criteria(self.criteria) self.table_indiff.add_criteria(self.criteria) self.table_pref.add_criteria(self.criteria) self.table_veto.add_criteria(self.criteria) self.table_prof.add_pt(self.balternatives, self.bpt) self.label_ncategories.setText("%d" % (len(self.bpt) + 1)) if self.same_pqv_thresholds_for_all_profiles() is True: self.cbox_samethresholds.setChecked(True) balternatives = Alternatives([Alternative('b')]) else: balternatives = self.balternatives if self.qpt is None and self.ppt is None: self.cbox_mrsort.setChecked(True) else: self.table_indiff.add_pt(balternatives, self.qpt) self.table_pref.add_pt(balternatives, self.ppt) if self.vpt is None: self.cbox_noveto.setChecked(True) else: self.table_veto.add_pt(balternatives, self.vpt) self.spinbox_cutlevel.setValue(self.lbda) self.__update_graph() self.layer_loaded = True def __reset_buttons(self): self.button_add_profile.setEnabled(True) self.button_del_profile.setEnabled(True) self.button_generate.setEnabled(True) self.button_chooseassign.setEnabled(True) self.button_loadxmcda.setEnabled(True) self.button_savexmcda.setEnabled(True) self.button_infer.setEnabled(False) self.button_zoom.setEnabled(False) self.button_show.setEnabled(False) def __criterion_state_changed(self, criterion): self.table_prof.disable_criterion(criterion) self.table_indiff.disable_criterion(criterion) self.table_pref.disable_criterion(criterion) self.table_veto.disable_criterion(criterion) def on_button_add_profile_pressed(self): name = "b%d" % (len(self.bpt) + 1) b = Alternative(name, name) ap = self.bpt["b%d" % len(self.bpt)].copy() ap.id = name self.balternatives.append(b) self.bpt.append(ap) self.table_prof.add(b, ap) if self.cbox_samethresholds.isChecked() is False: if self.cbox_mrsort.isChecked() is False: qp = self.qpt["b%d" % len(self.qpt)].copy() pp = self.ppt["b%d" % len(self.ppt)].copy() qp.id, pp.id = name, name self.qpt.append(qp) self.ppt.append(pp) self.table_indiff.add(b, qp) self.table_pref.add(b, pp) if self.cbox_noveto.isChecked() is False: vp = self.vpt["b%d" % len(self.vpt)].copy() vp.id = name self.vpt.append(vp) self.table_veto.add(b, vp) self.label_ncategories.setText("%d" % (len(self.bpt) + 1)) self.categories = generate_categories(len(self.bpt) + 1, prefix = "") self.cat_profiles = generate_categories_profiles(self.categories) def on_button_del_profile_pressed(self): if len(self.bpt) == 1: QtGui.QMessageBox.information(None, "Error", "Molel should have at least " \ "2 categories") return name = "b%d" % len(self.bpt) b = self.balternatives[name] self.table_prof.remove(b.id) self.balternatives.remove(b.id) self.bpt.remove(b.id) if self.cbox_samethresholds.isChecked() is False: self.table_indiff.remove(b.id) self.table_pref.remove(b.id) self.table_veto.remove(b.id) self.qpt.remove(b.id) self.ppt.remove(b.id) self.vpt.remove(b.id) self.label_ncategories.setText("%d" % (len(self.bpt) + 1)) self.categories = generate_categories(len(self.bpt) + 1, prefix = "") self.cat_profiles = generate_categories_profiles(self.categories) self.__update_graph() def on_button_generate_pressed(self): active_criteria = self.criteria.get_active() if self.bpt.is_complete(active_criteria.keys()) is False: QtGui.QMessageBox.information(None, "Error", "Profile table is incomplete") return if self.cbox_samethresholds.isChecked() is True: if self.cbox_mrsort.isChecked() is False: qpt = PerformanceTable(id = 'q') ppt = PerformanceTable(id = 'p') for i in range(len(self.bpt)): qp = next(self.qpt.itervalues()).copy() pp = next(self.ppt.itervalues()).copy() name = "b%d" % (i + 1) qp.id, pp.id = name, name qpt.append(qp), ppt.append(pp) else: qpt = None ppt = None if self.cbox_noveto.isChecked() is False: vpt = PerformanceTable(id = 'v') for i in range(len(self.bpt)): vp = next(self.vpt.itervalues()).copy() vp.id = "b%d" % (i + 1) vpt.append(vp) else: vpt = None else: qpt = self.qpt ppt = self.ppt vpt = self.vpt lbda = self.spinbox_cutlevel.value() model = ElectreTri(self.criteria, self.cv, self.bpt, lbda, self.cat_profiles, vpt, qpt, ppt) if self.combo_procedure.currentIndex() == COMBO_PROC_OPTIMIST: aa = model.optimist(self.pt) else: aa = model.pessimist(self.pt) (f, encoding) = saveDialog(self, "Save output shapefile", "Shapefiles (*.shp)", "shp", QtGui.QFileDialog.AcceptSave) if f is None or encoding is None: return generate_decision_map(self.layer.layer, aa, f, encoding) self.save_to_xmcda(os.path.splitext(f)[0] + ".xmcda") if self.iface is not None: addtocDialog(self, f, len(model.bpt)) def on_table_prof_cellChanged(self, row, col): if self.layer_loaded is False: return self.__update_graph() def lambda_to_xmcda(self, lbda): root = ElementTree.Element('methodParameters') xmcda = ElementTree.SubElement(root, 'parameter') xmcda.set('name', 'lambda') xmcda = ElementTree.SubElement(xmcda, 'value') xmcda = ElementTree.SubElement(xmcda, 'real') xmcda.text = str(lbda) return root def on_button_savexmcda_pressed(self): (f, encoding) = saveDialog(self, "Save MCDA model", "XMCDA files (*.xmcda)", "xmcda", QtGui.QFileDialog.AcceptSave) if f is None: return self.save_to_xmcda(f) def save_to_xmcda(self, filepath): xmcda = ElementTree.Element("{%s}XMCDA" % XMCDA_URL) xmcda.append(self.criteria.to_xmcda()) xmcda.append(self.cv.to_xmcda()) xmcda.append(self.balternatives.to_xmcda()) xmcda.append(self.bpt.to_xmcda()) xmcda.append(self.lambda_to_xmcda(self.spinbox_cutlevel.value())) if self.qpt: xmcda.append(self.qpt.to_xmcda()) if self.ppt: xmcda.append(self.ppt.to_xmcda()) if self.vpt: xmcda.append(self.vpt.to_xmcda()) f = open(filepath, "w") buf = ElementTree.tostring(xmcda, encoding="UTF-8", method="xml") f.write(buf) f.close() def on_button_loadxmcda_pressed(self): (f, encoding) = saveDialog(self, "Load MCDA model", "XMCDA files (*.xmcda)", "xmcda", QtGui.QFileDialog.AcceptOpen) if f is None: return try: self.__load_from_xmcda(f) except: traceback.print_exc(sys.stderr) QtGui.QMessageBox.information(None, "Error", "Cannot load XMCDA data") return self.__clear_tables() self.button_zoom.setEnabled(False) self.button_show.setEnabled(False) self.button_infer.setEnabled(False) self.__fill_model_tables() def __generate_category_colors(self): self.category_colors = {} ncat = len(self.bpt) + 1 for i in range(1, ncat + 1): color = QtGui.QColor(0, 255 - 220 * i / ncat, 0) self.category_colors[str(i)] = color def on_button_chooseassign_pressed(self): items = [c.id for c in self.criteria if c.disabled is True] if len(items) < 1: QtGui.QMessageBox.information(None, "Error", "No assignment column") return item, ok = QtGui.QInputDialog.getItem(self, "Select assignments column", "Column:", items, 0, False) if ok is False: return try: cid = item.toString() except: cid = str(item) ncat = len(self.bpt) + 1 pt, aa = PerformanceTable(), AlternativesAssignments() for ap in self.pt: perf = int(ap.performances[cid]) if perf > 0 and perf < (ncat + 1): pt.append(ap) aa.append(AlternativeAssignment(ap.id, str(perf))) if len(pt) < 1: QtGui.QMessageBox.information(None, "Error", "No assignments examples found") return self.a_ref = Alternatives([Alternative(a.id) for a in aa]) self.pt_ref = pt self.aa_ref = aa a = Alternatives([Alternative(aid) for aid in pt.keys()]) self.table_refs.reset_table() self.table_refs.add_criteria(self.criteria) self.table_refs.add_pt(a, pt, False) self.__generate_category_colors() self.table_refs.add_assignments(aa, self.category_colors, True) self.button_zoom.setEnabled(True) self.button_show.setEnabled(True) self.button_infer.setEnabled(True) def __parse_xmcda_object(self, xmcda, tag, object_type): e = ElementTree.fromstring(str(xmcda)) t = ElementTree.ElementTree(e) return object_type().from_xmcda(t.find(".//%s" % tag)) def __parse_xmcda_lambda(self, xmcda): e = ElementTree.fromstring(str(xmcda)) t = ElementTree.ElementTree(e) value = t.find('.//methodParameters/parameter/value/real') return float(value.text) def on_model_learned_accepted(self): for cid, cv in self.cv_learned.items(): self.cv[cid].value = cv.value for bid, bp in self.bpt.items(): bp.performances.update(self.bpt_learned[bid].performances) self.lbda = self.lbda_learned self.__clear_tables() self.button_zoom.setEnabled(False) self.button_show.setEnabled(False) self.button_infer.setEnabled(False) self.__fill_model_tables() self.cbox_samethresholds.setChecked(True) self.cbox_mrsort.setChecked(True) self.cbox_noveto.setChecked(True) def __show_model_learned(self, cv, bpt, lbda, a): dialog = InferenceDialog(self) dialog.setModal(True) self.connect(dialog, QtCore.SIGNAL("accepted()"), self.on_model_learned_accepted) dialog.show() model = ElectreTri(self.criteria, cv, bpt, lbda, self.cat_profiles) worst = self.pt.get_worst(self.criteria) best = self.pt.get_best(self.criteria) criteria_order = [c.id for c in self.criteria] graph = QGraphicsSceneEtri(model, worst, best, self.graph_plot.size(), criteria_order) dialog.graph_model.setScene(graph) dialog.label_lambda.setText("Lambda: %s" % str(lbda)) a_incomp = Alternatives([aref for aref in self.a_ref if aref.id not in a.keys()]) pt_incomp = PerformanceTable([ap for ap in self.pt_ref if ap.id in a_incomp.keys()]) pt_comp = PerformanceTable([ap for ap in self.pt_ref if ap.id in a.keys()]) dialog.table_comp.add_criteria(self.criteria) dialog.table_comp.add_pt(a, pt_comp) dialog.table_incomp.add_criteria(self.criteria) dialog.table_incomp.add_pt(a_incomp, pt_incomp) def on_inference_thread_finished(self, completed): try: self.cancelbox.close() except: pass if completed is False: return solution = self.inference_thread.solution try: msg = str(solution.messages) except: QtGui.QMessageBox.information(None, "Error", "Invalid reply received, " \ "nothing received!") return xmcda_msg = ElementTree.ElementTree(ElementTree.fromstring(msg)) if xmcda_msg.find(".//methodMessages") is None: QtGui.QMessageBox.information(None, "Error", "Invalid reply received") return error = xmcda_msg.find(".//methodMessages/errorMessage/text") if error is not None: QtGui.QMessageBox.information(None, "Error", "Webservice replied:\n" + error.text) return try: cv = self.__parse_xmcda_object(solution.crit_weights, "criteriaValues", CriteriaValues) bpt = self.__parse_xmcda_object(solution.reference_alts, "performanceTable", PerformanceTable) lbda = self.__parse_xmcda_lambda(getattr(solution, 'lambda')) a = self.__parse_xmcda_object(solution.compatible_alts, "alternatives", Alternatives) except: QtGui.QMessageBox.information(None, "Error", "Cannot parse reply") return self.cv_learned = cv self.bpt_learned = bpt self.lbda_learned = lbda self.__show_model_learned(cv, bpt, lbda, a) def on_cancelbox_button_clicked(self, button): self.inference_thread.stop() def __xmcda_input(self, obj): xmcda = ElementTree.Element("{%s}XMCDA" % XMCDA_URL) xmcda.append(obj) return ElementTree.tostring(xmcda, encoding="UTF-8", method="xml") def __save_xmcda_files(self, xmcda): for name, xm in xmcda.items(): f = open("/tmp/%s.xml" % name, "w") f.write(xm) f.close() def __generate_xmcda_input(self): # This ugly part is needed for the old version of the webservice # that doesn't handle correctly deactivated criteria criteria = self.criteria.get_active() pt_ref = self.pt_ref.copy() bpt = self.bpt.copy() for ap in pt_ref: for crit, value in ap.performances.items(): if crit not in criteria.keys(): del ap.performances[crit] for ap in bpt: for crit, value in ap.performances.items(): if crit not in criteria.keys(): del ap.performances[crit] xmcda = {} xmcda['alternatives'] = self.__xmcda_input(self.a_ref.to_xmcda()) xmcda['criteria'] = self.__xmcda_input(criteria.to_xmcda()) xmcda['categories'] = self.__xmcda_input(self.categories.to_xmcda()) xmcda['perfs_table'] = self.__xmcda_input(pt_ref.to_xmcda()) xmcda['assign'] = self.__xmcda_input(self.aa_ref.to_xmcda()) self.__save_xmcda_files(xmcda) index = self.combo_inference.currentIndex() if index == COMBO_INFERENCE_PROFILES: lbda = self.spinbox_cutlevel.value() xmcda['crit_weights'] = self.cv.to_xmcda() xmcda['lambda'] = self.lambda_to_xmcda(lbda) elif index == COMBO_INFERENCE_WEIGHTS: xmcda['cat_profiles'] = self.cat_profiles.to_xmcda() xmcda['reference_alts'] = bpt.to_xmcda() return xmcda def on_button_infer_pressed(self): xmcda = self.__generate_xmcda_input() self.inference_thread = InferenceThread(xmcda, self) self.connect(self.inference_thread, QtCore.SIGNAL("finished(bool)"), self.on_inference_thread_finished) self.inference_thread.start() self.cancelbox = QtGui.QMessageBox(self) self.cancelbox.setWindowTitle('Please wait...') self.cancelbox.setText('Press cancel to stop inference') self.cancelbox.setStandardButtons(QtGui.QMessageBox.Cancel) self.cancelbox.setModal(True) self.connect(self.cancelbox, QtCore.SIGNAL("buttonClicked(QAbstractButton *)"), self.on_cancelbox_button_clicked) self.cancelbox.show() def on_button_zoom_pressed(self): if len(self.a_ref) < 1: return features = self.layer.get_features_ids(self.a_ref.keys()) self.layer.layer.setSelectedFeatures(features) mc = self.iface.mapCanvas() rect = self.layer.layer.boundingBoxOfSelected() rect.scale(2) mc.setExtent(rect) mc.refresh() def on_button_show_pressed(self): if len(self.a_ref) < 1: return features = self.layer.get_features_ids(self.a_ref.keys()) self.layer.layer.setSelectedFeatures(features)
def __load_from_xmcda(self, xmcda_file): tree = ElementTree.parse(xmcda_file) root = tree.getroot() # ElementTree.dump(root) xmcda_formatversion = root.find('.//formatversion') xmcda_crit = root.find('.//criteria') xmcda_critval = root.find('.//criteriaValues') xmcda_b = root.find('.//alternatives') xmcda_pt = root.findall('.//performanceTable') xmcda_lbda = root.find('.//methodParameters/parameter/value/real') # Update criteria direction criteria = Criteria().from_xmcda(xmcda_crit) for c in criteria: if c.id in self.criteria: self.criteria[c.id].disabled = c.disabled self.criteria[c.id].direction = c.direction # Remove criteria values that are not in the vector layer cvs = CriteriaValues() cvs.from_xmcda(xmcda_critval) for cv in cvs: if cv.id not in self.criteria: cvs.remove(cv.id) for c in self.criteria: # Disable criteria for which there are no weights if c.id not in cvs: c.disabled = True cvs.append(CriterionValue(c.id, 0)) balternatives = Alternatives() balternatives.from_xmcda(xmcda_b) bpt = PerformanceTable() qpt, ppt, vpt = None, None, None for xmcda in xmcda_pt: if xmcda.get('id') is None: bpt.from_xmcda(xmcda) for bp, c in product(bpt, self.criteria.get_active()): perfs = bp.performances if c.id not in perfs or perfs[c.id] is None: perfs[c.id] = 0 elif xmcda.get('id') == 'q': qpt = PerformanceTable(id = 'q') qpt.from_xmcda(xmcda) elif xmcda.get('id') == 'p': ppt = PerformanceTable(id = 'p') ppt.from_xmcda(xmcda) elif xmcda.get('id') == 'v': vpt = PerformanceTable(id = 'v') vpt.from_xmcda(xmcda) if qpt is not None and len(qpt) == 0 and len(ppt) > 0: qpt = ppt.copy() qpt.id = "q" if ppt is not None and len(ppt) == 0 and len(qpt) > 0: ppt = qpt.copy() ppt.id = "p" lbda = float(xmcda_lbda.text) self.__check_params_consistency(bpt, qpt, ppt, vpt) # Everything is fine self.cv = cvs self.balternatives = balternatives self.bpt = bpt self.qpt = qpt self.ppt = ppt self.vpt = vpt self.lbda = lbda # Categories Profiles self.categories = generate_categories(len(self.bpt) + 1, prefix = "") self.cat_profiles = generate_categories_profiles(self.categories)