Skip to content
Snippets Groups Projects
sensecarbon_tsv.py 64.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • unknown's avatar
    unknown committed
    
            ul_px = coordinate2px(self.gt, min([cx0, cx1]), max([cy0, cy1]))
            lr_px = coordinate2px(self.gt, max([cx0, cx1]), min([cy0, cy1]))
            lr_px = [c+1 for c in lr_px] #+1
    
            return self.readImageChip([ul_px[0], lr_px[0]], [ul_px[1], lr_px[1]], bands=bands)
    
        def readImageChip(self, px_x, px_y, bands=[4,5,3]):
    
    
            ds = gdal.Open(self.pathImg, gdal.GA_ReadOnly)
    
    unknown's avatar
    unknown committed
    
            assert len(px_x) == 2 and px_x[0] <= px_x[1]
            assert len(px_y) == 2 and px_y[0] <= px_y[1]
    
            ns = px_x[1]-px_x[0]+1
            nl = px_y[1]-px_y[0]+1
    
    unknown's avatar
    unknown committed
    
            src_ns = ds.RasterXSize
            src_nl = ds.RasterYSize
    
    
            chipdata = dict()
    
    
    
            #pixel indices in source image
            x0 = max([0, px_x[0]])
            y0 = max([0, px_y[0]])
            x1 = min([src_ns, px_x[1]])
            y1 = min([src_nl, px_y[1]])
            win_xsize = x1-x0+1
            win_ysize = y1-y0+1
    
            #pixel indices in image chip (ideally 0 and ns-1 or nl-1)
            i0 = x0 - px_x[0]
            i1 = i0 + win_xsize
    
            j0 = y0 - px_y[0]
            j1 = j0+ win_ysize
    
    
    
    
    
            templateImg = np.zeros((nl,ns))
            if self.nodata:
                templateImg *= self.nodata
    
    
    unknown's avatar
    unknown committed
            templateImg = templateImg.astype(self.getdtype())
            templateMsk = np.ones((nl,ns), dtype='bool')
    
            if win_xsize < 1 or win_ysize < 1:
    
                six.print_('Selected image chip is out of raster image {}'.format(self.pathImg), file=sys.stderr)
    
    unknown's avatar
    unknown committed
                for i, b in enumerate(bands):
                    chipdata[b] = np.copy(templateImg)
    
            else:
                for i, b in enumerate(bands):
                    band = ds.GetRasterBand(b)
                    data = np.copy(templateImg)
                    data[j0:j1,i0:i1] = band.ReadAsArray(xoff=x0, yoff=y0, win_xsize=win_xsize,win_ysize=win_ysize)
                    chipdata[b] = data
                    nodatavalue = band.GetNoDataValue()
                    if nodatavalue is not None:
                        templateMsk[j0:j1,i0:i1] = np.logical_and(templateMsk[j0:j1,i0:i1], data[j0:j1,i0:i1] != nodatavalue)
    
                if self.pathMsk:
                    ds = gdal.Open(self.pathMsk)
                    tmp = ds.GetRasterBand(1).ReadAsArray(xoff=x0, yoff=y0, \
                                win_xsize=win_xsize,win_ysize=win_ysize) == 0
    
                    templateMsk[j0:j1,i0:i1] = np.logical_and(templateMsk[j0:j1,i0:i1], tmp)
    
            chipdata['mask'] = templateMsk
            return chipdata
    
        def __repr__(self):
    
            return 'TS Datum {} {}'.format(self.date, str(self.sensor))
    
        def __cmp__(self, other):
            return cmp(str((self.date, self.sensor)), str((other.date, other.sensor)))
    
        def __eq__(self, other):
            return self.date == other.date and self.sensor == other.sensor
    
        def __hash__(self):
            return hash((self.date,self.sensor.sensor_name))
    
    
    unknown's avatar
    unknown committed
    
    regYYYYDOY = re.compile(r'(19|20)\d{5}')
    regYYYYMMDD = re.compile(r'(19|20)\d{2}-\d{2}-\d{2}')
    
    unknown's avatar
    unknown committed
    regYYYY = re.compile(r'(19|20)\d{2}')
    
    unknown's avatar
    unknown committed
    def parseAcquisitionDate(text):
    
        match = regLandsatSceneID.search(text)
        if match:
            id = match.group()
            return getDateTime64FromYYYYDOY(id[9:16])
    
    unknown's avatar
    unknown committed
        match = regYYYYMMDD.search(text)
        if match:
            return np.datetime64(match.group())
    
    unknown's avatar
    unknown committed
        match = regYYYYDOY.search(text)
    
    unknown's avatar
    unknown committed
        if match:
            return getDateTime64FromYYYYDOY(match.group())
    
    unknown's avatar
    unknown committed
        match = regYYYY.search(text)
        if match:
            return np.datetime64(match.group())
    
    unknown's avatar
    unknown committed
        return None
    
    
    
    unknown's avatar
    unknown committed
    def getDateTime64FromYYYYDOY(yyyydoy):
        return getDateTime64FromDOY(yyyydoy[0:4], yyyydoy[4:7])
    
    def getDateTime64FromDOY(year, doy):
            if type(year) is str:
                year = int(year)
            if type(doy) is str:
                doy = int(doy)
            return np.datetime64('{:04d}-01-01'.format(year)) + np.timedelta64(doy-1, 'D')
    
    
    class PictureTest(QMainWindow):
    
    
        def __init__(self, parent=None, qImage=None):
    
    unknown's avatar
    unknown committed
            super(PictureTest,self).__init__(parent)
            self.setWindowTitle("Show Image with pyqt")
            self.imageLabel=QLabel()
            self.imageLabel.setSizePolicy(QSizePolicy.Ignored,QSizePolicy.Ignored)
            self.setCentralWidget(self.imageLabel)
    
            self.cv_img = None
    
    
            if qImage:
                self.addImage(qImage)
    
    unknown's avatar
    unknown committed
    
    
        def addImage(self, qImage):
            pxmap = QPixmap.fromImage(qImage)
            self.addPixmap(pxmap)
    
        def addPixmap(self, pixmap):
            pxmap = pixmap.scaled(self.imageLabel.size(), Qt.KeepAspectRatio)
            self.imageLabel.setPixmap(pxmap)
            self.imageLabel.adjustSize()
            self.imageLabel.update()
    
        def addNumpy(self, data):
    
    unknown's avatar
    unknown committed
    
    
            img = Array2Image(data)
    
    unknown's avatar
    unknown committed
    
            #self.resize(img.width(), img.height())
    
    def getChip3d(chips, rgb_idx, ranges):
        assert len(rgb_idx) == 3 and len(rgb_idx) == len(ranges)
        for i in rgb_idx:
            assert i in chips.keys()
    
        nl, ns = chips[rgb_idx[0]].shape
        a3d = np.ndarray((3,nl,ns), dtype='float')
    
        for i, rgb_i in enumerate(rgb_idx):
            range = ranges[i]
            data = chips[rgb_i].astype('float')
            data -= range[0]
            data *= 255./range[1]
            a3d[i,:] = data
    
        np.clip(a3d, 0, 255, out=a3d)
    
        return a3d.astype('uint8')
    
    def Array2Image(d3d):
        nb, nl, ns = d3d.shape
        byteperline = nb
        d3d = d3d.transpose([1,2,0]).copy()
    
        return QImage(d3d.data, ns, nl, QImage.Format_RGB888)
    
    
    class VerticalLabel(QLabel):
        def __init__(self, text):
            super(self.__class__, self).__init__()
            self.text = text
    
        def paintEvent(self, event):
            painter = QPainter(self)
            painter.setPen(Qt.black)
            painter.translate(20, 100)
            painter.rotate(-90)
            if self.text:
                painter.drawText(0, 0, self.text)
            painter.end()
    
    unknown's avatar
    unknown committed
    
    
        def minimumSizeHint(self):
            size = QLabel.minimumSizeHint(self)
            return QSize(size.height(), size.width())
    
        def sizeHint(self):
            size = QLabel.sizeHint(self)
            return QSize(size.height(), size.width())
    
    unknown's avatar
    unknown committed
    
    
    unknown's avatar
    unknown committed
    class ImageChipBuffer(object):
    
    
        def __init__(self):
    
            self.data = dict()
            self.BBox = None
            self.SRS = None
    
    unknown's avatar
    unknown committed
            pass
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def hasDataCube(self, TSD):
            return TSD in self.data.keys()
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def getMissingBands(self, TSD, bands):
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            missing = set(bands)
            if TSD in self.data.keys():
    
                missing = missing - set(self.data[TSD].keys())
    
    unknown's avatar
    unknown committed
            return missing
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def addDataCube(self, TSD, chipData):
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            assert self.BBox is not None, 'Please initialize the bounding box first.'
    
    unknown's avatar
    unknown committed
            assert isinstance(chipData, dict)
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if TSD not in self.data.keys():
                self.data[TSD] = dict()
            self.data[TSD].update(chipData)
    
        def getDataCube(self, TSD):
            return self.data.get(TSD)
    
    unknown's avatar
    unknown committed
    
    
        def getChipArray(self, TSD, band_view, mode='rgb'):
            assert mode in ['rgb', 'bgr']
            bands = band_view.getBands(TSD.sensor)
            band_ranges = band_view.getRanges(TSD.sensor)
            nb = len(bands)
            assert nb == 3 and nb == len(band_ranges)
            assert TSD in self.data.keys(), 'Time Series Datum {} is not in buffer'.format(TSD.getDate())
            chipData = self.data[TSD]
            for b in bands:
                assert b in chipData.keys()
    
    
    
            nl, ns = chipData[bands[0]].shape
    
            dtype= 'uint8'
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            array_data = np.ndarray((nl,ns, nb), dtype=dtype)
    
    
            if mode == 'rgb':
                ch_dst = [0,1,2]
            elif mode == 'bgr':
                # r -> dst channel 2
                # g -> dst channel 1
                # b -> dst channel 0
                ch_dst = [2,1,0]
            for i, i_dst in enumerate(ch_dst):
    
                offset = band_ranges[i][0]
                scale = 255./band_ranges[i][1]
    
                res = pg.rescaleData(chipData[bands[i]], scale, offset, dtype='float')
                np.clip(res, 0, 255, out=res)
                array_data[:,:,i_dst] = res
    
            return array_data
    
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def getChipRGB(self, TSD, band_view):
    
            bands = band_view.getBands(TSD.sensor)
            band_ranges = band_view.getRanges(TSD.sensor)
    
    unknown's avatar
    unknown committed
            assert len(bands) == 3 and len(bands) == len(band_ranges)
    
            assert TSD in self.data.keys(), 'Time Series Datum {} is not in buffer'.format(TSD.getDate())
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            chipData = self.data[TSD]
    
    unknown's avatar
    unknown committed
            for b in bands:
                assert b in chipData.keys()
    
            nl, ns = chipData[bands[0]].shape
            rgb_data = np.ndarray((3,nl,ns), dtype='float')
    
            for i, b in enumerate(bands):
                range = band_ranges[i]
                data = chipData[b].astype('float')
                data -= range[0]
                data *= 255./range[1]
                rgb_data[i,:] = data
    
            np.clip(rgb_data, 0, 255, out=rgb_data)
            rgb_data = rgb_data.astype('uint8')
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if band_view.useMaskValues():
                rgb = band_view.getMaskColor()
    
    unknown's avatar
    unknown committed
                is_masked = np.where(np.logical_not(chipData['mask']))
                for i, c in enumerate(rgb):
                    rgb_data[i, is_masked[0], is_masked[1]] = c
    
    
    unknown's avatar
    unknown committed
    
    
        def getChipImage(self, date, view):
            rgb = self.getChipRGB(date, view)
            nb, nl, ns = rgb.shape
            rgb = rgb.transpose([1,2,0]).copy('C')
            return QImage(rgb.data, ns, nl, QImage.Format_RGB888)
    
    unknown's avatar
    unknown committed
    
        def clear(self):
            self.data.clear()
    
        def setBoundingBox(self, BBox):
            assert type(BBox) is ogr.Geometry
            SRS = BBox.GetSpatialReference()
            assert SRS is not None
            if self.BBox is None or not self.BBox.Equals(BBox) or not self.SRS.IsSame(SRS):
                self.data.clear()
                self.BBox = BBox
                self.SRS = SRS
    
        def __repr__(self):
            info = ['Chipbuffer']
            info.append('Bounding Box: {}'.format(self.bbBoxWkt))
            info.append('Chips: {}'.format(len(self.data)))
            return '\n'.join(info)
    
    
    
    list2str = lambda ll : '\n'.join([str(l) for l in ll])
    
    
    class TimeSeriesViewer:
    
    unknown's avatar
    unknown committed
        """QGIS Plugin Implementation."""
    
        def __init__(self, iface):
            """Constructor.
    
            :param iface: An interface instance that will be passed to this class
                which provides the hook by which you can manipulate the QGIS
                application at run time.
            :type iface: QgsInterface
            """
            # Save reference to the QGIS interface
            self.iface = iface
    
            if isinstance(self.iface, qgis.gui.QgisInterface):
                import console
                console.show_console()
    
    unknown's avatar
    unknown committed
            # initialize plugin directory
            self.plugin_dir = os.path.dirname(__file__)
            # initialize locale
            locale = 'placeholder'
            #locale = QSettings().value('locale/userLocale')[0:2]
            locale_path = os.path.join(
                self.plugin_dir,
                'i18n',
                'EnMAPBox_{}.qm'.format(locale))
    
            if os.path.exists(locale_path):
                self.translator = QTranslator()
                self.translator.load(locale_path)
    
                if qVersion() > '4.3.3':
                    QCoreApplication.installTranslator(self.translator)
    
            # Create the dialog (after translation) and keep reference
            self.dlg = SenseCarbon_TSVGui()
            D = self.dlg
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            #init on empty time series
            self.TS = None
            self.init_TimeSeries()
    
            self.BAND_VIEWS = list()
    
    unknown's avatar
    unknown committed
            self.ImageChipBuffer = ImageChipBuffer()
            self.CHIPWIDGETS = collections.OrderedDict()
    
            self.ValidatorPxX = QIntValidator(0,99999)
            self.ValidatorPxY = QIntValidator(0,99999)
            D.btn_showPxCoordinate.clicked.connect(lambda: self.ua_showPxCoordinate_start())
            D.btn_selectByCoordinate.clicked.connect(self.ua_selectByCoordinate)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            D.btn_selectByRectangle.clicked.connect(self.ua_selectByRectangle)
    
            D.btn_addBandView.clicked.connect(lambda :self.ua_addBandView())
    
    unknown's avatar
    unknown committed
            D.btn_addTSImages.clicked.connect(lambda :self.ua_addTSImages())
            D.btn_addTSMasks.clicked.connect(lambda :self.ua_addTSMasks())
    
            D.btn_loadTSFile.clicked.connect(self.ua_loadTSFile)
            D.btn_saveTSFile.clicked.connect(self.ua_saveTSFile)
            D.btn_addTSExample.clicked.connect(self.ua_loadExampleTS)
    
            D.btn_labeling_clear.clicked.connect(D.tb_labeling_text.clear)
    
            D.actionAdd_Images.triggered.connect(lambda :self.ua_addTSImages())
            D.actionAdd_Masks.triggered.connect(lambda :self.ua_addTSMasks())
            D.actionLoad_Time_Series.triggered.connect(self.ua_loadTSFile)
            D.actionSave_Time_Series.triggered.connect(self.ua_saveTSFile)
            D.actionLoad_Example_Time_Series.triggered.connect(self.ua_loadExampleTS)
            D.actionAbout.triggered.connect( \
                lambda: QMessageBox.about(self.dlg, 'SenseCarbon TimeSeriesViewer', 'A viewer to visualize raster time series data'))
    
            D.btn_removeTSD.clicked.connect(lambda : self.ua_removeTSD(None))
            D.btn_removeTS.clicked.connect(self.ua_clear_TS)
    
    
    
    unknown's avatar
    unknown committed
            D.spinBox_ncpu.setRange(0, multiprocessing.cpu_count())
    
    
    unknown's avatar
    unknown committed
            # Declare instance attributes
            self.actions = []
            #self.menu = self.tr(u'&EnMAP-Box')
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.RectangleMapTool = None
            self.PointMapTool = None
    
            self.canvas_srs = osr.SpatialReference()
    
    
    unknown's avatar
    unknown committed
            if self.iface:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                self.canvas = self.iface.mapCanvas()
    
    unknown's avatar
    unknown committed
                self.menu = self.tr(u'&SenseCarbon TSV')
    
                #self.toolbar = self.iface.addToolBar(u'SenseCarbon TSV')
                #self.toolbar.setObjectName(u'SenseCarbon TSV')
    
    unknown's avatar
    unknown committed
    
    
    unknown's avatar
    unknown committed
                self.RectangleMapTool = qgis_add_ins.RectangleMapTool(self.canvas)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                self.RectangleMapTool.rectangleDrawed.connect(self.ua_selectBy_Response)
    
    unknown's avatar
    unknown committed
                self.PointMapTool = qgis_add_ins.PointMapTool(self.canvas)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                self.PointMapTool.coordinateSelected.connect(self.ua_selectBy_Response)
    
                #self.RectangleMapTool.connect(self.ua_selectByRectangle_Done)
    
            self.ICP = self.dlg.scrollArea_imageChip_content.layout()
            self.dlg.scrollArea_bandViews_content.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
            self.BVP = self.dlg.scrollArea_bandViews_content.layout()
    
    unknown's avatar
    unknown committed
            self.check_enabled()
            s = ""
    
    
        def init_TimeSeries(self, TS=None):
    
            if TS is None:
                TS = TimeSeries()
            assert type(TS) is TimeSeries
    
            if self.TS is not None:
                disconnect_signal(self.TS.datumAdded)
                disconnect_signal(self.TS.progress)
                disconnect_signal(self.TS.chipLoaded)
    
            self.TS = TS
            self.TS.datumAdded.connect(self.ua_datumAdded)
            self.TS.progress.connect(self.ua_TSprogress)
            self.TS.chipLoaded.connect(self.ua_showPxCoordinate_addChips)
    
            TSM = TimeSeriesTableModel(self.TS)
            D = self.dlg
            D.tableView_TimeSeries.setModel(TSM)
            D.tableView_TimeSeries.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
    
            D.cb_doi.setModel(TSM)
            D.cb_doi.setModelColumn(0)
            D.cb_doi.currentIndexChanged.connect(self.scrollToDate)
    
    
    
        def ua_loadTSFile(self, path=None):
            if path is None or path is False:
    
                path = QFileDialog.getOpenFileName(self.dlg, 'Open Time Series file', '')
    
    
                M = self.dlg.tableView_TimeSeries.model()
                M.beginResetModel()
                self.ua_clear_TS()
                self.TS.loadFromFile(path)
                M.endResetModel()
    
                self.refreshBandViews()
    
            self.check_enabled()
    
        def ua_saveTSFile(self):
            path = QFileDialog.getSaveFileName(self.dlg, caption='Save Time Series file')
            if path is not None:
                self.TS.saveToFile(path)
    
    
        def ua_loadExampleTS(self):
            import sensecarbon_tsv
            path_example = file_search(os.path.dirname(sensecarbon_tsv.__file__), 'testdata.txt', recursive=True)
            if path_example is None or len(path_example) == 0:
    
                QMessageBox.information(self.dlg, 'File not found', 'testdata.txt - this file describes an exemplary time series.')
    
            else:
                self.ua_loadTSFile(path=path_example[0])
    
    
    
    unknown's avatar
    unknown committed
        def ua_selectByRectangle(self):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if self.RectangleMapTool is not None:
                self.canvas.setMapTool(self.RectangleMapTool)
    
    unknown's avatar
    unknown committed
    
        def ua_selectByCoordinate(self):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if self.PointMapTool is not None:
                self.canvas.setMapTool(self.PointMapTool)
    
    
        def setCanvasSRS(self,srs):
            if type(srs) is osr.SpatialReference:
                self.canvas_srs = srs
            else:
                self.canvas_srs.ImportFromWkt(srs)
    
    
            self.dlg.tb_bb_srs.setPlainText(self.canvas_srs.ExportToProj4())
    
    
        def ua_selectBy_Response(self, geometry, srs_wkt):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            D = self.dlg
            x = D.spinBox_coordinate_x.value()
            y = D.spinBox_coordinate_x.value()
            dx = D.doubleSpinBox_subset_size_x.value()
            dy = D.doubleSpinBox_subset_size_y.value()
    
    
            self.setCanvasSRS(osr.GetUserInputAsWKT(str(srs_wkt)))
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
            if type(geometry) is QgsRectangle:
                center = geometry.center()
                x = center.x()
                y = center.y()
    
                dx = geometry.xMaximum() - geometry.xMinimum()
                dy = geometry.yMaximum() - geometry.yMinimum()
    
            if type(geometry) is QgsPoint:
                x = geometry.x()
                y = geometry.y()
    
    
            """
            ref_srs = self.TS.getSRS()
            if ref_srs is not None and not ref_srs.IsSame(canvas_srs):
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                print('Convert canvas coordinates to time series SRS')
                g = ogr.Geometry(ogr.wkbPoint)
                g.AddPoint(x,y)
                g.AssignSpatialReference(canvas_srs)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                x = g.GetX()
                y = g.GetY()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            D.doubleSpinBox_subset_size_x.setValue(dx)
            D.doubleSpinBox_subset_size_y.setValue(dy)
            D.spinBox_coordinate_x.setValue(x)
            D.spinBox_coordinate_y.setValue(y)
    
    
            if D.cb_loadSubsetDirectly.isChecked():
                self.ua_showPxCoordinate_start()
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def qgs_handleMouseDown(self, pt, btn):
    
    unknown's avatar
    unknown committed
    
    
        def ua_TSprogress(self, v_min, v, v_max):
            assert v_min <= v and v <= v_max
    
            if v_min < v_max:
                P = self.dlg.progressBar
                if P.minimum() != v_min or P.maximum() != v_max:
                    P.setRange(v_min, v_max)
                else:
                    s = ""
    
                P.setValue(v)
    
    unknown's avatar
    unknown committed
    
        def ua_datumAdded(self):
    
    unknown's avatar
    unknown committed
            if len(self.TS) > 0:
    
                self.setCanvasSRS(self.TS.getSRS())
    
    unknown's avatar
    unknown committed
                if self.dlg.spinBox_coordinate_x.value() == 0.0 and \
                   self.dlg.spinBox_coordinate_y.value() == 0.0:
    
                    xmin, ymin, xmax, ymax = self.TS.getMaxExtent(srs=self.canvas_srs)
    
    unknown's avatar
    unknown committed
                    self.dlg.spinBox_coordinate_x.setRange(xmin, xmax)
                    self.dlg.spinBox_coordinate_y.setRange(ymin, ymax)
    
                    #x, y = self.TS.getSceneCenter()
    
    unknown's avatar
    unknown committed
                    self.dlg.spinBox_coordinate_x.setValue(0.5*(xmin+xmax))
                    self.dlg.spinBox_coordinate_y.setValue(0.5*(ymin+ymax))
    
            self.dlg.cb_doi.setCurrentIndex(int(len(self.TS) / 2))
    
    unknown's avatar
    unknown committed
            self.dlg.tableView_TimeSeries.resizeColumnsToContents()
    
        def check_enabled(self):
            D = self.dlg
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            hasTS = len(self.TS) > 0 or DEBUG
    
            hasTSV = len(self.BAND_VIEWS) > 0
    
    unknown's avatar
    unknown committed
            hasQGIS = qgis_available
    
    
            #D.tabWidget_viewsettings.setEnabled(hasTS)
    
    unknown's avatar
    unknown committed
            D.btn_showPxCoordinate.setEnabled(hasTS and hasTSV)
            D.btn_selectByCoordinate.setEnabled(hasQGIS)
            D.btn_selectByRectangle.setEnabled(hasQGIS)
    
    
    
    unknown's avatar
    unknown committed
    
    
        # noinspection PyMethodMayBeStatic
        def tr(self, message):
            """Get the translation for a string using Qt translation API.
    
            We implement this ourselves since we do not inherit QObject.
    
            :param message: String for translation.
            :type message: str, QString
    
            :returns: Translated version of message.
            :rtype: QString
            """
            # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
            return QCoreApplication.translate('EnMAPBox', message)
    
    
    
        def initGui(self):
            """Create the menu entries and toolbar icons inside the QGIS GUI."""
    
    
    unknown's avatar
    unknown committed
            self.icon_path = ':/plugins/SenseCarbon/icon.png'
    
    
            icon = QIcon(self.icon_path)
            self.action = QAction(icon, self.tr(u'SenseCarbon Time Series Viewer'), self.iface.mainWindow())
            self.action.triggered.connect(self.run)
            #action.setEnabled(enabled_flag)
    
            #add to toolbar:
            self.iface.addToolBarIcon(self.action)
    
    
    unknown's avatar
    unknown committed
    
    
    
        def ua_addTSD_to_QGIS(self, TSD, bands):
    
    unknown's avatar
    unknown committed
        def unload(self):
    
            """Removes the plugin menu item and icon """
            self.iface.removeToolBarIcon(self.action)
    
    unknown's avatar
    unknown committed
    
        def run(self):
            """Run method that performs all the real work"""
    
            #self.dlg.setWindowIcon(QIcon(self.icon_path))
            # show the GUI
            self.dlg.show()
    
    
    
        def scrollToDate(self, date_of_interest):
    
            HBar = self.dlg.scrollArea_imageChips.horizontalScrollBar()
    
            TSDs = list(self.CHIPWIDGETS.keys())
            if len(TSDs) == 0:
    
                return
    
            #get date INDEX that is closest to requested date
    
            if type(date_of_interest) is str:
                date_of_interest = np.datetime64(date_of_interest)
    
    
            if type(date_of_interest) is np.datetime64:
                i_doi = TSDs.index(sorted(TSDs, key=lambda TSD: abs(date_of_interest - TSD.getDate()))[0])
            else:
                i_doi = date_of_interest
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            step = int(float(HBar.maximum()) / (len(TSDs)+1))
            HBar.setSingleStep(step)
            HBar.setPageStep(step*5)
            HBar.setValue(i_doi * step)
    
    unknown's avatar
    unknown committed
        def ua_showPxCoordinate_start(self):
    
    unknown's avatar
    unknown committed
    
            if len(self.TS) == 0:
                return
    
    unknown's avatar
    unknown committed
            D = self.dlg
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            dx = D.doubleSpinBox_subset_size_x.value() * 0.5
    
    unknown's avatar
    unknown committed
            dy = D.doubleSpinBox_subset_size_y.value() * 0.5
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
            cx = D.spinBox_coordinate_x.value()
            cy = D.spinBox_coordinate_y.value()
    
    unknown's avatar
    unknown committed
    
    
            pts = [(cx - dx, cy + dy), \
                   (cx + dx, cy + dy), \
                   (cx + dx, cy - dy), \
                   (cx - dx, cy - dy)]
    
    unknown's avatar
    unknown committed
    
    
            bb = getBoundingBoxPolygon(pts, srs=self.canvas_srs)
    
    unknown's avatar
    unknown committed
            bbWkt = bb.ExportToWkt()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            srsWkt = bb.GetSpatialReference().ExportToWkt()
    
    unknown's avatar
    unknown committed
            self.ImageChipBuffer.setBoundingBox(bb)
    
            D = self.dlg
    
    unknown's avatar
    unknown committed
            ratio = dx / dy
            size_px = D.spinBox_chipsize_max.value()
            if ratio > 1: #x is largest side
                size_x = size_px
                size_y = int(size_px / ratio)
            else: #y is largest
                size_y = size_px
                size_x = int(size_px * ratio)
    
    unknown's avatar
    unknown committed
    
    
    unknown's avatar
    unknown committed
            #get the dates of interes
            dates_of_interest = list()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            doiTSD = D.cb_doi.itemData(D.cb_doi.currentIndex())
            if doiTSD is None:
    
                idx = int(len(self.TS)/2)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                doiTSD = D.cb_doi.itemData(idx)
    
                D.cb_doi.setCurrentIndex(idx)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            centerDate = doiTSD.getDate()
    
            allDates = self.TS.getObservationDates()
    
            i_doi = allDates.index(centerDate)
    
    
    unknown's avatar
    unknown committed
            if D.rb_showEntireTS.isChecked():
    
                dates_of_interest = allDates
    
    unknown's avatar
    unknown committed
            elif D.rb_showTimeWindow.isChecked():
                i0 = max([0, i_doi-D.sb_ndates_before.value()])
    
                ie = min([i_doi + D.sb_ndates_after.value(), len(allDates)-1])
                dates_of_interest = allDates[i0:ie+1]
    
    unknown's avatar
    unknown committed
    
    
    
            diff = set(dates_of_interest)
            diff = diff.symmetric_difference(self.CHIPWIDGETS.keys())
    
    unknown's avatar
    unknown committed
    
    
            self.clearLayoutWidgets(self.ICP)
    
    unknown's avatar
    unknown committed
            self.CHIPWIDGETS.clear()
    
    
    unknown's avatar
    unknown committed
    
            #initialize image labels
    
    
            cnt_chips = 0
    
            TSDs_of_interest = list()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
            for date in dates_of_interest:
    
    unknown's avatar
    unknown committed
    
                #LV = QVBoxLayout()
                #LV.setSizeConstraint(QLayout.SetNoConstraint)
    
    
                for TSD in self.TS.getTSDs(date_of_interest=date):
                    TSDs_of_interest.append(TSD)
                    info_label_text = '{}\n{}'.format(TSD.date, TSD.sensor.sensor_name)
                    textLabel = QLabel(info_label_text)
    
                    tt = [TSD.date,TSD.pathImg, TSD.pathMsk]
    
                    textLabel.setToolTip(list2str(tt))
    
                    self.ICP.addWidget(textLabel, 0, cnt_chips)
                    viewList = list()
                    j = 1
                    for view in self.BAND_VIEWS:
    
                        bands = view.getBands(TSD.sensor)
    
                        #imageLabel = QLabel()
                        #imv = pg.GraphicsView()
                        #imv = QGraphicsView(self.dlg.scrollArea_imageChip_content)
                        #imv = MyGraphicsView(self.dlg.scrollArea_imageChip_content, iface=self.iface, path=TSD.pathImg, bands=bands)
                        #imv = pg.ImageView(view=None)
    
                        imgLabel = ImageChipLabel(time_series_viewer=self.dlg, iface=self.iface, TSD=TSD, bands=bands)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
                        imgLabel.setMinimumSize(size_x, size_y)
                        imgLabel.setMaximumSize(size_x, size_y)
    
                        imgLabel.clicked.connect(self.ua_collect_date)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
                        viewList.append(imgLabel)
                        self.ICP.addWidget(imgLabel, j, cnt_chips)
    
                        j += 1
    
                    textLabel = QLabel(info_label_text)
                    textLabel.setToolTip(str(TSD))
                    self.ICP.addWidget(textLabel, j, cnt_chips)
    
                    self.CHIPWIDGETS[TSD] = viewList
    
                    cnt_chips += 1
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.dlg.scrollArea_imageChip_content.update()
    
    
            self.scrollToDate(centerDate)
    
            s = ""
            #ScrollArea.show()
            #ScrollArea.horizontalScrollBar().setValue()
    
    
    
    unknown's avatar
    unknown committed
    
            #fill image labels
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            required_bands = dict()
            for j, view in enumerate(self.BAND_VIEWS):
                    for S in view.Sensors.keys():
    
                        bands = set()
                        bands.update(view.getBands(S))
                        if len(bands) != 3:
                            s = ""
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                        assert len(bands) == 3
                        if S not in required_bands.keys():
                            required_bands[S] = set()
                        required_bands[S] = required_bands[S].union(bands)
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            missing = set()
    
            for TSD in TSDs_of_interest:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                missing_bands = self.ImageChipBuffer.getMissingBands(TSD, required_bands[TSD.sensor])
                if len(missing_bands) == 0:
    
                    self.ua_showPxCoordinate_addChips(None, TSD=TSD)
    
    unknown's avatar
    unknown committed
                else:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    missing.add((TSD, tuple(missing_bands)))
    
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            missing =list(missing)
            if len(missing) > 0:
                missing = sorted(missing, key=lambda d: abs(centerDate - d[0].getDate()))
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                self.TS.getSpatialChips_parallel(bbWkt, srsWkt, TSD_band_list=missing)
    
        def ua_collect_date(self, ICL, event):
            if self.dlg.rb_labeling_activate.isChecked():
    
                txt = self.dlg.tb_labeling_text.toPlainText()
                reg = re.compile('\d{4}-\d{2}-\d{2}', re.I | re.MULTILINE)
                dates = set([np.datetime64(m) for m in reg.findall(txt)])
                doi = ICL.TSD.getDate()
    
    
                if event.button() == Qt.LeftButton:
    
                    dates.add(doi)
    
                elif event.button() == Qt.MiddleButton and doi in dates:
                    dates.remove(doi)
    
    
                dates = sorted(list(dates))
                txt = ' '.join([d.astype(str) for d in dates])
                self.dlg.tb_labeling_text.setText(txt)
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
        def ua_showPxCoordinate_addChips(self, results, TSD=None):
    
    unknown's avatar
    unknown committed
    
            if results is not None:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                TSD, chipData = results
                self.ImageChipBuffer.addDataCube(TSD, chipData)
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            if TSD not in self.CHIPWIDGETS.keys():
                six.print_('TSD {} does not exist in CHIPBUFFER'.format(TSD), file=sys.stderr)
            else:
                for imgChipLabel, bandView in zip(self.CHIPWIDGETS[TSD], self.BAND_VIEWS):
                    #imgView.clear()
                    #imageLabel.setScaledContents(True)
    
                    #rgb = self.ImageChipBuffer.getChipRGB(TSD, bandView)
                    array = self.ImageChipBuffer.getChipArray(TSD, bandView, mode = 'bgr')
                    qimg = pg.makeQImage(array, copy=True, transpose=False)
    
                    #rgb2 = rgb.transpose([1,2,0]).copy('C')
                    #qImg = qimage2ndarray.array2qimage(rgb2)
                    #img = QImage(rgb2.data, nl, ns, QImage.Format_RGB888)
    
                    pxMap = QPixmap.fromImage(qimg).scaled(imgChipLabel.size(), Qt.KeepAspectRatio)
                    imgChipLabel.setPixmap(pxMap)
                    imgChipLabel.update()
                    #imgView.setPixmap(pxMap)
                    #imageLabel.update()
                    #imgView.adjustSize()
                    #pxmap = QPixmap.fromImage(qimg)
                    #
    
                    """
                    pxmapitem = QGraphicsPixmapItem(pxmap)
                    if imgChipLabel.scene() is None:
                        imgChipLabel.setScene(QGraphicsScene())
                    else:
                        imgChipLabel.scene().clear()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    scene = imgChipLabel.scene()
                    scene.addItem(pxmapitem)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    imgChipLabel.fitInView(scene.sceneRect(), Qt.KeepAspectRatio)
                    """
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    pass
                self.ICP.layout().update()
                self.dlg.scrollArea_imageChip_content.update()
                s = ""
    
    unknown's avatar
    unknown committed
    
            pass
    
        def clearLayoutWidgets(self, L):
            if L is not None:
                while L.count():
                    w = L.takeAt(0)
                    w.widget().deleteLater()
                    #if w is not None:
                    #    w.widget().deleteLater()
    
    unknown's avatar
    unknown committed
    
        def ua_addTSImages(self, files=None):
            if files is None:
                files = QFileDialog.getOpenFileNames()
    
            if files:
                M = self.dlg.tableView_TimeSeries.model()
                M.beginResetModel()
                self.TS.addFiles(files)
                M.endResetModel()
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                self.refreshBandViews()
    
    
    unknown's avatar
    unknown committed
            self.check_enabled()
    
    
        def ua_addTSMasks(self, files=None):
    
            if files is None:
                files = QFileDialog.getOpenFileNames()
    
            l = len(files)
            if l > 0:
                M = self.dlg.tableView_TimeSeries.model()
                M.beginResetModel()
    
    unknown's avatar
    unknown committed
                self.TS.addMasks(files, raise_errors=False)
    
    unknown's avatar
    unknown committed
                M.endResetModel()
    
            self.check_enabled()
    
    
    
    
        def ua_addBandView(self, band_recommendation = [3, 2, 1]):
    
            bandView = BandView(self.TS, recommended_bands=band_recommendation)
            #bandView.removeView.connect(self.ua_removeBandView)
            self.BAND_VIEWS.append(bandView)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def refreshBandViews(self):
    
    
            if len(self.BAND_VIEWS) == 0 and len(self.TS) > 0:
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                self.ua_addBandView(band_recommendation=[3, 2, 1])
                self.ua_addBandView(band_recommendation=[4, 5, 3])
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            self.clearLayoutWidgets(self.BVP)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
            for i, BV in enumerate(self.BAND_VIEWS):
                W = QWidget()
                hl = QHBoxLayout()
                textLabel = VerticalLabel('View {}'.format(i+1))
                textLabel = QLabel('View {}'.format(i+1))
                textLabel.setToolTip('')
                textLabel.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)
                hl.addWidget(textLabel)
    
                for S in self.TS.Sensors.keys():
                    w = BV.getWidget(S)
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
                    w.setMaximumSize(w.size())
                    #w.setMinimumSize(w.size())
                    w.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.MinimumExpanding)
                    #w.setBands(band_recommendation)
                    hl.addWidget(w)
                    s = ""
    
                hl.addItem(QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum))
                W.setLayout(hl)
                self.BVP.addWidget(W)
            self.check_enabled()
    
    unknown's avatar
    unknown committed
    
    
    unknown's avatar
    unknown committed
    
    
    Benjamin Jakimow's avatar
    Benjamin Jakimow committed
        def ua_removeBandView(self, w):
            self.BAND_VIEWS.remove(w)
    
        def ua_clear_TS(self):
    
    unknown's avatar
    unknown committed
            #remove views
    
            M = self.dlg.tableView_TimeSeries.model()
            M.beginResetModel()
            self.TS.clear()
            M.endResetModel()
            self.check_enabled()
    
    
        def ua_removeTSD(self, TSDs=None):
            if TSDs is None:
                TSDs = self.getSelectedTSDs()
            assert isinstance(TSDs,list)
    
    unknown's avatar
    unknown committed
    
    
    unknown's avatar
    unknown committed
            M = self.dlg.tableView_TimeSeries.model()
            M.beginResetModel()
    
            self.TS.removeDates(TSDs)
    
    unknown's avatar
    unknown committed
            M.endResetModel()
    
    unknown's avatar
    unknown committed
            self.check_enabled()
    
    unknown's avatar
    unknown committed
    
    
    
        def getSelectedTSDs(self):
    
            TV = self.dlg.tableView_TimeSeries
            TVM = TV.model()
    
            return [TVM.getTimeSeriesDatumFromIndex(idx) for idx in TV.selectionModel().selectedRows()]
    
    def disconnect_signal(signal):
        while True:
            try:
                signal.disconnect()
            except TypeError: