def __init__(self):
        self.data = None
        self._models = OrderedDict()
        box = gui.vBox(self.controlArea, 'Evaluation Parameters')
        gui.spin(box,
                 self,
                 'n_folds',
                 1,
                 100,
                 label='Number of folds:',
                 callback=self.on_changed)
        gui.spin(box,
                 self,
                 'forecast_steps',
                 1,
                 100,
                 label='Forecast steps:',
                 callback=self.on_changed)
        gui.auto_commit(box, self, 'autocommit', '&Apply')
        gui.rubber(self.controlArea)

        self.model = model = PyTableModel(parent=self)
        view = gui.TableView(self)
        view.setModel(model)
        view.horizontalHeader().setStretchLastSection(False)
        view.verticalHeader().setVisible(True)
        self.mainArea.layout().addWidget(view)
Exemple #2
0
    def __init__(self):
        self.data = None
        box = gui.vBox(self.controlArea, 'Granger Test')
        gui.hSlider(box,
                    self,
                    'confidence',
                    minValue=90,
                    maxValue=99,
                    label='Confidence:',
                    labelFormat=" %d%%",
                    callback=self.on_changed)
        gui.spin(box,
                 self,
                 'max_lag',
                 1,
                 50,
                 label='Max lag:',
                 callback=self.on_changed)
        gui.auto_commit(box, self, 'autocommit', '&Test')
        gui.rubber(self.controlArea)

        self.model = model = PyTableModel(parent=self)
        model.setHorizontalHeaderLabels(
            ['Min. lag', 'Series 1', '', 'Series 2'])
        view = gui.TableView(self)
        view.setModel(model)
        bold = view.BoldFontDelegate(self)
        view.setItemDelegateForColumn(1, bold)
        view.setItemDelegateForColumn(3, bold)
        view.horizontalHeader().setStretchLastSection(False)
        self.mainArea.layout().addWidget(view)
Exemple #3
0
    def __init__(self):
        super().__init__()
        self.corpus = None  # corpus taken from distances
        self.linkage = None  # hierarchical clustering linkage as returned by Orange
        self.distances = None  # DistMatrix on input
        self.clustering_mask = None  # 1D array of clusters for self.corpus
        self.threshold_spin = None

        # Info
        self.n_documents = ''
        self.n_unique = ''
        self.n_duplicates = ''
        info_box = gui.widgetBox(self.controlArea, box='Info')
        gui.label(info_box, self, 'Documents: %(n_documents)s')
        gui.label(info_box, self, '  ◦ unique: %(n_unique)s')
        gui.label(info_box, self, '  ◦ duplicates: %(n_duplicates)s')

        # Threshold Histogram & Cluster View
        self.histogram = Histogram(self)
        self.table_view = gui.TableView(
            selectionMode=QListView.SingleSelection)
        self.table_model = PyTableModel()
        self.table_model.setHorizontalHeaderLabels(['Cluster', 'Size'])
        self.table_view.setModel(self.table_model)
        self.table_view.selectionModel().selectionChanged.connect(
            self.send_duplicates)

        # Add to main area
        height = 300
        main_area = gui.hBox(self.mainArea)
        self.histogram.setMinimumWidth(300)
        self.histogram.setMinimumHeight(height)
        self.table_view.setFixedWidth(140)
        main_area.layout().addWidget(self.histogram)
        main_area.layout().addWidget(self.table_view)

        # Controls
        gui.comboBox(self.controlArea,
                     self,
                     'linkage_method',
                     items=self.LINKAGE,
                     box='Linkage',
                     callback=self.recalculate_linkage,
                     orientation=Qt.Horizontal)
        self.threshold_spin = gui.doubleSpin(self.controlArea,
                                             self,
                                             'threshold',
                                             0,
                                             float('inf'),
                                             0.01,
                                             decimals=2,
                                             label='Distance threshold',
                                             box='Distances',
                                             callback=self.threshold_changed,
                                             keyboardTracking=False,
                                             controlWidth=60)
        self.histogram.region.sigRegionChangeFinished.connect(
            self.threshold_from_histogram_region)
        self.threshold_spin.setEnabled(False)
        gui.rubber(self.controlArea)
Exemple #4
0
    def __init__(self):
        OWWidget.__init__(self)
        ConcurrentWidgetMixin.__init__(self)
        self.data = None
        self.selected_attributes = None
        box = gui.vBox(self.controlArea, "Granger Test")
        gui.hSlider(
            box,
            self,
            "confidence",
            minValue=90,
            maxValue=99,
            label="Confidence:",
            labelFormat=" %d%%",
            callback=self._setting_changed,
        )
        gui.spin(
            box,
            self,
            "max_lag",
            1,
            50,
            label="Max lag:",
            callback=self._setting_changed,
        )
        self.test_button = gui.button(box, self, "&Test", self._toggle_run)
        gui.rubber(self.controlArea)

        self.model = model = PyTableModel(parent=self)

        model.setHorizontalHeaderLabels(COLUMNS)
        self.causality_view = view = gui.TableView(self)
        view.setModel(model)
        bold = view.BoldFontDelegate(self)
        view.setItemDelegateForColumn(2, bold)
        view.setItemDelegateForColumn(4, bold)
        view.horizontalHeader().setStretchLastSection(False)
        view.horizontalHeader().sectionClicked.connect(self.header_click)
        view.selectionModel().selectionChanged.connect(self.on_select)
        view.sortByColumn(1, Qt.AscendingOrder)
        self.mainArea.layout().addWidget(view)
        self._set_modified(False)

        self.auto_commit_widget = gui.auto_commit(
            widget=self.controlArea,
            master=self,
            value="autocommit",
            label="Apply",
            commit=self.commit,
        )
    def __init__(self):
        self.data = None
        self.classifier = None
        self.selected = None

        self.model = CustomRuleViewerTableModel(parent=self)
        self.model.set_horizontal_header_labels(
            [
                "IF conditions",
                "",
                "THEN class",
                "Distribution",
                "Probabilities [%]",
                "Quality",
                "Length",
            ]
        )

        self.proxy_model = QSortFilterProxyModel(parent=self)
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.setSortRole(self.model.SortRole)

        self.view = gui.TableView(self, wordWrap=False)
        self.view.setModel(self.proxy_model)
        self.view.verticalHeader().setVisible(True)
        self.view.horizontalHeader().setStretchLastSection(False)
        self.view.selectionModel().selectionChanged.connect(self.commit)

        self.dist_item_delegate = DistributionItemDelegate(self)
        self.view.setItemDelegateForColumn(3, self.dist_item_delegate)

        self.mainArea.layout().setContentsMargins(0, 0, 0, 0)
        self.mainArea.layout().addWidget(self.view)
        bottom_box = gui.hBox(widget=self.mainArea, box=None, margin=0, spacing=0)

        original_order_button = QPushButton("Restore original order", autoDefault=False)
        original_order_button.setFixedWidth(180)
        bottom_box.layout().addWidget(original_order_button)
        original_order_button.clicked.connect(self.restore_original_order)

        gui.separator(bottom_box, width=5, height=0)
        gui.checkBox(
            widget=bottom_box,
            master=self,
            value="compact_view",
            label="Compact view",
            callback=self.on_update,
        )
    def __init__(self):
        super().__init__()

        self.data = None
        self.classifier = None
        self.selected = None

        self.info.set_input_summary(self.info.NoInput)
        self.info.set_output_summary(self.info.NoOutput)

        self.model = CustomRuleViewerTableModel(parent=self)
        self.model.set_horizontal_header_labels([
            "IF conditions", "", "THEN class", "Distribution",
            "Probabilities [%]", "Quality", "Length"
        ])

        self.proxy_model = QSortFilterProxyModel(parent=self)
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.setSortRole(self.model.SortRole)

        self.view = gui.TableView(self, wordWrap=False)
        self.view.setModel(self.proxy_model)
        self.view.verticalHeader().setVisible(True)
        self.view.horizontalHeader().setStretchLastSection(False)
        self.view.selectionModel().selectionChanged.connect(self.commit)

        self.dist_item_delegate = DistributionItemDelegate(self)
        self.view.setItemDelegateForColumn(3, self.dist_item_delegate)

        self.controlArea.layout().addWidget(self.view)

        gui.checkBox(widget=self.buttonsArea,
                     master=self,
                     value="compact_view",
                     label="Compact view",
                     callback=self.on_update)
        gui.rubber(self.buttonsArea)

        original_order_button = gui.button(
            self.buttonsArea,
            self,
            "Restore original order",
            autoDefault=False,
            callback=self.restore_original_order,
            attribute=Qt.WA_LayoutUsesWidgetRect,
        )
        original_order_button.clicked.connect(self.restore_original_order)
Exemple #7
0
    def __init__(self, master):
        QObject.__init__(self)
        OWComponent.__init__(self, master)

        self.view = gui.TableView(wordWrap=True,
                                  editTriggers=gui.TableView.NoEditTriggers)
        header = self.view.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.ResizeToContents)
        header.setDefaultAlignment(Qt.AlignCenter)
        header.setStretchLastSection(False)
        header.setContextMenuPolicy(Qt.CustomContextMenu)
        header.customContextMenuRequested.connect(self.show_column_chooser)

        self.model = QStandardItemModel(master)
        self.model.setHorizontalHeaderLabels(["Method"])
        self.view.setModel(self.model)
        self.view.setItemDelegate(self.ItemDelegate())
Exemple #8
0
    def __init__(self):
        super().__init__()

        self.data = None
        self.classifier = None
        self.selected = None

        self.model = CustomRuleViewerTableModel(parent=self)
        self.model.set_horizontal_header_labels(
            ["如果条件", "", "然后类别", "分布", "概率 [%]", "质量", "长度"])

        self.proxy_model = QSortFilterProxyModel(parent=self)
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.setSortRole(self.model.SortRole)

        self.view = gui.TableView(self, wordWrap=False)
        self.view.setModel(self.proxy_model)
        self.view.verticalHeader().setVisible(True)
        self.view.horizontalHeader().setStretchLastSection(False)
        self.view.selectionModel().selectionChanged.connect(self.commit)

        self.dist_item_delegate = DistributionItemDelegate(self)
        self.view.setItemDelegateForColumn(3, self.dist_item_delegate)

        self.controlArea.layout().addWidget(self.view)

        gui.checkBox(
            widget=self.buttonsArea,
            master=self,
            value="compact_view",
            label="紧凑型视图",
            callback=self.on_update,
        )
        gui.rubber(self.buttonsArea)

        original_order_button = gui.button(
            self.buttonsArea,
            self,
            "恢复原始顺序",
            autoDefault=False,
            callback=self.restore_original_order,
            attribute=Qt.WA_LayoutUsesWidgetRect,
        )
        original_order_button.clicked.connect(self.restore_original_order)
    def test_report_table(self):
        rep = OWReport.get_instance()
        model = PyTableModel([["x", 1, 2], ["y", 2, 2]])
        model.setHorizontalHeaderLabels(["a", "b", "c"])

        model.setData(model.index(0, 0), Qt.AlignHCenter | Qt.AlignTop,
                      Qt.TextAlignmentRole)
        model.setData(model.index(1, 0), QFont("", -1, QFont.Bold),
                      Qt.FontRole)
        model.setData(model.index(1, 2), QBrush(Qt.red), Qt.BackgroundRole)

        view = gui.TableView()
        view.show()
        view.setModel(model)
        rep.report_table("Name", view)
        self.maxDiff = None
        self.assertEqual(
            rep.report_html,
            "<h2>Name</h2><table>\n"
            "<tr>"
            '<th style="color:black;border:0;background:transparent;'
            'text-align:left;vertical-align:middle;">a</th>'
            '<th style="color:black;border:0;background:transparent;'
            'text-align:left;vertical-align:middle;">b</th>'
            '<th style="color:black;border:0;background:transparent;'
            'text-align:left;vertical-align:middle;">c</th>'
            "</tr>"
            "<tr>"
            '<td style="color:black;border:0;background:transparent;'
            'text-align:center;vertical-align:top;">x</td>'
            '<td style="color:black;border:0;background:transparent;'
            'text-align:right;vertical-align:middle;">1</td>'
            '<td style="color:black;border:0;background:transparent;'
            'text-align:right;vertical-align:middle;">2</td>'
            "</tr>"
            "<tr>"
            '<td style="color:black;border:0;background:transparent;'
            'font-weight: bold;text-align:left;vertical-align:middle;">y</td>'
            '<td style="color:black;border:0;background:transparent;'
            'text-align:right;vertical-align:middle;">2</td>'
            '<td style="color:black;border:0;background:#ff0000;'
            'text-align:right;vertical-align:middle;">2</td>'
            "</tr></table>",
        )
Exemple #10
0
    def __init__(self):
        super().__init__()

        self.data = None
        self.test_data = None
        self.preprocessor = None
        self.train_data_missing_vals = False
        self.test_data_missing_vals = False
        self.scorers = []

        #: An Ordered dictionary with current inputs and their testing results.
        self.learners = OrderedDict()  # type: Dict[Any, Input]

        self.__state = State.Waiting
        # Do we need to [re]test any learners, set by _invalidate and
        # cleared by __update
        self.__needupdate = False
        self.__task = None  # type: Optional[Task]
        self.__executor = ThreadExecutor()

        sbox = gui.vBox(self.controlArea, "Sampling")
        rbox = gui.radioButtons(sbox,
                                self,
                                "resampling",
                                callback=self._param_changed)

        gui.appendRadioButton(rbox, "Cross validation")
        ibox = gui.indentedBox(rbox)
        gui.comboBox(ibox,
                     self,
                     "n_folds",
                     label="Number of folds: ",
                     items=[str(x) for x in self.NFolds],
                     maximumContentsLength=3,
                     orientation=Qt.Horizontal,
                     callback=self.kfold_changed)
        gui.checkBox(ibox,
                     self,
                     "cv_stratified",
                     "Stratified",
                     callback=self.kfold_changed)
        gui.appendRadioButton(rbox, "Cross validation by feature")
        ibox = gui.indentedBox(rbox)
        self.feature_model = DomainModel(order=DomainModel.METAS,
                                         valid_types=DiscreteVariable)
        self.features_combo = gui.comboBox(ibox,
                                           self,
                                           "fold_feature",
                                           model=self.feature_model,
                                           orientation=Qt.Horizontal,
                                           callback=self.fold_feature_changed)

        gui.appendRadioButton(rbox, "Random sampling")
        ibox = gui.indentedBox(rbox)
        gui.comboBox(ibox,
                     self,
                     "n_repeats",
                     label="Repeat train/test: ",
                     items=[str(x) for x in self.NRepeats],
                     maximumContentsLength=3,
                     orientation=Qt.Horizontal,
                     callback=self.shuffle_split_changed)
        gui.comboBox(ibox,
                     self,
                     "sample_size",
                     label="Training set size: ",
                     items=["{} %".format(x) for x in self.SampleSizes],
                     maximumContentsLength=5,
                     orientation=Qt.Horizontal,
                     callback=self.shuffle_split_changed)
        gui.checkBox(ibox,
                     self,
                     "shuffle_stratified",
                     "Stratified",
                     callback=self.shuffle_split_changed)

        gui.appendRadioButton(rbox, "Leave one out")

        gui.appendRadioButton(rbox, "Test on train data")
        gui.appendRadioButton(rbox, "Test on test data")

        self.cbox = gui.vBox(self.controlArea, "Target Class")
        self.class_selection_combo = gui.comboBox(
            self.cbox,
            self,
            "class_selection",
            items=[],
            sendSelectedValue=True,
            valueType=str,
            callback=self._on_target_class_changed,
            contentsLength=8)

        gui.rubber(self.controlArea)

        self.view = gui.TableView(wordWrap=True, )
        header = self.view.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.ResizeToContents)
        header.setDefaultAlignment(Qt.AlignCenter)
        header.setStretchLastSection(False)
        header.setContextMenuPolicy(Qt.CustomContextMenu)
        header.customContextMenuRequested.connect(self.show_column_chooser)

        self.result_model = QStandardItemModel(self)
        self.result_model.setHorizontalHeaderLabels(["Method"])
        self.view.setModel(self.result_model)
        self.view.setItemDelegate(ItemDelegate())

        box = gui.vBox(self.mainArea, "Evaluation Results")
        box.layout().addWidget(self.view)
Exemple #11
0
    def __init__(self):
        super().__init__()
        self.data = None
        self.domainmodels = []
        self.unmatched = []

        top = self.controlArea

        def _radioChanged():
            self.mainArea.setVisible(self.is_decoding == 0
                                     and len(self.unmatched))
            self.commit()

        modes = gui.radioButtons(top,
                                 self,
                                 'is_decoding',
                                 callback=_radioChanged)

        gui.appendRadioButton(
            modes,
            '&Encode region names into geographical coordinates:',
            insertInto=top)
        box = gui.indentedBox(top)
        model = DomainModel(parent=self,
                            valid_types=(StringVariable, DiscreteVariable))
        self.domainmodels.append(model)

        combo = gui.comboBox(box,
                             self,
                             'str_attr',
                             label='Region identifier:',
                             orientation=Qt.Horizontal,
                             callback=self.region_attr_changed,
                             sendSelectedValue=True,
                             model=model)
        gui.comboBox(box,
                     self,
                     'str_type',
                     label='Identifier type:',
                     orientation=Qt.Horizontal,
                     items=tuple(self.ID_TYPE.keys()),
                     callback=lambda: self.commit(),
                     sendSelectedValue=True)

        # Select first mode if any of its combos are changed
        for combo in box.findChildren(QComboBox):
            combo.activated.connect(lambda: setattr(self, 'is_decoding', 0))

        gui.appendRadioButton(modes,
                              '&Decode latitude and longitude into regions:',
                              insertInto=top)
        box = gui.indentedBox(top)
        model = DomainModel(parent=self, valid_types=ContinuousVariable)
        self.domainmodels.append(model)
        combo = gui.comboBox(box,
                             self,
                             'lat_attr',
                             label='Latitude:',
                             orientation=Qt.Horizontal,
                             callback=lambda: self.commit(),
                             sendSelectedValue=True,
                             model=model)
        combo = gui.comboBox(box,
                             self,
                             'lon_attr',
                             label='Longitude:',
                             orientation=Qt.Horizontal,
                             callback=lambda: self.commit(),
                             sendSelectedValue=True,
                             model=model)
        gui.comboBox(
            box,
            self,
            'admin',
            label='Administrative level:',
            orientation=Qt.Horizontal,
            callback=lambda: self.commit(),
            items=
            ('Country',
             '1st-level subdivision (state, region, province, municipality, ...)',
             '2nd-level subdivisions (1st-level & US counties)'),
        )

        # Select second mode if any of its combos are changed
        for combo in box.findChildren(QComboBox):
            combo.activated.connect(lambda: setattr(self, 'is_decoding', 1))

        gui.checkBox(
            top,
            self,
            'append_features',
            label='E&xtend coded data with additional region properties',
            callback=lambda: self.commit(),
            toolTip='Extend coded data with region properties, such as'
            'ISO codes, continent, subregion, region type, '
            'economy type, FIPS/HASC codes, region capital etc. as available.')

        gui.auto_commit(self.controlArea, self, 'autocommit', '&Apply')
        gui.rubber(self.controlArea)

        model = self.replacementsModel = PyTableModel(self.replacements,
                                                      parent=self,
                                                      editable=[False, True])
        view = gui.TableView(self,
                             sortingEnabled=False,
                             selectionMode=gui.TableView.NoSelection,
                             editTriggers=gui.TableView.AllEditTriggers)
        view.horizontalHeader().setResizeMode(QHeaderView.Stretch)
        view.verticalHeader().setSectionResizeMode(0)
        view.setModel(model)

        owwidget = self

        class TableItemDelegate(QItemDelegate):
            def createEditor(self, parent, options, index):
                nonlocal owwidget
                edit = QLineEdit(parent)
                wordlist = [''] + ToLatLon.valid_values(
                    owwidget.ID_TYPE[owwidget.str_type])
                edit.setCompleter(
                    QCompleter(wordlist,
                               edit,
                               caseSensitivity=Qt.CaseInsensitive,
                               filterMode=Qt.MatchContains))

                def save_and_commit():
                    if edit.text() and edit.text() in wordlist:
                        model = index.model()
                        pindex = QPersistentModelIndex(index)
                        if pindex.isValid():
                            new_index = pindex.sibling(pindex.row(),
                                                       pindex.column())
                            save = model.setData(new_index, edit.text(),
                                                 Qt.EditRole)
                            if save:
                                owwidget.commit()
                                return
                    edit.clear()

                edit.editingFinished.connect(save_and_commit)
                return edit

        view.setItemDelegate(TableItemDelegate())
        model.setHorizontalHeaderLabels(
            ['Unmatched Identifier', 'Custom Replacement'])
        box = gui.vBox(self.mainArea)
        self.info_str = ' /'
        gui.label(box, self, 'Unmatched identifiers: %(info_str)s')
        box.layout().addWidget(view)
        self.mainArea.setVisible(self.is_decoding == 0)
Exemple #12
0
    def __init__(self):
        super().__init__()

        self.data = None
        self.test_data = None
        self.preprocessor = None
        self.train_data_missing_vals = False
        self.test_data_missing_vals = False

        #: An Ordered dictionary with current inputs and their testing results.
        self.learners = OrderedDict()

        sbox = gui.vBox(self.controlArea, "Sampling")
        rbox = gui.radioButtons(
            sbox, self, "resampling", callback=self._param_changed)

        gui.appendRadioButton(rbox, "Cross validation")
        ibox = gui.indentedBox(rbox)
        gui.comboBox(
            ibox, self, "n_folds", label="Number of folds: ",
            items=[str(x) for x in self.NFolds], maximumContentsLength=3,
            orientation=Qt.Horizontal, callback=self.kfold_changed)
        gui.checkBox(
            ibox, self, "cv_stratified", "Stratified",
            callback=self.kfold_changed)

        gui.appendRadioButton(rbox, "Random sampling")
        ibox = gui.indentedBox(rbox)
        gui.comboBox(
            ibox, self, "n_repeats", label="Repeat train/test: ",
            items=[str(x) for x in self.NRepeats], maximumContentsLength=3,
            orientation=Qt.Horizontal, callback=self.shuffle_split_changed)
        gui.comboBox(
            ibox, self, "sample_size", label="Training set size: ",
            items=["{} %".format(x) for x in self.SampleSizes],
            maximumContentsLength=5, orientation=Qt.Horizontal,
            callback=self.shuffle_split_changed)
        gui.checkBox(
            ibox, self, "shuffle_stratified", "Stratified",
            callback=self.shuffle_split_changed)

        gui.appendRadioButton(rbox, "Leave one out")

        gui.appendRadioButton(rbox, "Test on train data")
        gui.appendRadioButton(rbox, "Test on test data")

        self.cbox = gui.vBox(self.controlArea, "Target Class")
        self.class_selection_combo = gui.comboBox(
            self.cbox, self, "class_selection", items=[],
            sendSelectedValue=True, valueType=str,
            callback=self._on_target_class_changed,
            contentsLength=8)

        gui.rubber(self.controlArea)

        self.view = gui.TableView(
            wordWrap=True,
        )
        header = self.view.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.ResizeToContents)
        header.setDefaultAlignment(Qt.AlignCenter)
        header.setStretchLastSection(False)

        self.result_model = QStandardItemModel(self)
        self.result_model.setHorizontalHeaderLabels(["Method"])
        self.view.setModel(self.result_model)
        self.view.setItemDelegate(ItemDelegate())

        box = gui.vBox(self.mainArea, "Evaluation Results")
        box.layout().addWidget(self.view)
Exemple #13
0
    def __init__(self):
        super().__init__()
        self.data = None
        self.domainmodels = []

        top = self.controlArea

        def _radioChanged():
            self.mainArea.setVisible(self.is_decoding == 0)
            self.commit()

        modes = gui.radioButtons(top,
                                 self,
                                 'is_decoding',
                                 callback=_radioChanged)

        gui.appendRadioButton(
            modes,
            '&Encode region names into geographical coordinates:',
            insertInto=top)
        box = gui.indentedBox(top)
        model = DomainModel(parent=self,
                            valid_types=(StringVariable, DiscreteVariable))
        self.domainmodels.append(model)

        def _region_attr_changed():
            if self.data is None:
                return

            # Auto-detect the type of region in the attribute and set its combo
            values = self._get_data_values()
            func = ToLatLon.detect_input(values)
            str_type = next((k for k, v in self.ID_TYPE.items() if v == func),
                            None)
            if str_type is not None and str_type != self.str_type:
                self.str_type = str_type

            self.commit()

        combo = gui.comboBox(box,
                             self,
                             'str_attr',
                             label='Region identifier:',
                             orientation=Qt.Horizontal,
                             callback=_region_attr_changed,
                             sendSelectedValue=True)
        combo.setModel(model)
        gui.comboBox(box,
                     self,
                     'str_type',
                     label='Identifier type:',
                     orientation=Qt.Horizontal,
                     items=tuple(self.ID_TYPE.keys()),
                     callback=lambda: self.commit(),
                     sendSelectedValue=True)

        # Select first mode if any of its combos are changed
        for combo in box.findChildren(QComboBox):
            combo.currentIndexChanged.connect(
                lambda: setattr(self, 'is_decoding', 0))

        gui.appendRadioButton(modes,
                              '&Decode latitude and longitude into regions:',
                              insertInto=top)
        box = gui.indentedBox(top)
        model = DomainModel(parent=self, valid_types=ContinuousVariable)
        self.domainmodels.append(model)
        combo = gui.comboBox(box,
                             self,
                             'lat_attr',
                             label='Latitude:',
                             orientation=Qt.Horizontal,
                             callback=lambda: self.commit(),
                             sendSelectedValue=True)
        combo.setModel(model)
        combo = gui.comboBox(box,
                             self,
                             'lon_attr',
                             label='Longitude:',
                             orientation=Qt.Horizontal,
                             callback=lambda: self.commit(),
                             sendSelectedValue=True)
        combo.setModel(model)
        gui.comboBox(
            box,
            self,
            'admin',
            label='Administrative level:',
            orientation=Qt.Horizontal,
            callback=lambda: self.commit(),
            items=
            ('Country',
             '1st-level subdivision (state, region, province, municipality, ...)',
             '2nd-level subdivisions (1st-level & US counties)'),
        )

        # Select second mode if any of its combos are changed
        for combo in box.findChildren(QComboBox):
            combo.currentIndexChanged.connect(
                lambda: setattr(self, 'is_decoding', 1))

        gui.checkBox(
            top,
            self,
            'append_features',
            label='E&xtend coded data with additional region properties',
            callback=lambda: self.commit(),
            toolTip='Extend coded data with region properties, such as'
            'ISO codes, continent, subregion, region type, '
            'economy type, FIPS/HASC codes, region capital etc. as available.')

        gui.auto_commit(self.controlArea, self, 'autocommit', '&Apply')

        model = self.replacementsModel = PyTableModel(self.replacements,
                                                      parent=self,
                                                      editable=[False, True])
        view = gui.TableView(self,
                             sortingEnabled=False,
                             selectionMode=gui.TableView.NoSelection,
                             editTriggers=gui.TableView.AllEditTriggers)
        view.horizontalHeader().setSectionResizeMode(0)
        view.verticalHeader().setSectionResizeMode(0)
        view.setModel(model)

        owwidget = self

        class EditorFactory(QItemEditorFactory):
            def createEditor(self, p_int, parent):
                nonlocal owwidget
                edit = QLineEdit(parent)
                wordlist = [''] + ToLatLon.valid_values(
                    owwidget.ID_TYPE[owwidget.str_type])
                edit.setCompleter(
                    QCompleter(wordlist,
                               edit,
                               caseSensitivity=Qt.CaseInsensitive,
                               filterMode=Qt.MatchContains))
                return edit

        self.factory = EditorFactory()
        view.itemDelegate().setItemEditorFactory(self.factory)
        model.setHorizontalHeaderLabels(
            ['Unmatched Identifier', 'Custom Replacement'])
        box = gui.vBox(self.mainArea)
        self.info_str = ' /'
        gui.label(box, self, 'Unmatched identifiers: %(info_str)s')
        box.layout().addWidget(view)
        self.mainArea.setVisible(self.is_decoding == 0)
    def __init__(self):
        self.model = None

        self._task = None  # type: Optional[self.Task]
        self._executor = ThreadExecutor(self)
        self.is_downloading = False

        box = gui.vBox(self.controlArea, 'Database Connection')
        gui.lineEdit(box,
                     self,
                     'con_hostname',
                     label='Hostname:',
                     orientation=Qt.Horizontal,
                     validator=Validator.Hostname())
        gui.lineEdit(box,
                     self,
                     'con_port',
                     label='Port:',
                     orientation=Qt.Horizontal,
                     validator=Validator.Port())
        gui.lineEdit(box,
                     self,
                     'con_username',
                     label='Username:'******'con_password',
                            label='Password:'******'con_database',
                     label='Database:',
                     orientation=Qt.Horizontal)
        gui.spin(box, self, 'con_timeout', 5, 300, 5, label='Timeout [s]:')
        self.btn_connect = gui.button(box,
                                      self,
                                      self.LABEL_CONNECT,
                                      callback=self.load_data)

        box = gui.vBox(self.controlArea, 'Download')

        def _dateTimeChanged(editted):
            def handler():
                minTime = self.date_from.dateTime().toMSecsSinceEpoch() / 1000
                maxTime = self.date_to.dateTime().toMSecsSinceEpoch() / 1000
                if minTime > maxTime:
                    minTime = maxTime = minTime if editted == self.date_from else maxTime

                    other = self.date_to if editted == self.date_from else self.date_from
                    with blockSignals(other):
                        other.setDateTime(editted.dateTime())

                    self.btn_download.setEnabled(minTime != maxTime)

                # Update saved settings
                self.sample_ts_from = minTime
                self.sample_ts_to = maxTime

            return handler

        kwargs = dict(calendarPopup=True,
                      displayFormat=' '.join(self.DATE_FORMATS),
                      timeSpec=Qt.UTC)
        date_from = self.date_from = QDateTimeEdit(self, **kwargs)
        date_to = self.date_to = QDateTimeEdit(self, **kwargs)
        date_from.setDateTime(
            QDateTime.fromMSecsSinceEpoch(self.sample_ts_from * 1000, Qt.UTC))
        date_to.setDateTime(
            QDateTime.fromMSecsSinceEpoch(self.sample_ts_to * 1000, Qt.UTC))
        date_from.dateTimeChanged.connect(_dateTimeChanged(date_from))
        date_to.dateTimeChanged.connect(_dateTimeChanged(date_to))

        hbox = gui.hBox(box)
        hbox.layout().addWidget(QLabel('From:'))
        hbox.layout().addWidget(date_from)
        hbox = gui.hBox(box)
        hbox.layout().addWidget(QLabel('To:'))
        hbox.layout().addWidget(date_to)

        self.box_include_data = gui.vBox(box, 'Include')

        gui.spin(box,
                 self,
                 'sample_size',
                 100,
                 20000,
                 100,
                 label='Sample size:')
        gui.comboBox(box,
                     self,
                     'sample_resolution',
                     label='Resolution:',
                     orientation=Qt.Horizontal,
                     items=tuple(self.RESOLUTION.keys()),
                     sendSelectedValue=True)
        gui.comboBox(box,
                     self,
                     'sample_interpolation',
                     label='Interpolation:',
                     orientation=Qt.Horizontal,
                     items=tuple(self.INTERPOLATION.keys()),
                     sendSelectedValue=True)

        self.btn_download = gui.button(box,
                                       self,
                                       self.LABEL_DOWNLOAD,
                                       callback=self.download)
        gui.rubber(self.controlArea)

        ## Main area

        class Model(PyTableModel):
            def update_row(self, i, row):
                self[i] = row

        model = self.model = Model(parent=self)
        model.setHorizontalHeaderLabels([
            'Node Id', 'Interfaces', 'Start Time', 'Stop Time',
            'Available Data'
        ])
        view = self.view = gui.TableView(self)
        view.horizontalHeader().setStretchLastSection(False)
        view.setModel(self.model)
        self.mainArea.layout().addWidget(view)

        # Restore node info table from cache, if any
        try:
            lst = CachedNodeInfoTable.load_list()
        except Exception:
            pass  # Cache not exists
        else:
            model.wrap(lst)

        # Restore tables checkboxes from cache
        try:
            tables = CachedNodeInfoTable.load_tables()
        except Exception:
            pass
        else:
            for table in tables:
                self.box_include_data.layout().addWidget(
                    QCheckBox(table, self, checked=table
                              in self.included_data))

        # Establish default database connection from settings
        set_connection_params(self.con_hostname,
                              self.con_port,
                              self.con_username,
                              self.con_password,
                              self.con_database,
                              timeout=self.con_timeout)