Пример #1
0
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab

        # initialize the map for locating sections
        canvas = LineMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False
        self.locateSections = QAction('Locate sections\non map', self, icon=self.style().standardIcon(QStyle.SP_DialogHelpButton),
                                      triggered=self.locateSectionsEvent)
        self.locateSections_short = QAction('Locate sections\non map', self,
                                            icon=self.style().standardIcon(QStyle.SP_DialogHelpButton),
                                            triggered=self.locateSectionsEvent)
        self.map.closeEvent = self.enable_locate
        self.cumulativeFluxAct = QAction('Show\ncumulative flux', self, checkable=True,
                                         icon=self.style().standardIcon(QStyle.SP_DialogApplyButton))
        self.cumulativeFluxAct.toggled.connect(self.changeFluxType)

        self.toolBar.addAction(self.locateSections)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.selectColumnsAct)
        self.toolBar.addAction(self.editColumnNamesAct)
        self.toolBar.addAction(self.editColumColorAct)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.convertTimeAct)
        self.toolBar.addAction(self.changeDateAct)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.cumulativeFluxAct)

        self.mapMenu = QMenu('&Map', self)
        self.mapMenu.addAction(self.locateSections_short)
        self.menuBar.addMenu(self.mapMenu)
        self.menuBar.addMenu(self.poly_menu)
Пример #2
0
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab

        # initialize the map for locating polygons
        canvas = PolygonMapCanvas()
        self.map = MapViewer(canvas)

        self.has_map = False
        self.locatePolygons = QAction('Locate polygons\non map',
                                      self,
                                      icon=self.style().standardIcon(
                                          QStyle.SP_DialogHelpButton),
                                      triggered=self.locatePolygonsEvent)
        self.locatePolygons_short = QAction('Locate polygons on map',
                                            self,
                                            icon=self.style().standardIcon(
                                                QStyle.SP_DialogHelpButton),
                                            triggered=self.locatePolygonsEvent)
        self.map.closeEvent = self.enable_locate
        self.toolBar.addAction(self.locatePolygons)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.selectColumnsAct)
        self.toolBar.addAction(self.editColumnNamesAct)
        self.toolBar.addAction(self.editColumColorAct)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.convertTimeAct)
        self.toolBar.addAction(self.changeDateAct)

        self.mapMenu = QMenu('&Map', self)
        self.mapMenu.addAction(self.locatePolygons_short)
        self.menuBar.addMenu(self.mapMenu)
        self.menuBar.addMenu(self.poly_menu)
Пример #3
0
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab

        self.has_map = False
        canvas = MapCanvas()
        self.map = MapViewer(canvas)

        self.var_IDs = []
        self.current_var = ''
        self.openAttributes = QAction('Attributes\nTable',
                                      self,
                                      icon=self.style().standardIcon(
                                          QStyle.SP_FileDialogListView),
                                      triggered=self.openAttributesEvent)
        self.openAttributes_short = QAction('Attributes Table',
                                            self,
                                            icon=self.style().standardIcon(
                                                QStyle.SP_FileDialogListView),
                                            triggered=self.openAttributesEvent)
        self.locatePoints = QAction('Locate points\non map',
                                    self,
                                    icon=self.style().standardIcon(
                                        QStyle.SP_DialogHelpButton),
                                    triggered=self.map_event)
        self.locatePoints_short = QAction('Locate points on map',
                                          self,
                                          icon=self.style().standardIcon(
                                              QStyle.SP_DialogHelpButton),
                                          triggered=self.map_event)
        self.input.map.closeEvent = self.enable_locate
        self.input.attribute_table.closeEvent = self.enable_attribute

        self.toolBar.addAction(self.locatePoints)
        self.toolBar.addAction(self.openAttributes)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.select_variable)
        self.toolBar.addAction(self.selectColumnsAct)
        self.toolBar.addAction(self.editColumnNamesAct)
        self.toolBar.addAction(self.editColumColorAct)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.convertTimeAct)
        self.toolBar.addAction(self.changeDateAct)

        self.mapMenu = QMenu('&Map', self)
        self.mapMenu.addAction(self.locatePoints)
        self.pointsMenu = QMenu('&Data', self)
        self.pointsMenu.addAction(self.openAttributes_short)
        self.pointsMenu.addSeparator()
        self.pointsMenu.addAction(self.select_variable_short)
        self.pointsMenu.addAction(self.selectColumnsAct_short)
        self.pointsMenu.addAction(self.editColumnNamesAct_short)
        self.pointsMenu.addAction(self.editColumColorAct_short)

        self.menuBar.addMenu(self.mapMenu)
        self.menuBar.addMenu(self.pointsMenu)
Пример #4
0
    def __init__(self, parent):
        super().__init__(parent)
        canvas = LineMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False

        self.data = None
        self.mesh = None

        self.lines = []
        self.line_interpolators = []
        self.line_interpolators_internal = []  # without intersection points

        self._initWidgets()  # some instance attributes will be set there
        self._setLayout()
        self._bindEvents()
Пример #5
0
    def __init__(self, parent):
        super().__init__(parent)
        self.ref_data = None
        self.test_data = None
        self.ref_mesh = None

        self.polygons = []
        self.selected_polygon = None
        self.ref_mesh = None
        self.polygon_added = False  # is the intersection between the mesh and the selected polygon calculated?

        # initialize the map for locating polygons
        canvas = PolygonMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False

        self._initWidgets()
        self._setLayout()
        self._bindEvents()
Пример #6
0
    def __init__(self, parent):
        super().__init__(parent)
        self.old_frequency = '1'

        canvas = MapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False

        self.data = None
        self.mesh = None

        self.points = []
        self.point_interpolators = []
        self.fields = []
        self.attributes = []
        self.attribute_table = PointAttributeTable()

        self._initWidgets()  # some instance attributes will be set there
        self._setLayout()
        self._bindEvents()
Пример #7
0
class ImageTab(VolumePlotViewer):
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab

        # initialize the map for locating polygons
        canvas = PolygonMapCanvas()
        self.map = MapViewer(canvas)

        self.has_map = False
        self.locatePolygons = QAction('Locate polygons\non map',
                                      self,
                                      icon=self.style().standardIcon(
                                          QStyle.SP_DialogHelpButton),
                                      triggered=self.locatePolygonsEvent)
        self.locatePolygons_short = QAction('Locate polygons on map',
                                            self,
                                            icon=self.style().standardIcon(
                                                QStyle.SP_DialogHelpButton),
                                            triggered=self.locatePolygonsEvent)
        self.map.closeEvent = self.enable_locate
        self.toolBar.addAction(self.locatePolygons)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.selectColumnsAct)
        self.toolBar.addAction(self.editColumnNamesAct)
        self.toolBar.addAction(self.editColumColorAct)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.convertTimeAct)
        self.toolBar.addAction(self.changeDateAct)

        self.mapMenu = QMenu('&Map', self)
        self.mapMenu.addAction(self.locatePolygons_short)
        self.menuBar.addMenu(self.mapMenu)
        self.menuBar.addMenu(self.poly_menu)

    def enable_locate(self, event):
        self.locatePolygons.setEnabled(True)
        self.locatePolygons_short.setEnabled(True)

    def getData(self):
        # get the new data
        csv_file = self.input.csvNameBox.text()
        self.data, headers = read_csv(csv_file,
                                      self.input.parent.csv_separator)

        self.var_ID = self.input.var_ID
        self.second_var_ID = self.input.second_var_ID
        if self.input.data.header.date is not None:
            year, month, day, hour, minute, second = self.input.data.header.date
            self.start_time = datetime.datetime(year, month, day, hour, minute,
                                                second)
        else:
            self.start_time = datetime.datetime(1900, 1, 1, 0, 0, 0)
        self.datetime = list(
            map(lambda x: self.start_time + datetime.timedelta(seconds=x),
                self.data['time']))

        self.str_datetime = list(
            map(lambda x: x.strftime('%Y/%m/%d\n%H:%M'), self.datetime))
        self.str_datetime_bis = list(
            map(lambda x: x.strftime('%d/%m/%y\n%H:%M'), self.datetime))

        self.columns = headers[1:]
        self.column_labels = {x: x for x in self.columns}
        self.column_colors = {
            column: color
            for column, color in zip(self.columns, cycle(self.defaultColors))
        }

        # initialize the plot
        self.time = [
            self.data['time'], self.data['time'], self.data['time'],
            self.data['time'] / 60, self.data['time'] / 3600,
            self.data['time'] / 86400
        ]
        self.language = self.input.data.language
        self.current_xlabel = self._defaultXLabel()
        self.current_ylabel = self._defaultYLabel()
        self.current_title = ''
        self.replot()

    def locatePolygonsEvent(self):
        if not self.has_map:
            self.map.canvas.reinitFigure(
                self.input.mesh, self.input.polygons,
                map(self.column_labels.get, [
                    'Polygon %d' % (i + 1)
                    for i in range(len(self.input.polygons))
                ]))
            self.has_map = True
        self.locatePolygons.setEnabled(False)
        self.locatePolygons_short.setEnabled(False)
        self.map.show()

    def reset(self):
        self.has_map = False
        self.map.close()

        super().reset()
        self.current_columns = ('Polygon 1', )
Пример #8
0
class InputTab(SerafinInputTab):
    def __init__(self, parent):
        super().__init__(parent)
        self.ref_data = None
        self.test_data = None
        self.ref_mesh = None

        self.polygons = []
        self.selected_polygon = None
        self.ref_mesh = None
        self.polygon_added = False  # is the intersection between the mesh and the selected polygon calculated?

        # initialize the map for locating polygons
        canvas = PolygonMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False

        self._initWidgets()
        self._setLayout()
        self._bindEvents()

    def _initWidgets(self):
        # create the button open the reference file
        self.btnOpen.setText('Load\nReference')

        # create the button open the test file
        self.btnOpenTest = QPushButton('Load\nTest',
                                       self,
                                       icon=self.style().standardIcon(
                                           QStyle.SP_DialogOpenButton))
        self.btnOpenTest.setToolTip('<b>Open</b> a Serafin file')
        self.btnOpenTest.setFixedSize(105, 50)
        self.btnOpenTest.setEnabled(False)

        # create the button open the polygon file
        self.btnOpenPolygon = QPushButton('Load polygons\n(optional)',
                                          self,
                                          icon=self.style().standardIcon(
                                              QStyle.SP_DialogOpenButton))
        self.btnOpenPolygon.setToolTip('<b>Open</b> a .i2s or .shp file')
        self.btnOpenPolygon.setFixedSize(135, 50)
        self.btnOpenPolygon.setEnabled(False)

        # create the button for locating polygons on map
        self.locatePolygons = QPushButton('Locate polygons\non map',
                                          icon=self.style().standardIcon(
                                              QStyle.SP_DialogHelpButton))
        self.locatePolygons.setToolTip('<b>Open</b> a map with polygons')
        self.locatePolygons.setFixedSize(135, 50)
        self.locatePolygons.setEnabled(False)

        # create some text fields displaying the IO files info
        self.testNameBox = QLineEdit()
        self.testNameBox.setReadOnly(True)
        self.testNameBox.setFixedHeight(30)
        self.testNameBox.setMinimumWidth(600)
        self.testSummaryTextBox = QPlainTextEdit()
        self.testSummaryTextBox.setReadOnly(True)
        self.testSummaryTextBox.setMinimumHeight(40)
        self.testSummaryTextBox.setMaximumHeight(50)
        self.testSummaryTextBox.setMinimumWidth(600)
        self.polygonNameBox = QPlainTextEdit()
        self.polygonNameBox.setReadOnly(True)
        self.polygonNameBox.setFixedHeight(50)
        self.polygonNameBox.setMinimumWidth(600)

        # create combo box widgets for choosing the variable
        self.varBox = QComboBox()
        self.varBox.setFixedSize(400, 30)

        # create combo box widgets for choosing the polygon
        self.polygonBox = QComboBox()
        self.polygonBox.setFixedSize(400, 30)

    def _bindEvents(self):
        self.btnOpen.clicked.connect(self.btnOpenRefEvent)
        self.btnOpenTest.clicked.connect(self.btnOpenTestEvent)
        self.btnOpenPolygon.clicked.connect(self.btnOpenPolygonEvent)
        self.locatePolygons.clicked.connect(self.locatePolygonsEvent)
        self.polygonBox.currentTextChanged.connect(self.selectPolygonEvent)
        self.map.closeEvent = lambda event: self.locatePolygons.setEnabled(True
                                                                           )

    def _setLayout(self):
        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 20))
        mainLayout.setSpacing(15)

        hlayout = QHBoxLayout()
        hlayout.setAlignment(Qt.AlignLeft)
        hlayout.addItem(QSpacerItem(50, 1))
        hlayout.addWidget(self.btnOpen)
        hlayout.addWidget(self.btnOpenTest)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.langBox)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.btnOpenPolygon)
        hlayout.addWidget(self.locatePolygons)
        hlayout.setSpacing(10)
        mainLayout.addLayout(hlayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        glayout = QGridLayout()
        glayout.addWidget(QLabel('     Reference'), 1, 1)
        glayout.addWidget(self.inNameBox, 1, 2)
        glayout.addWidget(QLabel('     Summary'), 2, 1)
        glayout.addWidget(self.summaryTextBox, 2, 2)
        glayout.addWidget(QLabel('     Test'), 3, 1)
        glayout.addWidget(self.testNameBox, 3, 2)
        glayout.addWidget(QLabel('     Summary'), 4, 1)
        glayout.addWidget(self.testSummaryTextBox, 4, 2)
        glayout.addWidget(QLabel('     Polygons'), 5, 1)
        glayout.addWidget(self.polygonNameBox, 5, 2)
        glayout.setAlignment(Qt.AlignLeft)
        glayout.setVerticalSpacing(10)

        mainLayout.addLayout(glayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        glayout = QGridLayout()
        glayout.addWidget(QLabel('     Select the variable to compare'), 1, 1)
        glayout.addWidget(self.varBox, 1, 2)
        glayout.addWidget(QLabel('     Select the comparison domain'), 2, 1)
        glayout.addWidget(self.polygonBox, 2, 2)
        glayout.setSpacing(10)
        mainLayout.addLayout(glayout)
        mainLayout.setAlignment(glayout, Qt.AlignTop | Qt.AlignLeft)

        mainLayout.addItem(QSpacerItem(30, 15))
        mainLayout.addWidget(QLabel('   Message logs'))
        mainLayout.addWidget(self.logTextBox.widget)
        self.setLayout(mainLayout)
        self.setLayout(mainLayout)

    def _reinitRef(self):
        self.reset()
        self.ref_mesh = None
        self.ref_data = None
        self.polygon_added = False
        self.selected_polygon = None
        self.polygons = []

        self.test_data = None
        self.testSummaryTextBox.clear()
        self.testNameBox.clear()
        self.polygonNameBox.clear()
        self.varBox.clear()
        self.polygonBox.clear()
        self.btnOpenTest.setEnabled(False)
        self.btnOpenPolygon.setEnabled(False)
        self.locatePolygons.setEnabled(False)

        self.map.hide()
        self.has_map = False
        self.parent.reset()

    def _reinitTest(self, filename):
        self.test_data = None
        self.testNameBox.setText(filename)
        self.testSummaryTextBox.clear()
        self.varBox.clear()

    def locatePolygonsEvent(self):
        if not self.has_map:
            self.map.canvas.reinitFigure(
                self.ref_mesh, self.polygons,
                ['Polygon %d' % (i + 1) for i in range(len(self.polygons))])
            self.has_map = True
        self.locatePolygons.setEnabled(False)
        self.map.show()

    def selectPolygonEvent(self, text):
        if not text:
            return
        elif text == 'Entire mesh':
            self.selected_polygon = None
        else:
            polygon_index = int(text.split()[1]) - 1
            self.selected_polygon = self.polygons[polygon_index]
        self.polygon_added = False

    def btnOpenRefEvent(self):
        canceled, filename = super().open_event()
        if canceled:
            return

        self._reinitRef()
        success, data = self.read_2d(filename)
        if not success:
            return

        self.ref_data = data

        # record the mesh
        self.parent.inDialog()
        meshLoader = LoadMeshDialog('comparison', self.ref_data.header)
        self.ref_mesh = meshLoader.run()
        self.parent.outDialog()
        if meshLoader.thread.canceled:
            self.summaryTextBox.clear()
            self.ref_data = None
            return

        self.parent.add_reference()

        self.btnOpenTest.setEnabled(True)
        self.btnOpenPolygon.setEnabled(True)
        self.polygonBox.addItem('Entire mesh')

    def btnOpenTestEvent(self):
        canceled, filename = super().open_event()
        if canceled:
            return

        self._reinitTest(filename)
        success, data = self.read_2d(filename, update=False)
        if not success:
            return

            # check if the mesh is identical to the reference
        if not np.all(self.ref_data.header.x == data.header.x) or \
           not np.all(self.ref_data.header.y == data.header.y) or \
           not np.all(self.ref_data.header.ikle == data.header.ikle):
            QMessageBox.critical(
                self, 'Error', 'The mesh is not identical to the reference.',
                QMessageBox.Ok)
            return

        # check if the test file has common variables with the reference file
        common_vars = [(var_ID, var_names) for var_ID, var_names in zip(
            self.ref_data.header.var_IDs, self.ref_data.header.var_names)
                       if var_ID in data.header.var_IDs]
        if not common_vars:
            QMessageBox.critical(
                self, 'Error', 'No common variable with the reference file.',
                QMessageBox.Ok)
            return

        self.test_data = data
        self.testNameBox.setText(filename)
        self.testSummaryTextBox.appendPlainText(
            self.test_data.header.summary())

        self.parent.add_test()

        for var_ID, var_name in common_vars:
            self.varBox.addItem(var_ID +
                                ' (%s)' % var_name.decode('utf-8').strip())

    def btnOpenPolygonEvent(self):
        success, filename, polygons = open_polygons()
        if not success:
            return

        self.polygons = polygons
        self.map.close()
        self.map.has_figure = False

        self.polygonNameBox.clear()
        self.polygonNameBox.appendPlainText(
            filename + '\n' + 'The file contains {} polygon{}.'.format(
                len(self.polygons), 's' if len(self.polygons) > 1 else ''))

        self.polygonBox.clear()
        self.polygonBox.addItem('Entire mesh')
        for i in range(len(self.polygons)):
            self.polygonBox.addItem('Polygon %d' % (i + 1))
        self.locatePolygons.setEnabled(True)
Пример #9
0
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab
        self.ewsd = None
        self.xlim = None
        self.ylim = None

        # set up a custom plot viewer
        self.plotViewer = PlotViewer()
        self.plotViewer.exitAct.setEnabled(False)
        self.plotViewer.menuBar.setVisible(False)
        self.XLimitsAct = QAction('Change X limits',
                                  self,
                                  triggered=self.changeXlimits,
                                  enabled=False,
                                  icon=self.style().standardIcon(
                                      QStyle.SP_DialogNoButton))
        self.YLimitsAct = QAction('Change Y limits',
                                  self,
                                  triggered=self.changeYlimits,
                                  enabled=False,
                                  icon=self.style().standardIcon(
                                      QStyle.SP_DialogNoButton))

        self.plotViewer.toolBar.addAction(self.XLimitsAct)
        self.plotViewer.toolBar.addAction(self.YLimitsAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.xLabelAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.yLabelAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.titleAct)

        # put it in a group box to get a nice border
        gb = QGroupBox()
        ly = QHBoxLayout()
        ly.addWidget(self.plotViewer)
        gb.setLayout(ly)
        gb.setStyleSheet(
            'QGroupBox {border: 8px solid rgb(108, 122, 137); border-radius: 6px }'
        )
        gb.setMinimumWidth(600)

        # create the reference time selection widget
        self.timeSelection = DoubleTimeSelection()

        # create the compute button
        self.btnCompute = QPushButton('Compute',
                                      icon=self.style().standardIcon(
                                          QStyle.SP_DialogApplyButton))
        self.btnCompute.setFixedSize(105, 50)
        self.btnCompute.clicked.connect(self.btnComputeEvent)

        # create the color map button
        self.btnColorMap = QPushButton('2D View',
                                       icon=self.style().standardIcon(
                                           QStyle.SP_DialogHelpButton))
        self.btnColorMap.setFixedSize(105, 50)
        self.btnColorMap.clicked.connect(self.btnColorMapEvent)
        self.btnColorMap.setEnabled(False)

        # initialize the map for 2D view
        canvas = ColorMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False
        self.map.closeEvent = lambda event: self.btnColorMap.setEnabled(True)

        # create the stats box
        self.resultBox = QPlainTextEdit()
        self.resultBox.setMinimumWidth(400)
        self.resultBox.setMaximumWidth(600)

        # set layout
        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 10))
        mainLayout.addWidget(self.timeSelection)
        vlayout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.btnColorMap)
        hlayout.addWidget(self.btnCompute)
        hlayout.setSpacing(10)
        vlayout.addLayout(hlayout)
        vlayout.setAlignment(hlayout, Qt.AlignTop | Qt.AlignRight)
        vlayout.addItem(QSpacerItem(10, 10))
        vlayout.addWidget(self.resultBox)
        vlayout.setAlignment(Qt.AlignHCenter)
        hlayout = QHBoxLayout()
        hlayout.addLayout(vlayout)
        hlayout.addWidget(gb, Qt.AlignHCenter)
        hlayout.setSpacing(10)
        mainLayout.addLayout(hlayout)
        self.setLayout(mainLayout)

        # template for text output
        self.template = '=== EWSD distribution between Ref (frame {}) and Test (frame {}) ===\n'\
                        'Mean         \t{:<30}\n' \
                        'Variance     \t{:<30}\n' \
                        'Min          \t{:<30}\n' \
                        'Quartile 25  \t{:<30}\n' \
                        'Median       \t{:<30}\n' \
                        'Quartile 75  \t{:<30}\n' \
                        'Max          \t{:<30}\n'
Пример #10
0
class ErrorDistributionTab(QWidget):
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab
        self.ewsd = None
        self.xlim = None
        self.ylim = None

        # set up a custom plot viewer
        self.plotViewer = PlotViewer()
        self.plotViewer.exitAct.setEnabled(False)
        self.plotViewer.menuBar.setVisible(False)
        self.XLimitsAct = QAction('Change X limits',
                                  self,
                                  triggered=self.changeXlimits,
                                  enabled=False,
                                  icon=self.style().standardIcon(
                                      QStyle.SP_DialogNoButton))
        self.YLimitsAct = QAction('Change Y limits',
                                  self,
                                  triggered=self.changeYlimits,
                                  enabled=False,
                                  icon=self.style().standardIcon(
                                      QStyle.SP_DialogNoButton))

        self.plotViewer.toolBar.addAction(self.XLimitsAct)
        self.plotViewer.toolBar.addAction(self.YLimitsAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.xLabelAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.yLabelAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.titleAct)

        # put it in a group box to get a nice border
        gb = QGroupBox()
        ly = QHBoxLayout()
        ly.addWidget(self.plotViewer)
        gb.setLayout(ly)
        gb.setStyleSheet(
            'QGroupBox {border: 8px solid rgb(108, 122, 137); border-radius: 6px }'
        )
        gb.setMinimumWidth(600)

        # create the reference time selection widget
        self.timeSelection = DoubleTimeSelection()

        # create the compute button
        self.btnCompute = QPushButton('Compute',
                                      icon=self.style().standardIcon(
                                          QStyle.SP_DialogApplyButton))
        self.btnCompute.setFixedSize(105, 50)
        self.btnCompute.clicked.connect(self.btnComputeEvent)

        # create the color map button
        self.btnColorMap = QPushButton('2D View',
                                       icon=self.style().standardIcon(
                                           QStyle.SP_DialogHelpButton))
        self.btnColorMap.setFixedSize(105, 50)
        self.btnColorMap.clicked.connect(self.btnColorMapEvent)
        self.btnColorMap.setEnabled(False)

        # initialize the map for 2D view
        canvas = ColorMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False
        self.map.closeEvent = lambda event: self.btnColorMap.setEnabled(True)

        # create the stats box
        self.resultBox = QPlainTextEdit()
        self.resultBox.setMinimumWidth(400)
        self.resultBox.setMaximumWidth(600)

        # set layout
        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 10))
        mainLayout.addWidget(self.timeSelection)
        vlayout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.btnColorMap)
        hlayout.addWidget(self.btnCompute)
        hlayout.setSpacing(10)
        vlayout.addLayout(hlayout)
        vlayout.setAlignment(hlayout, Qt.AlignTop | Qt.AlignRight)
        vlayout.addItem(QSpacerItem(10, 10))
        vlayout.addWidget(self.resultBox)
        vlayout.setAlignment(Qt.AlignHCenter)
        hlayout = QHBoxLayout()
        hlayout.addLayout(vlayout)
        hlayout.addWidget(gb, Qt.AlignHCenter)
        hlayout.setSpacing(10)
        mainLayout.addLayout(hlayout)
        self.setLayout(mainLayout)

        # template for text output
        self.template = '=== EWSD distribution between Ref (frame {}) and Test (frame {}) ===\n'\
                        'Mean         \t{:<30}\n' \
                        'Variance     \t{:<30}\n' \
                        'Min          \t{:<30}\n' \
                        'Quartile 25  \t{:<30}\n' \
                        'Median       \t{:<30}\n' \
                        'Quartile 75  \t{:<30}\n' \
                        'Max          \t{:<30}\n'

    def add_reference(self):
        self.timeSelection.initRef(self.input.ref_data.header.nb_frames)

    def add_test(self):
        self.timeSelection.initTest(self.input.test_data.header.nb_frames)

    def reset(self):
        self.ewsd = None
        self.xlim = None
        self.ylim = None
        self.has_map = False
        self.timeSelection.clearText()
        self.resultBox.clear()
        self.plotViewer.defaultPlot()
        self.plotViewer.current_title = 'Distribution of EWSD (element-wise signed deviation)'
        self.plotViewer.current_ylabel = 'Frequency'
        self.plotViewer.current_xlabel = 'EWSD'
        self.XLimitsAct.setEnabled(False)
        self.YLimitsAct.setEnabled(False)
        self.btnColorMap.setEnabled(False)

    def changeXlimits(self):
        value, ok = QInputDialog.getText(
            self,
            'Change X limits',
            'Enter the new X limits',
            text=', '.join(
                map(lambda x: '{:+f}'.format(x),
                    self.plotViewer.canvas.axes.get_xlim())))
        if not ok:
            return
        try:
            xmin, xmax = map(float, value.split(','))
        except ValueError:
            QMessageBox.critical(self, 'Error', 'Invalid input.',
                                 QMessageBox.Ok)
            return

        self.xlim = xmin, xmax
        self.updateHistogram()
        self.has_map = False

    def changeYlimits(self):
        value, ok = QInputDialog.getText(
            self,
            'Change Y limits',
            'Enter the new Y limits',
            text=', '.join(
                map(lambda x: '{:+f}'.format(x),
                    self.plotViewer.canvas.axes.get_ylim())))
        if not ok:
            return
        try:
            self.ylim = tuple(map(float, value.split(',')))
        except ValueError:
            QMessageBox.critical(self, 'Error', 'Invalid input.',
                                 QMessageBox.Ok)
            return

        self.plotViewer.canvas.axes.set_ylim(self.ylim)
        self.plotViewer.canvas.draw()

    def updateStats(self, ref_time, test_time):
        ewsd = np.array(list(self.ewsd.values()))
        quantile25, median, quantile75 = np.percentile(ewsd, [25, 50, 75])
        self.resultBox.appendPlainText(
            self.template.format(ref_time + 1, test_time + 1, np.mean(ewsd),
                                 np.var(ewsd, ddof=1), np.min(ewsd),
                                 quantile25, median, quantile75, np.max(ewsd)))

    def updateHistogram(self):
        ewsd = list(self.ewsd.values())
        if self.xlim is not None:
            ewsd = list(
                filter(lambda x: self.xlim[0] <= x <= self.xlim[1], ewsd))

        weights = np.ones_like(
            ewsd
        ) / self.input.ref_mesh.nb_triangles_inside  # make frequency histogram

        self.plotViewer.canvas.axes.clear()
        self.plotViewer.canvas.axes.grid(linestyle='dotted')

        self.plotViewer.canvas.axes.hist(ewsd,
                                         weights=weights,
                                         histtype='bar',
                                         color='g',
                                         edgecolor='k',
                                         alpha=0.5)
        self.plotViewer.canvas.axes.set_xlabel(self.plotViewer.current_xlabel)
        self.plotViewer.canvas.axes.set_ylabel(self.plotViewer.current_ylabel)
        self.plotViewer.canvas.axes.set_title(self.plotViewer.current_title)

        if self.ylim is not None:
            self.plotViewer.canvas.axes.set_ylim(self.ylim)

        self.plotViewer.canvas.draw()

        self.btnColorMap.setEnabled(True)
        self.XLimitsAct.setEnabled(True)
        self.YLimitsAct.setEnabled(True)

    def btnComputeEvent(self):
        self.xlim = None
        self.ylim = None
        self.has_map = False

        ref_time = int(self.timeSelection.refIndex.text()) - 1
        test_time = int(self.timeSelection.testIndex.text()) - 1
        selected_variable = self.input.varBox.currentText().split('(')[0][:-1]

        with Serafin.Read(self.input.ref_data.filename,
                          self.input.ref_data.language) as input_stream:
            input_stream.header = self.input.ref_data.header
            input_stream.time = self.input.ref_data.time
            ref_values = input_stream.read_var_in_frame(
                ref_time, selected_variable)

        with Serafin.Read(self.input.test_data.filename,
                          self.input.test_data.language) as input_stream:
            input_stream.header = self.input.test_data.header
            input_stream.time = self.input.test_data.time
            test_values = input_stream.read_var_in_frame(
                test_time, selected_variable)

        values = test_values - ref_values
        self.ewsd = self.input.ref_mesh.element_wise_signed_deviation(values)

        self.updateStats(ref_time, test_time)
        self.updateHistogram()

    def btnColorMapEvent(self):
        if not self.has_map:
            reply = QMessageBox.question(
                self, 'Show distribution in 2D',
                'This may take some time. Are you sure to proceed?',
                QMessageBox.Yes | QMessageBox.No)
            if reply == QMessageBox.No:
                return

            self.map.canvas.reinitFigure(self.input.ref_mesh, self.ewsd,
                                         self.xlim,
                                         self.input.ref_mesh.polygon)
            self.has_map = True
        self.btnColorMap.setEnabled(False)
        self.map.show()
Пример #11
0
class InputTab(SerafinInputTab):
    def __init__(self, parent):
        super().__init__(parent)
        canvas = LineMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False

        self.data = None
        self.mesh = None

        self.lines = []
        self.line_interpolators = []
        self.line_interpolators_internal = []  # without intersection points

        self._initWidgets()  # some instance attributes will be set there
        self._setLayout()
        self._bindEvents()

    def _initWidgets(self):
        # create the button open lines
        self.btnOpenLines = QPushButton('Load\nLines',
                                        self,
                                        icon=self.style().standardIcon(
                                            QStyle.SP_DialogOpenButton))
        self.btnOpenLines.setToolTip('<b>Open</b> a .i2s or .shp file')
        self.btnOpenLines.setFixedSize(105, 50)
        self.btnOpenLines.setEnabled(False)

        # create some text fields displaying the IO files info
        self.linesNameBox = QPlainTextEdit()
        self.linesNameBox.setReadOnly(True)
        self.linesNameBox.setFixedHeight(50)

        # create the map button
        self.btnMap = QPushButton('Locate lines\non map',
                                  self,
                                  icon=self.style().standardIcon(
                                      QStyle.SP_DialogHelpButton))
        self.btnMap.setFixedSize(135, 50)
        self.btnMap.setEnabled(False)

    def _bindEvents(self):
        self.btnOpen.clicked.connect(self.btnOpenSerafinEvent)
        self.btnOpenLines.clicked.connect(self.btnOpenLinesEvent)
        self.btnMap.clicked.connect(self.btnMapEvent)

    def _setLayout(self):
        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 10))
        mainLayout.setSpacing(15)
        hlayout = QHBoxLayout()
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.setAlignment(Qt.AlignLeft)
        hlayout.addWidget(self.btnOpen)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.langBox)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.btnOpenLines)
        hlayout.addWidget(self.btnMap)
        mainLayout.addLayout(hlayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        glayout = QGridLayout()
        glayout.addWidget(QLabel('     Input file'), 1, 1)
        glayout.addWidget(self.inNameBox, 1, 2)
        glayout.addWidget(QLabel('     Summary'), 2, 1)
        glayout.addWidget(self.summaryTextBox, 2, 2)
        glayout.addWidget(QLabel('     Lines file'), 3, 1)
        glayout.addWidget(self.linesNameBox, 3, 2)
        glayout.setAlignment(Qt.AlignLeft)
        glayout.setSpacing(10)
        mainLayout.addLayout(glayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        mainLayout.addWidget(QLabel('   Message logs'))
        mainLayout.addWidget(self.logTextBox.widget)
        self.setLayout(mainLayout)

    def _reinitInput(self):
        self.reset()
        self.data = None
        self.has_map = False
        self.btnMap.setEnabled(False)
        self.mesh = None
        self.btnOpenLines.setEnabled(False)
        self.parent.reset()

    def _resetDefaultOptions(self):
        nb_nonempty = 0

        self.line_interpolators = []
        self.line_interpolators_internal = []

        for line in self.lines:
            line_interpolators, distances, \
                line_interpolators_internal, distances_internal = self.mesh.get_line_interpolators(line)
            if line_interpolators:
                nb_nonempty += 1
            self.line_interpolators.append((line_interpolators, distances))
            self.line_interpolators_internal.append(
                (line_interpolators_internal, distances_internal))

        if nb_nonempty == 0:
            self.lines = []
            self.line_interpolators = []
            self.line_interpolators_internal = []

            self.linesNameBox.clear()
            self.parent.reset()

        else:
            old_filename = self.linesNameBox.toPlainText().split('\n')[0]
            self.linesNameBox.clear()
            self.linesNameBox.appendPlainText(
                old_filename + '\n' + 'The file contains {} open polyline{}.'
                '{} line{} the mesh continuously.'.format(
                    len(self.lines), 's' if len(self.lines) > 1 else '',
                    nb_nonempty,
                    's intersect' if nb_nonempty > 1 else ' intersects'))

            self.has_map = False
            self.btnMap.setEnabled(True)
            self.parent.getInput()

    def btnOpenSerafinEvent(self):
        canceled, filename = super().open_event()
        if canceled:
            return

        self._reinitInput()
        success, data = self.read_2d(filename)
        if not success:
            return

        # record the mesh for future visualization and calculations
        self.parent.inDialog()
        meshLoader = LoadMeshDialog('interpolation', data.header)
        self.mesh = meshLoader.run()
        self.parent.outDialog()
        if meshLoader.thread.canceled:
            self.linesNameBox.clear()
            self.parent.reset()
            return

        self.data = data
        self.btnOpenLines.setEnabled(True)
        self._resetDefaultOptions()

    def btnOpenLinesEvent(self):
        success, filename, polylines = open_polylines()
        if not success:
            return
        self.lines = polylines
        logging.info('Finished reading the lines file %s' % filename)

        nb_nonempty, indices_nonempty, \
            self.line_interpolators, self.line_interpolators_internal = self.mesh.get_line_interpolators(self.lines)

        if nb_nonempty == 0:
            QMessageBox.critical(self, 'Error',
                                 'No line intersects the mesh continuously.',
                                 QMessageBox.Ok)
            return

        logging.info('Finished reading the lines file %s' % filename)

        self.linesNameBox.clear()
        self.linesNameBox.appendPlainText(
            filename + '\n' + 'The file contains {} open polyline{}.'
            '{} line{} the mesh continuously.'.format(
                len(self.lines), 's' if len(self.lines) > 1 else '',
                nb_nonempty,
                's intersect' if nb_nonempty > 1 else ' intersects'))

        self.has_map = False
        self.btnMap.setEnabled(True)
        self.parent.getInput()

    def btnMapEvent(self):
        if not self.has_map:
            self.map.canvas.reinitFigure(
                self.mesh, self.lines,
                ['Line %d' % (i + 1) for i in range(len(self.lines))],
                list(
                    islice(
                        cycle(['b', 'r', 'g', 'y', 'k', 'c', '#F28AD6', 'm']),
                        len(self.lines))))

            self.has_map = True

            self.map.canvas.draw()
            self.has_map = True
        self.map.show()
Пример #12
0
class InputTab(SerafinInputTab):
    def __init__(self, parent):
        super().__init__(parent)
        self.old_frequency = '1'

        canvas = MapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False

        self.data = None
        self.mesh = None

        self.points = []
        self.point_interpolators = []
        self.fields = []
        self.attributes = []
        self.attribute_table = PointAttributeTable()

        self._initWidgets()  # some instance attributes will be set there
        self._setLayout()
        self._bindEvents()

    def _initWidgets(self):
        # create the button open points
        self.btnOpenPoints = QPushButton('Load\nPoints',
                                         self,
                                         icon=self.style().standardIcon(
                                             QStyle.SP_DialogOpenButton))
        self.btnOpenPoints.setToolTip('<b>Open</b> a .shp file')
        self.btnOpenPoints.setFixedSize(105, 50)
        self.btnOpenPoints.setEnabled(False)

        self.btnOpenAttributes = QPushButton('Attributes\nTable',
                                             self,
                                             icon=self.style().standardIcon(
                                                 QStyle.SP_FileDialogListView))
        self.btnOpenAttributes.setToolTip('<b>Open</b> the attribute table')
        self.btnOpenAttributes.setFixedSize(105, 50)
        self.btnOpenAttributes.setEnabled(False)

        # create some text fields displaying the IO files info
        self.pointsNameBox = QPlainTextEdit()
        self.pointsNameBox.setReadOnly(True)
        self.pointsNameBox.setFixedHeight(50)

        # create two 3-column tables for variables selection
        self.firstTable = VariableTable()
        self.secondTable = VariableTable()

        self.timeSampling = QLineEdit('1')
        self.timeSampling.setFixedWidth(50)

        # create the map button
        self.btnMap = QPushButton('Locate points\non map',
                                  self,
                                  icon=self.style().standardIcon(
                                      QStyle.SP_DialogHelpButton))
        self.btnMap.setFixedSize(135, 50)
        self.btnMap.setEnabled(False)

        # create the submit button
        self.btnSubmit = QPushButton('Submit\nto .csv',
                                     self,
                                     icon=self.style().standardIcon(
                                         QStyle.SP_DialogSaveButton))
        self.btnSubmit.setToolTip('<b>Write</b> output to .csv')
        self.btnSubmit.setFixedSize(105, 50)
        self.btnSubmit.setEnabled(False)

        # create the output file name box
        self.csvNameBox = QLineEdit()
        self.csvNameBox.setReadOnly(True)
        self.csvNameBox.setFixedHeight(30)

    def _bindEvents(self):
        self.btnOpen.clicked.connect(self.btnOpenSerafinEvent)
        self.btnOpenPoints.clicked.connect(self.btnOpenPointsEvent)
        self.btnOpenAttributes.clicked.connect(self.btnOpenAttributesEvent)
        self.btnMap.clicked.connect(self.btnMapEvent)
        self.btnSubmit.clicked.connect(self.btnSubmitEvent)
        self.timeSampling.editingFinished.connect(self._checkSamplingFrequency)

    def _setLayout(self):
        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 10))
        mainLayout.setSpacing(15)
        hlayout = QHBoxLayout()
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.setAlignment(Qt.AlignLeft)
        hlayout.addWidget(self.btnOpen)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.langBox)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.btnOpenPoints)
        hlayout.addWidget(self.btnOpenAttributes)
        hlayout.addWidget(self.btnMap)
        mainLayout.addLayout(hlayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        glayout = QGridLayout()
        glayout.addWidget(QLabel('     Input file'), 1, 1)
        glayout.addWidget(self.inNameBox, 1, 2)
        glayout.addWidget(QLabel('     Summary'), 2, 1)
        glayout.addWidget(self.summaryTextBox, 2, 2)
        glayout.addWidget(QLabel('     Points file'), 3, 1)
        glayout.addWidget(self.pointsNameBox, 3, 2)
        glayout.setAlignment(Qt.AlignLeft)
        glayout.setSpacing(10)
        mainLayout.addLayout(glayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        glayout = QGridLayout()
        hlayout = QHBoxLayout()
        hlayout.addItem(QSpacerItem(30, 1))
        vlayout = QVBoxLayout()
        lb = QLabel('Available variables')
        vlayout.addWidget(lb)
        vlayout.setAlignment(lb, Qt.AlignHCenter)
        vlayout.addWidget(self.firstTable)
        hlayout.addLayout(vlayout)
        hlayout.addItem(QSpacerItem(15, 1))

        vlayout = QVBoxLayout()
        lb = QLabel('Output variables')
        vlayout.addWidget(lb)
        vlayout.setAlignment(lb, Qt.AlignHCenter)
        vlayout.addWidget(self.secondTable)
        hlayout.addLayout(vlayout)
        hlayout.addItem(QSpacerItem(30, 1))

        glayout.addLayout(hlayout, 1, 1)
        hlayout = QHBoxLayout()
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(QLabel('Time sampling frequency'))
        hlayout.addWidget(self.timeSampling)
        hlayout.setAlignment(self.timeSampling, Qt.AlignLeft)
        hlayout.addStretch()
        glayout.addLayout(hlayout, 2, 1)

        glayout.setAlignment(Qt.AlignLeft)
        glayout.setSpacing(10)
        mainLayout.addLayout(glayout)
        mainLayout.addItem(QSpacerItem(30, 10))

        hlayout = QHBoxLayout()
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.btnSubmit)
        hlayout.addWidget(self.csvNameBox)
        mainLayout.addLayout(hlayout)
        mainLayout.addItem(QSpacerItem(30, 15))

        mainLayout.addWidget(QLabel('   Message logs'))
        mainLayout.addWidget(self.logTextBox.widget)
        self.setLayout(mainLayout)

    def _reinitInput(self):
        self.reset()
        self.data = None
        self.has_map = False
        self.firstTable.setRowCount(0)
        self.secondTable.setRowCount(0)
        self.btnMap.setEnabled(False)
        self.btnOpenAttributes.setEnabled(False)
        self.mesh = None
        self.btnOpenPoints.setEnabled(False)
        self.old_frequency = self.timeSampling.text()

        self.timeSampling.setText('1')
        self.btnSubmit.setEnabled(False)
        self.csvNameBox.clear()
        self.parent.tab.setTabEnabled(1, False)

    def _resetDefaultOptions(self):
        if int(self.old_frequency) <= len(self.data.time):
            self.timeSampling.setText(self.old_frequency)

        is_inside, self.point_interpolators = self.mesh.get_point_interpolators(
            self.points)
        nb_inside = sum(map(int, is_inside))
        if nb_inside == 0:
            self.pointsNameBox.clear()
            self.points = []
            self.point_interpolators = []
        else:
            self.attribute_table.getData(self.points, is_inside, self.fields,
                                         self.attributes)
            old_filename = self.pointsNameBox.toPlainText().split('\n')[0]
            self.pointsNameBox.clear()
            self.pointsNameBox.appendPlainText(
                old_filename + '\n' + 'The file contains {} point{}.'
                '{} point{} inside the mesh.'.format(
                    len(self.points), 's' if len(self.points) > 1 else '',
                    nb_inside, 's are' if nb_inside > 1 else ' is'))
            self.btnSubmit.setEnabled(True)
            self.btnOpenAttributes.setEnabled(True)
            self.btnMap.setEnabled(True)

    def _initVarTables(self):
        self.firstTable.fill(self.data.header)

    def _checkSamplingFrequency(self):
        try:
            sampling_frequency = int(self.timeSampling.text())
        except ValueError:
            QMessageBox.critical(self, 'Error',
                                 'The sampling frequency must be a number!',
                                 QMessageBox.Ok)
            self.timeSampling.setText('1')
            return
        if sampling_frequency < 1 or sampling_frequency > len(self.data.time):
            QMessageBox.critical(
                self, 'Error',
                'The sampling frequency must be in the range [1; nbFrames]!',
                QMessageBox.Ok)
            self.timeSampling.setText('1')
            return

    def getSelectedVariables(self):
        return self.secondTable.get_selected()

    def btnOpenSerafinEvent(self):
        canceled, filename = super().open_event()
        if canceled:
            return

        self._reinitInput()
        success, data = self.read_2d(filename)
        if not success:
            return

        # record the mesh for future visualization and calculations
        self.parent.inDialog()
        meshLoader = LoadMeshDialog('interpolation', data.header)
        self.mesh = meshLoader.run()
        self.parent.outDialog()
        if meshLoader.thread.canceled:
            self.pointsNameBox.clear()
            self.summaryTextBox.clear()
            return

        self.data = data
        self.btnOpenPoints.setEnabled(True)
        self._resetDefaultOptions()
        self.parent.imageTab.reset()

        # displaying the available variables
        self._initVarTables()

    def btnOpenPointsEvent(self):
        success, filename, points, attributes, fields = open_points()
        if not success:
            return

        logging.info('Finished reading the points file %s' % filename)
        is_inside, point_interpolators = self.mesh.get_point_interpolators(
            points)
        nb_inside = sum(map(int, is_inside))
        if nb_inside == 0:
            QMessageBox.critical(self, 'Error', 'No point inside the mesh.',
                                 QMessageBox.Ok)
            return

        self.points = points
        self.attributes = attributes
        self.fields = fields
        self.attribute_table.getData(self.points, is_inside, self.fields,
                                     self.attributes)
        self.point_interpolators = point_interpolators
        self.pointsNameBox.clear()
        self.pointsNameBox.appendPlainText(
            filename + '\n' + 'The file contains {} point{}.'
            '{} point{} inside the mesh.'.format(
                len(self.points), 's' if len(self.points) > 1 else '',
                nb_inside, 's are' if nb_inside > 1 else ' is'))

        self.has_map = False
        self.btnMap.setEnabled(True)
        self.btnOpenAttributes.setEnabled(True)
        self.btnSubmit.setEnabled(True)
        self.csvNameBox.clear()
        self.parent.imageTab.reset()
        self.parent.tab.setTabEnabled(1, False)

    def btnOpenAttributesEvent(self):
        self.attribute_table.show()

    def btnMapEvent(self):
        if not self.has_map:
            self.map.canvas.initFigure(self.mesh)
            self.map.canvas.axes.scatter(*zip(*self.points))
            labels = ['%d' % (i + 1) for i in range(len(self.points))]
            for label, (x, y) in zip(labels, self.points):
                self.map.canvas.axes.annotate(
                    label,
                    xy=(x, y),
                    xytext=(-20, 20),
                    fontsize=8,
                    textcoords='offset points',
                    ha='right',
                    va='bottom',
                    bbox=dict(boxstyle='round,pad=0.5', fc='yellow',
                              alpha=0.5),
                    arrowprops=dict(arrowstyle='->',
                                    connectionstyle='arc3,rad=0'))

            self.map.canvas.draw()
            self.has_map = True
        self.map.show()

    def btnSubmitEvent(self):
        selected_var_IDs = self.getSelectedVariables()

        if not selected_var_IDs:
            QMessageBox.critical(
                self, 'Error',
                'Choose at least one output variable before submit!',
                QMessageBox.Ok)
            return

        canceled, filename = save_dialog('CSV')
        if canceled:
            return

        self.csvNameBox.setText(filename)
        logging.info('Writing the output to %s' % filename)
        self.parent.inDialog()

        sampling_frequency = int(self.timeSampling.text())
        selected_time = self.data.time[::sampling_frequency]
        indices_inside = [
            i for i in range(len(self.points))
            if self.point_interpolators[i] is not None
        ]

        # initialize the progress bar
        process = WriteCSVProcess(self.parent.csv_separator,
                                  self.parent.digits, self.mesh)
        progressBar = OutputProgressDialog()

        with Serafin.Read(self.data.filename,
                          self.data.language) as input_stream:
            input_stream.header = self.data.header
            input_stream.time = self.data.time

            progressBar.setValue(1)
            QApplication.processEvents()

            with open(filename, 'w') as output_stream:
                progressBar.connectToThread(process)
                process.write_csv(
                    input_stream, selected_time, selected_var_IDs,
                    output_stream, indices_inside,
                    [self.points[i] for i in indices_inside],
                    [self.point_interpolators[i] for i in indices_inside])
        if not process.canceled:
            progressBar.outputFinished()
        progressBar.exec_()
        self.parent.outDialog()

        if process.canceled:
            self.csvNameBox.clear()
            return

        self.parent.imageTab.getData(selected_var_IDs, indices_inside)
        self.parent.tab.setTabEnabled(1, True)
Пример #13
0
class ImageTab(PointPlotViewer):
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab

        self.has_map = False
        canvas = MapCanvas()
        self.map = MapViewer(canvas)

        self.var_IDs = []
        self.current_var = ''
        self.openAttributes = QAction('Attributes\nTable',
                                      self,
                                      icon=self.style().standardIcon(
                                          QStyle.SP_FileDialogListView),
                                      triggered=self.openAttributesEvent)
        self.openAttributes_short = QAction('Attributes Table',
                                            self,
                                            icon=self.style().standardIcon(
                                                QStyle.SP_FileDialogListView),
                                            triggered=self.openAttributesEvent)
        self.locatePoints = QAction('Locate points\non map',
                                    self,
                                    icon=self.style().standardIcon(
                                        QStyle.SP_DialogHelpButton),
                                    triggered=self.map_event)
        self.locatePoints_short = QAction('Locate points on map',
                                          self,
                                          icon=self.style().standardIcon(
                                              QStyle.SP_DialogHelpButton),
                                          triggered=self.map_event)
        self.input.map.closeEvent = self.enable_locate
        self.input.attribute_table.closeEvent = self.enable_attribute

        self.toolBar.addAction(self.locatePoints)
        self.toolBar.addAction(self.openAttributes)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.select_variable)
        self.toolBar.addAction(self.selectColumnsAct)
        self.toolBar.addAction(self.editColumnNamesAct)
        self.toolBar.addAction(self.editColumColorAct)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.convertTimeAct)
        self.toolBar.addAction(self.changeDateAct)

        self.mapMenu = QMenu('&Map', self)
        self.mapMenu.addAction(self.locatePoints)
        self.pointsMenu = QMenu('&Data', self)
        self.pointsMenu.addAction(self.openAttributes_short)
        self.pointsMenu.addSeparator()
        self.pointsMenu.addAction(self.select_variable_short)
        self.pointsMenu.addAction(self.selectColumnsAct_short)
        self.pointsMenu.addAction(self.editColumnNamesAct_short)
        self.pointsMenu.addAction(self.editColumColorAct_short)

        self.menuBar.addMenu(self.mapMenu)
        self.menuBar.addMenu(self.pointsMenu)

    def enable_attribute(self, event):
        self.openAttributes.setEnabled(True)
        self.openAttributes_short.setEnabled(True)

    def enable_locate(self, event):
        self.locatePoints.setEnabled(True)
        self.locatePoints_short.setEnabled(True)

    def map_event(self):
        self.locatePoints.setEnabled(False)
        self.locatePoints_short.setEnabled(False)
        self.input.btnMapEvent()

    def _to_column(self, point):
        point_index = int(point.split()[1]) - 1
        x, y = self.input.points[point_index]
        return 'Point %d %s (%.4f|%.4f)' % (point_index + 1, self.current_var,
                                            x, y)

    def editColumns(self):
        msg = PointLabelEditor(
            self.column_labels, self.column_name, self.input.points, [
                self.input.point_interpolators[i] is not None
                for i in range(len(self.input.points))
            ], self.input.fields, self.input.attributes)
        value = msg.exec_()
        if value == QDialog.Rejected:
            return
        msg.getLabels(self.column_labels)
        self.replot()

    def getData(self, var_IDs, point_indices):
        self.var_IDs = var_IDs
        self.current_var = var_IDs[0]

        # get the new data
        csv_file = self.input.csvNameBox.text()
        self.data, headers = read_csv(csv_file,
                                      self.input.parent.csv_separator)

        if self.input.data.header.date is not None:
            year, month, day, hour, minute, second = self.input.data.header.date
            self.start_time = datetime.datetime(year, month, day, hour, minute,
                                                second)
        else:
            self.start_time = datetime.datetime(1900, 1, 1, 0, 0, 0)
        self.datetime = list(
            map(lambda x: self.start_time + datetime.timedelta(seconds=x),
                self.data['time']))

        self.str_datetime = list(
            map(lambda x: x.strftime('%Y/%m/%d\n%H:%M'), self.datetime))
        self.str_datetime_bis = list(
            map(lambda x: x.strftime('%d/%m/%y\n%H:%M'), self.datetime))

        self.columns = ['Point %d' % (i + 1) for i in point_indices]
        self.current_columns = self.columns[0:1]
        self.column_labels = {x: x for x in self.columns}
        self.column_colors = {
            column: color
            for column, color in zip(self.columns, cycle(self.defaultColors))
        }

        # initialize the plot
        self.time = [
            self.data['time'], self.data['time'], self.data['time'],
            self.data['time'] / 60, self.data['time'] / 3600,
            self.data['time'] / 86400
        ]
        self.language = self.input.data.language
        self.current_xlabel = self._defaultXLabel()
        self.current_ylabel = self._defaultYLabel()
        self.current_title = ''
        self.replot()

    def openAttributesEvent(self):
        self.openAttributes.setEnabled(False)
        self.openAttributes_short.setEnabled(False)
        self.input.attribute_table.show()

    def replot(self):
        self.canvas.axes.clear()
        for point in self.current_columns:
            self.canvas.axes.plot(self.time[self.timeFormat],
                                  self.data[self._to_column(point)],
                                  '-',
                                  color=self.column_colors[point],
                                  linewidth=2,
                                  label=self.column_labels[point])
        self.canvas.axes.legend()
        self.canvas.axes.grid(linestyle='dotted')
        self.canvas.axes.set_xlabel(self.current_xlabel)
        self.canvas.axes.set_ylabel(self.current_ylabel)
        self.canvas.axes.set_title(self.current_title)
        if self.timeFormat in [1, 2]:
            self.canvas.axes.set_xticklabels(
                self.str_datetime if self.timeFormat ==
                1 else self.str_datetime_bis)
            for label in self.canvas.axes.get_xticklabels():
                label.set_rotation(45)
                label.set_fontsize(8)
        self.canvas.draw()

    def reset(self):
        self.has_map = False
        self.map.close()
        self.input.attribute_table.close()

        # reinitialize old graphical parameters
        super().reset()
        self.current_columns = ('Point 1', )