예제 #1
0
 def actualizePeakModelComparative():
     model = QStandardItemModel()
     #root=MSDialogController.getColouredRootItem(sample)
     sampleList = QApplication.instance().model
     groups = sampleList.peaksGrouping()
     model.setVerticalHeaderLabels(["/".join(map(str, round([mass, rt], 4).tolist())) for mass, rt in sorted(groups.keys(), key=lambda x:x[0])])
     model.setHorizontalHeaderLabels([spl.shortName() for spl in sampleList.isamples()])
     for i, key in enumerate(sorted(groups.keys(), key=lambda x:x[0])):
         zeros = [0.] * len(sampleList)
         for peak in groups[key]:
             try:
                 idx = [spl.shortName() for spl in sampleList].index(peak.sample.shortName())
             except ValueError:
                 print "Error in %s"%MSDialogController.actualizePeakModelComparative.__name__
             zeros[idx] = peak
         for j in xrange(len(zeros)):
             item = QStandardItem()
             if not zeros[j]:
                 item.setBackground(QBrush(Qt.red))
                 item.setText("Not found")
             else:
                 MSDialogController.setRightIcon(zeros[j], item)#set the colour actually
                 item.setText(str(round(zeros[j].area, 2)))
             model.setItem(i, j, item)
     return model
예제 #2
0
 def actualizePeakModelComparative():
     model = QStandardItemModel()
     #root=MSDialogController.getColouredRootItem(sample)
     sampleList = QApplication.instance().model
     groups = sampleList.peaksGrouping()
     model.setVerticalHeaderLabels([
         "/".join(map(str,
                      round([mass, rt], 4).tolist()))
         for mass, rt in sorted(groups.keys(), key=lambda x: x[0])
     ])
     model.setHorizontalHeaderLabels(
         [spl.shortName() for spl in sampleList.isamples()])
     for i, key in enumerate(sorted(groups.keys(), key=lambda x: x[0])):
         zeros = [0.] * len(sampleList)
         for peak in groups[key]:
             try:
                 idx = [spl.shortName() for spl in sampleList
                        ].index(peak.sample.shortName())
             except ValueError:
                 print "Error in %s" % MSDialogController.actualizePeakModelComparative.__name__
             zeros[idx] = peak
         for j in xrange(len(zeros)):
             item = QStandardItem()
             if not zeros[j]:
                 item.setBackground(QBrush(Qt.red))
                 item.setText("Not found")
             else:
                 MSDialogController.setRightIcon(
                     zeros[j], item)  #set the colour actually
                 item.setText(str(round(zeros[j].area, 2)))
             model.setItem(i, j, item)
     return model
예제 #3
0
class OWConfusionMatrix(widget.OWWidget):
    name = "Confusion Matrix"
    description = "Shows a confusion matrix."
    icon = "icons/ConfusionMatrix.svg"
    priority = 1001

    inputs = [{"name": "Evaluation Results",
               "type": Orange.evaluation.testing.Results,
               "handler": "set_results"}]
    outputs = [{"name": "Selected Data",
                "type": Orange.data.Table}]

    quantities = ["Number of instances",
                  "Observed and expected instances",
                  "Proportion of predicted",
                  "Proportion of true"]

    selected_learner = settings.Setting([])
    selected_quantity = settings.Setting(0)
    append_predictions = settings.Setting(True)
    append_probabilities = settings.Setting(False)
    autocommit = settings.Setting(True)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.results = None
        self.learners = []
        self._invalidated = False

        box = gui.widgetBox(self.controlArea, "Learners")

        self.learners_box = gui.listBox(
            box, self, "selected_learner", "learners",
            callback=self._learner_changed
        )
        box = gui.widgetBox(self.controlArea, "Show")

        combo = gui.comboBox(box, self, "selected_quantity",
                             items=self.quantities,
                             callback=self._update)

        box = gui.widgetBox(self.controlArea, "Selection")

        gui.button(box, self, "Correct",
                   callback=self.select_correct, autoDefault=False)
        gui.button(box, self, "Misclassified",
                   callback=self.select_wrong, autoDefault=False)
        gui.button(box, self, "None",
                   callback=self.select_none, autoDefault=False)

        self.outputbox = box = gui.widgetBox(self.controlArea, "Output")
        gui.checkBox(box, self, "append_predictions",
                     "Append class predictions", callback=self._invalidate)
        gui.checkBox(box, self, "append_probabilities",
                     "Append predicted class probabilities",
                     callback=self._invalidate)

        b = gui.button(box, self, "Commit", callback=self.commit, default=True)
        cb = gui.checkBox(box, self, "autocommit", "Commit automatically")
        gui.setStopper(self, b, cb, "_invalidated", callback=self.commit)

        grid = QGridLayout()
        grid.setContentsMargins(0, 0, 0, 0)
        grid.addWidget(QLabel("Predicted"), 0, 1, Qt.AlignCenter)
        grid.addWidget(VerticalLabel("Correct Class"), 1, 0, Qt.AlignCenter)

        self.tablemodel = QStandardItemModel()
        self.tableview = QTableView(
            editTriggers=QTableView.NoEditTriggers,
        )
        self.tableview.setModel(self.tablemodel)
        self.tableview.selectionModel().selectionChanged.connect(
            self._invalidate
        )
        grid.addWidget(self.tableview, 1, 1)
        self.mainArea.layout().addLayout(grid)

    def set_results(self, results):
        """Set the input results."""

        self.clear()
        self.warning([0, 1])

        data = None
        if results is not None:
            if results.data is not None:
                data = results.data

        if data is not None and \
                not isinstance(data.domain.class_var,
                               Orange.data.DiscreteVariable):
            data = None
            results = None
            self.warning(
                0, "Confusion Matrix cannot be used for regression results.")

        self.results = results
        self.data = data

        if data is not None:
            class_values = data.domain.class_var.values
        elif results is not None:
            raise NotImplementedError

        if results is not None:
            nmodels, ntests = results.predicted.shape
            headers = class_values + [unicodedata.lookup("N-ARY SUMMATION")]

            # NOTE: The 'fitter_names' is set in 'Test Learners' widget.
            if hasattr(results, "fitter_names"):
                self.learners = results.fitter_names
            else:
                self.learners = ["L %i" % (i + 1) for i in range(nmodels)]

            self.tablemodel.setVerticalHeaderLabels(headers)
            self.tablemodel.setHorizontalHeaderLabels(headers)
            self.tablemodel.setRowCount(len(class_values) + 1)
            self.tablemodel.setColumnCount(len(class_values) + 1)
            self.selected_learner = [0]
            self._update()

    def clear(self):
        self.learners = []
        self.results = None
        self.data = None
        self.tablemodel.clear()

    def select_correct(self):
        selection = QItemSelection()
        n = self.tablemodel.rowCount()
        for i in range(n):
            index = self.tablemodel.index(i, i)
            selection.select(index, index)

        self.tableview.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect
        )

    def select_wrong(self):
        selection = QItemSelection()
        n = self.tablemodel.rowCount()

        for i in range(n):
            for j in range(i + 1, n):
                index = self.tablemodel.index(i, j)
                selection.select(index, index)
                index = self.tablemodel.index(j, i)
                selection.select(index, index)

        self.tableview.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect
        )

    def select_none(self):
        self.tableview.selectionModel().clear()

    def commit(self):
        if self.results and self.data:
            indices = self.tableview.selectedIndexes()
            indices = {(ind.row(), ind.column()) for ind in indices}
            actual = self.results.actual
            selected_learner = self.selected_learner[0]
            learner_name = self.learners[selected_learner]
            predicted = self.results.predicted[selected_learner]
            selected = [i for i, t in enumerate(zip(actual, predicted))
                        if t in indices]
            row_indices = self.results.row_indices[selected]

            extra = []
            class_var = self.data.domain.class_var
            metas = self.data.domain.metas

            if self.append_predictions:
                predicted = numpy.array(predicted[selected], dtype=object)
                extra.append(predicted.reshape(-1, 1))
                var = Orange.data.DiscreteVariable(
                    "{}({})".format(class_var.name, learner_name),
                    class_var.values
                )
                metas = metas + (var,)

            if self.append_probabilities and \
                    self.results.probabilities is not None:
                probs = self.results.probabilities[selected_learner, selected]
                extra.append(numpy.array(probs, dtype=object))
                pvars = [Orange.data.ContinuousVariable("p({})".format(value))
                         for value in class_var.values]
                metas = metas + tuple(pvars)

            X = self.data.X[row_indices]
            Y = self.data.Y[row_indices]
            M = self.data.metas[row_indices]

            M = numpy.hstack((M,) + tuple(extra))
            domain = Orange.data.Domain(
                self.data.domain.attributes,
                self.data.domain.class_vars,
                metas
            )

            data = Orange.data.Table.from_numpy(domain, X, Y, M)

        else:
            data = None

        self.send("Selected Data", data)
        self._invalidated = False

    def _invalidate(self):
        if self.autocommit:
            self.commit()
        else:
            self._invalidated = True

    def _learner_changed(self):
        # The selected learner has changed
        self._update()

    def _update(self):
        # Update the displayed confusion matrix
        if self.results is not None and self.selected_learner:
            index = self.selected_learner[0]
            cmatrix = confusion_matrix(self.results, index)
            colsum = cmatrix.sum(axis=0)
            rowsum = cmatrix.sum(axis=1)
            total = rowsum.sum()

            if self.selected_quantity == 0:
                value = lambda i, j: int(cmatrix[i, j])
            elif self.selected_quantity == 1:
                priors = numpy.outer(rowsum, colsum) / total
                value = lambda i, j: \
                    "{} / {:5.3f}".format(cmatrix[i, j], priors[i, j])
            elif self.selected_quantity == 2:
                value = lambda i, j: \
                    ("{:2.1f} %".format(100 * cmatrix[i, j] / colsum[i])
                     if colsum[i] else "N/A")
            elif self.selected_quantity == 3:
                value = lambda i, j: \
                    ("{:2.1f} %".format(100 * cmatrix[i, j] / rowsum[i])
                     if colsum[i] else "N/A")
            else:
                assert False

            model = self.tablemodel
            for i, row in enumerate(cmatrix):
                for j, _ in enumerate(row):
                    item = model.item(i, j)
                    if item is None:
                        item = QStandardItem()
                    item.setData(value(i, j), Qt.DisplayRole)
                    item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                    item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                    model.setItem(i, j, item)

            font = model.invisibleRootItem().font()
            bold_font = QFont(font)
            bold_font.setBold(True)

            def sum_item(value):
                item = QStandardItem()
                item.setData(value, Qt.DisplayRole)
                item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                item.setFlags(Qt.ItemIsEnabled)
                item.setFont(bold_font)
                return item

            N = len(colsum)
            for i in range(N):
                model.setItem(N, i, sum_item(int(colsum[i])))
                model.setItem(i, N, sum_item(int(rowsum[i])))

            model.setItem(N, N, sum_item(int(total)))
예제 #4
0
class OWConfusionMatrix(widget.OWWidget):
    name = "Confusion Matrix"
    description = "Shows a confusion matrix."
    icon = "icons/ConfusionMatrix.svg"
    priority = 1001

    inputs = [{
        "name": "Evaluation Results",
        "type": Orange.evaluation.Results,
        "handler": "set_results"
    }]
    outputs = [{"name": "Selected Data", "type": Orange.data.Table}]

    quantities = [
        "Number of instances", "Proportion of predicted",
        "Proportion of actual"
    ]

    selected_learner = settings.Setting([])
    selected_quantity = settings.Setting(0)
    append_predictions = settings.Setting(True)
    append_probabilities = settings.Setting(False)
    autocommit = settings.Setting(True)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.data = None
        self.results = None
        self.learners = []

        box = gui.widgetBox(self.controlArea, "Learners")

        self.learners_box = gui.listBox(box,
                                        self,
                                        "selected_learner",
                                        "learners",
                                        callback=self._learner_changed)
        box = gui.widgetBox(self.controlArea, "Show")

        gui.comboBox(box,
                     self,
                     "selected_quantity",
                     items=self.quantities,
                     callback=self._update)

        box = gui.widgetBox(self.controlArea, "Select")

        gui.button(box,
                   self,
                   "Correct",
                   callback=self.select_correct,
                   autoDefault=False)
        gui.button(box,
                   self,
                   "Misclassified",
                   callback=self.select_wrong,
                   autoDefault=False)
        gui.button(box,
                   self,
                   "None",
                   callback=self.select_none,
                   autoDefault=False)

        self.outputbox = box = gui.widgetBox(self.controlArea, "Output")
        gui.checkBox(box,
                     self,
                     "append_predictions",
                     "Predictions",
                     callback=self._invalidate)
        gui.checkBox(box,
                     self,
                     "append_probabilities",
                     "Probabilities",
                     callback=self._invalidate)

        gui.auto_commit(self.controlArea, self, "autocommit", "Send Data",
                        "Auto send is on")

        grid = QGridLayout()
        grid.setContentsMargins(0, 0, 0, 0)
        grid.addWidget(QLabel("Predicted"), 0, 1, Qt.AlignCenter)
        grid.addWidget(VerticalLabel("Actual Class"), 1, 0, Qt.AlignCenter)

        self.tablemodel = QStandardItemModel()
        self.tableview = QTableView(editTriggers=QTableView.NoEditTriggers)
        self.tableview.setModel(self.tablemodel)
        self.tableview.selectionModel().selectionChanged.connect(
            self._invalidate)
        grid.addWidget(self.tableview, 1, 1)
        self.mainArea.layout().addLayout(grid)

    def set_results(self, results):
        """Set the input results."""

        self.clear()
        self.warning([0, 1])

        data = None
        if results is not None:
            if results.data is not None:
                data = results.data

        if data is not None and \
                not isinstance(data.domain.class_var,
                               Orange.data.DiscreteVariable):
            data = None
            results = None
            self.warning(
                0, "Confusion Matrix cannot be used for regression results.")

        self.results = results
        self.data = data

        if data is not None:
            class_values = data.domain.class_var.values
        elif results is not None:
            raise NotImplementedError

        if results is not None:
            nmodels, ntests = results.predicted.shape
            headers = class_values + [unicodedata.lookup("N-ARY SUMMATION")]

            # NOTE: The 'learner_names' is set in 'Test Learners' widget.
            if hasattr(results, "learner_names"):
                self.learners = results.learner_names
            else:
                self.learners = ["L %i" % (i + 1) for i in range(nmodels)]

            self.tablemodel.setVerticalHeaderLabels(headers)
            self.tablemodel.setHorizontalHeaderLabels(headers)
            self.tablemodel.setRowCount(len(class_values) + 1)
            self.tablemodel.setColumnCount(len(class_values) + 1)
            self.selected_learner = [0]
            self._update()

    def clear(self):
        self.results = None
        self.data = None
        self.tablemodel.clear()
        # Clear learners last. This action will invoke `_learner_changed`
        # method
        self.learners = []

    def select_correct(self):
        selection = QItemSelection()
        n = self.tablemodel.rowCount()
        for i in range(n):
            index = self.tablemodel.index(i, i)
            selection.select(index, index)

        self.tableview.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect)

    def select_wrong(self):
        selection = QItemSelection()
        n = self.tablemodel.rowCount()

        for i in range(n):
            for j in range(i + 1, n):
                index = self.tablemodel.index(i, j)
                selection.select(index, index)
                index = self.tablemodel.index(j, i)
                selection.select(index, index)

        self.tableview.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect)

    def select_none(self):
        self.tableview.selectionModel().clear()

    def commit(self):
        if self.results is not None and self.data is not None \
                and self.selected_learner:
            indices = self.tableview.selectedIndexes()
            indices = {(ind.row(), ind.column()) for ind in indices}
            actual = self.results.actual
            selected_learner = self.selected_learner[0]
            learner_name = self.learners[selected_learner]
            predicted = self.results.predicted[selected_learner]
            selected = [
                i for i, t in enumerate(zip(actual, predicted)) if t in indices
            ]
            row_indices = self.results.row_indices[selected]

            extra = []
            class_var = self.data.domain.class_var
            metas = self.data.domain.metas

            if self.append_predictions:
                predicted = numpy.array(predicted[selected], dtype=object)
                extra.append(predicted.reshape(-1, 1))
                var = Orange.data.DiscreteVariable(
                    "{}({})".format(class_var.name, learner_name),
                    class_var.values)
                metas = metas + (var, )

            if self.append_probabilities and \
                    self.results.probabilities is not None:
                probs = self.results.probabilities[selected_learner, selected]
                extra.append(numpy.array(probs, dtype=object))
                pvars = [
                    Orange.data.ContinuousVariable("p({})".format(value))
                    for value in class_var.values
                ]
                metas = metas + tuple(pvars)

            X = self.data.X[row_indices]
            Y = self.data.Y[row_indices]
            M = self.data.metas[row_indices]
            row_ids = self.data.ids[row_indices]

            M = numpy.hstack((M, ) + tuple(extra))
            domain = Orange.data.Domain(self.data.domain.attributes,
                                        self.data.domain.class_vars, metas)
            data = Orange.data.Table.from_numpy(domain, X, Y, M)
            data.ids = row_ids
            data.name = learner_name

        else:
            data = None

        self.send("Selected Data", data)

    def _invalidate(self):
        self.commit()

    def _learner_changed(self):
        # The selected learner has changed
        self._update()
        self._invalidate()

    def _update(self):
        # Update the displayed confusion matrix
        if self.results is not None and self.selected_learner:
            index = self.selected_learner[0]
            cmatrix = confusion_matrix(self.results, index)
            colsum = cmatrix.sum(axis=0)
            rowsum = cmatrix.sum(axis=1)
            total = rowsum.sum()

            if self.selected_quantity == 0:
                value = lambda i, j: int(cmatrix[i, j])
            elif self.selected_quantity == 1:
                value = lambda i, j: \
                    ("{:2.1f} %".format(100 * cmatrix[i, j] / colsum[i])
                     if colsum[i] else "N/A")
            elif self.selected_quantity == 2:
                value = lambda i, j: \
                    ("{:2.1f} %".format(100 * cmatrix[i, j] / rowsum[i])
                     if colsum[i] else "N/A")
            else:
                assert False

            model = self.tablemodel
            for i, row in enumerate(cmatrix):
                for j, _ in enumerate(row):
                    item = model.item(i, j)
                    if item is None:
                        item = QStandardItem()
                    item.setData(value(i, j), Qt.DisplayRole)
                    item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                    item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                    model.setItem(i, j, item)

            font = model.invisibleRootItem().font()
            bold_font = QFont(font)
            bold_font.setBold(True)

            def sum_item(value):
                item = QStandardItem()
                item.setData(value, Qt.DisplayRole)
                item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                item.setFlags(Qt.ItemIsEnabled)
                item.setFont(bold_font)
                return item

            N = len(colsum)
            for i in range(N):
                model.setItem(N, i, sum_item(int(colsum[i])))
                model.setItem(i, N, sum_item(int(rowsum[i])))

            model.setItem(N, N, sum_item(int(total)))
class OWCorrelations(OWWidget):
    name = "Correlations"

    description = "Calculate correlation"
    icon = "icons/correlation.svg"

    inputs = [("Data", Table, 'set_data')]
    outputs = [("Correlations", Table), ("Variables", AttributeList)]

    def __init__(self):
        super().__init__()
        self.data = None

        self.pairwise_correlations = True
        self.correlations_type = 0
        self.selected_index = None
        self.changed_flag = False
        self.auto_commit = True
        self.splitter_state = None
        self.corr_graph = CorrelationsGraph(self)
        self.mainArea.layout().addWidget(self.corr_graph.plot_widget)
        self.resize(1000, 500)  # TODO better size handling

        gui.radioButtonsInBox(
            self.controlArea,
            self,
            "correlations_type",
            ("Pairwise Pearson correlation", "Pairwise Spearman correlation"),
            box="Correlations",
            callback=self.on_corr_type_change)

        self.corr_table = CorrelationsTableView()

        self.corr_model = QStandardItemModel()
        self.corr_table.setModel(self.corr_model)

        self.controlArea.layout().addWidget(self.corr_table)
        self.corr_table.selectionModel().selectionChanged.connect(
            self.on_table_selection_change)

    @property
    def target_variable(self):
        if self.data:
            return self.data.domain.class_var
        else:
            return None

    def on_corr_type_change(self):
        """Do necessary actions after correlation type change.

        Clear computed data, set selected by user variables and finally
        commit(_if) changes.
        """
        if self.data is not None:
            curr_selection = self.selected_vars
            self.clear_computed()
            self.run()

            if curr_selection:
                try:
                    self.set_selected_vars(*curr_selection)
                except Exception as ex:
                    import traceback
                    traceback.print_exc()

            self.commit_if()

    def on_table_selection_change(self, selected, deselected):
        indexes = self.corr_table.selectionModel().selectedIndexes()
        if indexes:
            index = indexes[0]
            i, j = index.row(), index.column()
            if self.correlations_type == 2 and \
                    is_continuous(self.target_variable):
                j = len(self.var_names) - 1

            vars = [self.cont_vars[i], self.cont_vars[j]]
            self.corr_graph.update_data(vars[0], vars[1], i, j)
        else:
            vars = None
        self.selected_vars = vars

        self.send("Variables", vars)

    def clear_computed(self):
        """Clear computed data."""
        self.corr_model.clear()
        self.set_all_pairwise_matrix(None)
        self.set_target_correlations(None, None)

    def set_selected_vars(self, x, y):
        """Set selected by user variable(s)."""
        x = self.cont_vars.index(x)
        y = self.cont_vars.index(y)
        if self.correlations_type == 2:
            y = 0

        model = self.corr_model
        sel_model = self.corr_table.selectionModel()
        sel_model.select(model.index(x, y), QItemSelectionModel.ClearAndSelect)

    def set_data(self, data):
        """
        Check if data has enough continuous variables.
        Update data, correlation type, correlation graph and commit changes.
        """
        self.clear()
        self.information()
        self.data = data
        if data is None:
            return
        if len(list(filter(lambda x: x.is_continuous, data.domain))) >= 2:
            self.set_variables_list(data)
            self.selected_index = None
            self.corr_graph.set_data(data)

            if self.selected_index is None or \
                    any(n in self.data.domain for n in self.selected_index):
                self.selected_index = self.var_names[:2]

            self.run()

        else:
            self.data = None
            self.information("Need data with at least 2 continuous variables.")

            self.commit_if()

        self.send("Correlations", Table(data))

    def clear(self):
        """ Clear all widget data. """
        self.data = None
        self.selected_vars = None
        self.clear_graph()

    def clear_graph(self):
        self.corr_graph._clear_plot_widget()
        self.corr_graph.set_data(None, None)
        self.corr_graph.replot()

    def set_variables_list(self, data):
        '''
        :param data: data
        :return: sets cont_vars and var_names
        '''
        vars = list(data.domain.variables)
        vars = [v for v in vars if v.is_continuous]
        self.cont_vars = vars
        self.var_names = [v.name for v in vars]

    def run(self):
        """ Start data matrix creation. """
        if self.correlations_type < 2:
            if self.correlations_type == 0:
                matrix = pairwise_pearson_correlations(self.data,
                                                       self.cont_vars)
            elif self.correlations_type == 1:
                matrix = pairwise_spearman_correlations(
                    self.data, self.cont_vars)
            self.set_all_pairwise_matrix(matrix)

        elif self.target_variable and self.target_variable.is_continuous:
            vars = [v for v in self.cont_vars if v != self.target_variable]
            p_corr = target_pearson_correlations(self.data, vars,
                                                 self.target_variable)
            s_corr = target_spearman_correlations(self.data, vars,
                                                  self.target_variable)
            correlations = [list(t) for t in zip(p_corr, s_corr)]
            self.set_target_correlations(correlations, vars)

    def set_all_pairwise_matrix(self, matrix):
        """ Set data matrix to correlations model and resize table. """
        self.matrix = matrix
        if matrix is not None:
            for i, row in enumerate(matrix):
                for j, e in enumerate(row):
                    item = QStandardItem()
                    if i != j:
                        item.setData(str(round(e, 5)), Qt.DisplayRole)
                    else:
                        item.setData(QColor(192, 192, 192), Qt.BackgroundRole)
                    self.corr_model.setItem(i, j, item)

            vars = self.cont_vars
            header = [v.name for v in vars]
            self.corr_model.setVerticalHeaderLabels(header)
            self.corr_model.setHorizontalHeaderLabels(header)

            self.corr_table.resizeColumnsToContents()
            self.corr_table.resizeRowsToContents()

            self.corr_table.updateGeometry()

    def set_target_correlations(self, correlations, vars=None):
        self.target_correlations = correlations
        if correlations is not None:
            for i, row in enumerate(correlations):
                for j, c in enumerate(row):
                    item = QStandardItem()
                    item.setData(c, Qt.DisplayRole)
                    self.corr_model.setItem(i, j, item)

            if vars is None:
                vars = self.cont_vars

            v_header = [v.name for v in vars]
            h_header = ["Pearson", "Spearman"]
            self.corr_model.setVerticalHeaderLabels(v_header)
            self.corr_model.setHorizontalHeaderLabels(h_header)

            self.corr_table.resizeColumnsToContents()
            self.corr_table.resizeRowsToContents()

            QTimer.singleShot(100, self.corr_table.updateGeometry)

    def commit_if(self):
        if self.auto_commit:
            self.commit()
        else:
            self.changed_flag = True

    def commit(self):
        table = None
        if self.data is not None:
            if self.correlations_type == 2 and self.target_variable and \
                    self.target_variable.is_continuous:
                pearson = ContinuousVariable.make("Pearson")
                spearman = ContinuousVariable.make("Spearman")
                row_name = StringVariable.make("Variable")

                domain = Orange.data.Domain([pearson, spearman],
                                            metas=[row_name])
                table = Orange.data.Table(domain, self.target_correlations)
                for inst, name in zip(table, self.var_names):
                    inst[row_name] = name
        self.send("Correlations", table)

    def selection_changed(self):  # TODO FIX IT
        pass
예제 #6
0
class DoProfile(QWidget):

    def __init__(self, iface, dockwidget1 , tool1 , plugin, parent = None):
        QWidget.__init__(self, parent)
        self.profiles = None        #dictionary where is saved the plotting data {"l":[l],"z":[z], "layer":layer1, "curve":curve1}
        self.xAxisSteps = None
        self.xAxisStepType = "numeric"
        self.iface = iface
        self.tool = tool1
        self.dockwidget = dockwidget1
        self.pointstoDraw = None
        self.plugin = plugin
        #init scale widgets
        self.dockwidget.sbMaxVal.setValue(0)
        self.dockwidget.sbMinVal.setValue(0)
        self.dockwidget.sbMaxVal.setEnabled(False)
        self.dockwidget.sbMinVal.setEnabled(False)
        self.dockwidget.sbMinVal.valueChanged.connect(self.reScalePlot)
        self.dockwidget.sbMaxVal.valueChanged.connect(self.reScalePlot)


    #**************************** function part *************************************************

    # remove layers which were removed from QGIS
    def removeClosedLayers(self, model1):
        qgisLayerNames = []
        for i in range(0, self.iface.mapCanvas().layerCount()):
                qgisLayerNames.append(self.iface.mapCanvas().layer(i).name())

        for i in range(0 , model1.rowCount()):
            layerName = model1.item(i,2).data(Qt.EditRole)
            if not layerName in qgisLayerNames:
                self.plugin.removeLayer(i)
                self.removeClosedLayers(model1)
                break

    def calculatePointProfile(self, point, model, library):
        self.model = model
        self.library = library
        
        statName = self.getPointProfileStatNames()[0]

        self.removeClosedLayers(model)
        if point == None:
            return
        PlottingTool().clearData(self.dockwidget, model, library)
        self.profiles = []
        
        #creating the plots of profiles
        for i in range(0 , model.rowCount()):
            self.profiles.append( {"layer": model.item(i,3).data(Qt.EditRole) } )
            self.profiles[i][statName] = []
            self.profiles[i]["l"] = []
            layer = self.profiles[i]["layer"]

            if layer:
                try:
                    ident = layer.dataProvider().identify(point, QgsRaster.IdentifyFormatValue )
                except:
                    ident = None
            else:
                ident = None
            #if ident is not None and ident.has_key(choosenBand+1):
            if ident is not None:
                self.profiles[i][statName] = ident.results().values()
                self.profiles[i]["l"] = ident.results().keys()
        
        self.setXAxisSteps()
        PlottingTool().attachCurves(self.dockwidget, self.profiles, model, library)
        PlottingTool().reScalePlot(self.dockwidget, self.profiles, model, library)
        self.setupTableTab(model)

    def getPointProfileStatNames(self):
        return ["value"]

    # The code is based on the approach of ZonalStatistics from Processing toolbox 
    def calculatePolygonProfile(self, geometry, crs, model, library):
        self.model = model
        self.library = library
        
        self.removeClosedLayers(model)
        if geometry is None or geometry.isEmpty():
            return
        
        PlottingTool().clearData(self.dockwidget, model, library)
        self.profiles = []

        #creating the plots of profiles
        for i in range(0 , model.rowCount()):
            self.profiles.append( {"layer": model.item(i,3).data(Qt.EditRole) } )
            self.profiles[i]["l"] = []
            for statistic in self.getPolygonProfileStatNames():
                self.profiles[i][statistic] = []
            
            # Get intersection between polygon geometry and raster following ZonalStatistics code
            rasterDS = gdal.Open(self.profiles[i]["layer"].source(), gdal.GA_ReadOnly)
            geoTransform = rasterDS.GetGeoTransform()
            
    
            cellXSize = abs(geoTransform[1])
            cellYSize = abs(geoTransform[5])
            rasterXSize = rasterDS.RasterXSize
            rasterYSize = rasterDS.RasterYSize
    
            rasterBBox = QgsRectangle(geoTransform[0], geoTransform[3] - cellYSize
                                      * rasterYSize, geoTransform[0] + cellXSize
                                      * rasterXSize, geoTransform[3])
            rasterGeom = QgsGeometry.fromRect(rasterBBox)
            
            memVectorDriver = ogr.GetDriverByName('Memory')
            memRasterDriver = gdal.GetDriverByName('MEM')
            
            intersectedGeom = rasterGeom.intersection(geometry)
            ogrGeom = ogr.CreateGeometryFromWkt(intersectedGeom.exportToWkt())
            
            bbox = intersectedGeom.boundingBox()

            xMin = bbox.xMinimum()
            xMax = bbox.xMaximum()
            yMin = bbox.yMinimum()
            yMax = bbox.yMaximum()

            (startColumn, startRow) = self.mapToPixel(xMin, yMax, geoTransform)
            (endColumn, endRow) = self.mapToPixel(xMax, yMin, geoTransform)

            width = endColumn - startColumn
            height = endRow - startRow

            if width == 0 or height == 0:
                return

            srcOffset = (startColumn, startRow, width, height)

            newGeoTransform = (
                geoTransform[0] + srcOffset[0] * geoTransform[1],
                geoTransform[1],
                0.0,
                geoTransform[3] + srcOffset[1] * geoTransform[5],
                0.0,
                geoTransform[5],
            )
            
            # Create a temporary vector layer in memory
            memVDS = memVectorDriver.CreateDataSource('out')
            memLayer = memVDS.CreateLayer('poly', crs, ogr.wkbPolygon)

            ft = ogr.Feature(memLayer.GetLayerDefn())
            ft.SetGeometry(ogrGeom)
            memLayer.CreateFeature(ft)
            ft.Destroy()
            
            # Rasterize it
            rasterizedDS = memRasterDriver.Create('', srcOffset[2],
                    srcOffset[3], 1, gdal.GDT_Byte)
            rasterizedDS.SetGeoTransform(newGeoTransform)
            gdal.RasterizeLayer(rasterizedDS, [1], memLayer, burn_values=[1])
            rasterizedArray = rasterizedDS.ReadAsArray()
            
            for bandNumber in range(1, rasterDS.RasterCount+1): 
                rasterBand = rasterDS.GetRasterBand(bandNumber)
                noData = rasterBand.GetNoDataValue()
                if noData is None:
                    noData = np.nan
                scale = rasterBand.GetScale()
                if scale is None:
                    scale = 1.0
                offset = rasterBand.GetOffset()
                if offset is None:
                    offset = 0.0
                srcArray = rasterBand.ReadAsArray(*srcOffset)
                srcArray = srcArray*scale+offset 
                masked = np.ma.MaskedArray(srcArray,
                            mask=np.logical_or.reduce((
                             srcArray == noData,
                             np.logical_not(rasterizedArray),
                             np.isnan(srcArray))))

                self.profiles[i]["l"].append(bandNumber)
                self.profiles[i]["count"].append(float(masked.count()))
                self.profiles[i]["max"].append(float(masked.max()))
                self.profiles[i]["mean"].append(float(masked.mean()))
                self.profiles[i]["median"].append(float(np.ma.median(masked)))
                self.profiles[i]["min"].append(float(masked.min()))
                self.profiles[i]["range"].append(float(masked.max()) - float(masked.min()))
                self.profiles[i]["std"].append(float(masked.std()))
                self.profiles[i]["sum"].append(float(masked.sum()))
                self.profiles[i]["unique"].append(np.unique(masked.compressed()).size)
                self.profiles[i]["var"].append(float(masked.var()))
                
            memVDS = None
            rasterizedDS = None
        
        rasterDS = None
        
        self.setXAxisSteps()
        PlottingTool().attachCurves(self.dockwidget, self.profiles, model, library)
        PlottingTool().reScalePlot(self.dockwidget, self.profiles, model, library)
        self.setupTableTab(model)

    def getPolygonProfileStatNames(self):
        return ["count", "max", "mean", "median", "min", "range", "std", "sum", "unique", "var"]

    def setXAxisSteps(self):
        if self.xAxisSteps == None:
            self.changeXAxisStepType("numeric")
            return
        
        elif self.xAxisSteps[0] == "Timesteps":
            self.changeXAxisStepType("numeric")
            for profile in self.profiles:
                stepsNum = len(profile["l"])
                startTime = self.xAxisSteps[1]
                step = self.xAxisSteps[2]
                stepType = self.xAxisSteps[3]
                useNetcdfTime = self.xAxisSteps[4]
                if stepType == "years":
                    stepType = "days"
                    step = step * 365
                elif stepType == "months":
                    stepType = "days"
                    step = step * 365/12

                profile["l"] = []
                if useNetcdfTime and (profile["layer"].source().startswith("NETCDF:") or
                                      profile["layer"].source().endswith(".nc")):
                    try:
                        import netCDF4
                        if profile["layer"].source().startswith("NETCDF:"):
                            filename = re.match('NETCDF:\"(.*)\":.*$', profile["layer"].source()).group(1)
                        else:
                            filename = profile["layer"].source()
                        nc = netCDF4.Dataset(filename, mode='r')
                        profile["l"] = netCDF4.num2date(nc.variables["time"][:],
                                                        units = nc.variables["time"].units,
                                                        calendar = nc.variables["time"].calendar)
                        nc.close()
                    except ImportError:
                        text = "Temporal/Spectral Profile Tool: netCDF4 module is required to read NetCDF " + \
                               "time dimension. Please use pip install netCDF4"
                        self.iface.messageBar().pushWidget(self.iface.messageBar().createMessage(text), 
                                                           QgsMessageBar.WARNING, 5)
                        profile["l"] = []
                    except KeyError:
                        text = "Temporal/Spectral Profile Tool: NetCDF file does not have " + \
                               "time dimension."
                        self.iface.messageBar().pushWidget(self.iface.messageBar().createMessage(text), 
                                                           QgsMessageBar.WARNING, 5)
                        nc.close()
                        profile["l"] = []
                if profile["l"] == []:
                    for i in range(stepsNum):
                        timedeltaParams = {stepType: step*i}
                        profile["l"].append(startTime + timedelta(**timedeltaParams))
                self.changeXAxisStepType("timedate")        
        else:
            for profile in self.profiles:
                # Truncate the profiles to the minimum of the length of each profile
                # or length of provided x-axis steps
                stepsNum = min(len(self.xAxisSteps), len(profile["l"]))
                profile["l"] = self.xAxisSteps[:stepsNum]
                for stat in profile.keys():
                    if stat == "l" or stat == "layer":
                        continue
                    profile[stat] = profile[stat][:stepsNum]
                    
                # If any x-axis step is a NaN then remove the corresponding
                # value from profile
                nans = [i for i, x in enumerate(profile["l"]) if math.isnan(x)]
                for stat in profile.keys():
                    if stat == "layer":
                        continue
                    profile[stat] = [x for i, x in enumerate(profile[stat]) if i not in nans]
            
            self.changeXAxisStepType("numeric")
            
    def changeXAxisStepType(self, newType):
        if self.xAxisStepType == newType:
            return
        else:
            self.xAxisStepType = newType
            PlottingTool().resetAxis(self.dockwidget, self.library)
    
    def mapToPixel(self, mX, mY, geoTransform):
        (pX, pY) = gdal.ApplyGeoTransform(
            gdal.InvGeoTransform(geoTransform), mX, mY)
            
        return (int(pX), int(pY))            
    
    def setupTableTab(self, model1):
        #*********************** TAble tab *************************************************
        try:                                                                    #Reinitializing the table tab
            self.VLayout = self.dockwidget.scrollAreaWidgetContents.layout()
            while 1:
                child = self.VLayout.takeAt(0)
                if not child:
                    break
                child.widget().deleteLater()
        except:
            self.VLayout = QVBoxLayout(self.dockwidget.scrollAreaWidgetContents)
            self.VLayout.setContentsMargins(9, -1, -1, -1)
        #Setup the table tab
        self.groupBox = []
        self.profilePushButton = []
        self.tableView = []
        self.verticalLayout = []
        for i in range(0 , model1.rowCount()):
            self.groupBox.append( QGroupBox(self.dockwidget.scrollAreaWidgetContents) )
            sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
            sizePolicy.setHorizontalStretch(0)
            sizePolicy.setVerticalStretch(0)
            sizePolicy.setHeightForWidth(self.groupBox[i].sizePolicy().hasHeightForWidth())
            self.groupBox[i].setSizePolicy(sizePolicy)
            self.groupBox[i].setMinimumSize(QSize(0, 150))
            self.groupBox[i].setMaximumSize(QSize(16777215, 350))
            self.groupBox[i].setTitle(QApplication.translate("GroupBox" + str(i), self.profiles[i]["layer"].name(), None, QApplication.UnicodeUTF8))
            self.groupBox[i].setObjectName("groupBox" + str(i))

            self.verticalLayout.append( QVBoxLayout(self.groupBox[i]) )
            self.verticalLayout[i].setObjectName("verticalLayout")
            #The table
            self.tableView.append( QTableView(self.groupBox[i]) )
            self.tableView[i].setObjectName("tableView" + str(i))
            font = QFont("Arial", 8)
            columns = len(self.profiles[i]["l"])
            rowNames = self.profiles[i].keys()
            rowNames.remove("layer") # holds the QgsMapLayer instance
            rowNames.remove("l") # holds the band number
            rows = len(rowNames)
            self.mdl = QStandardItemModel(rows+1, columns)
            self.mdl.setVerticalHeaderLabels(["band"] + rowNames)
            for j in range(columns):
                self.mdl.setData(self.mdl.index(0, j, QModelIndex()), str(self.profiles[i]["l"][j]))
                self.mdl.setData(self.mdl.index(0, j, QModelIndex()), font ,Qt.FontRole)
                for k in range(rows):
                    self.mdl.setData(self.mdl.index(k+1, j, QModelIndex()), str(self.profiles[i][rowNames[k]][j]))
                    self.mdl.setData(self.mdl.index(k+1, j, QModelIndex()), font ,Qt.FontRole)
            #self.tableView[i].setVerticalHeaderLabels(rowNames)
            self.tableView[i].verticalHeader().setDefaultSectionSize(18)
            self.tableView[i].horizontalHeader().setDefaultSectionSize(60)
            self.tableView[i].setModel(self.mdl)
            self.verticalLayout[i].addWidget(self.tableView[i])

            self.horizontalLayout = QHBoxLayout()

            #the copy to clipboard button
            self.profilePushButton.append( QPushButton(self.groupBox[i]) )
            sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            sizePolicy.setHorizontalStretch(0)
            sizePolicy.setVerticalStretch(0)
            sizePolicy.setHeightForWidth(self.profilePushButton[i].sizePolicy().hasHeightForWidth())
            self.profilePushButton[i].setSizePolicy(sizePolicy)
            self.profilePushButton[i].setText(QApplication.translate("GroupBox", "Copy to clipboard", None, QApplication.UnicodeUTF8))
            self.profilePushButton[i].setObjectName(str(i))
            self.horizontalLayout.addWidget(self.profilePushButton[i])

            self.horizontalLayout.addStretch(0)
            self.verticalLayout[i].addLayout(self.horizontalLayout)

            self.VLayout.addWidget(self.groupBox[i])
            QObject.connect(self.profilePushButton[i], SIGNAL("clicked()"), self.copyTable)

    def copyTable(self):                            #Writing the table to clipboard in excel form
        nr = int( self.sender().objectName() )
        self.clipboard = QApplication.clipboard()
        text = "band"
        rowNames = self.profiles[nr].keys()
        rowNames.remove("layer")
        rowNames.remove("l")
        for name in rowNames:
            text += "\t"+name
        text += "\n"
        for i in range( len(self.profiles[nr]["l"]) ):
            text += str(self.profiles[nr]["l"][i])
            for j in range(len(rowNames)):
                text += "\t" + str(self.profiles[nr][rowNames[j]][i])
            text += "\n"
        self.clipboard.setText(text)

    def reScalePlot(self, param):                         # called when a spinbox value changed
        if type(param) != float:    
            # don't execute it twice, for both valueChanged(int) and valueChanged(str) signals
            return
        if self.dockwidget.sbMinVal.value() == self.dockwidget.sbMaxVal.value() == 0:
            # don't execute it on init
            return
        PlottingTool().reScalePlot(self.dockwidget, self.profiles, self.model, self.library, autoMode = False)