diff --git a/timeseriesviewer/main.py b/timeseriesviewer/main.py
index a551e2c586771338c602b31d97100cf09727d08c..552811facceff068f2be72e77080614be8fd2b70 100644
--- a/timeseriesviewer/main.py
+++ b/timeseriesviewer/main.py
@@ -73,7 +73,9 @@ import pyqtgraph as pg
 
 
 class SpatialExtent(QgsRectangle):
-
+    """
+    Object to keep QgsRectangle and QgsCoordinateReferenceSystem together
+    """
     @staticmethod
     def fromMapCanvas(mapCanvas):
         assert isinstance(mapCanvas, QgsMapCanvas)
@@ -81,8 +83,6 @@ class SpatialExtent(QgsRectangle):
         crs = mapCanvas.mapSettings().destinationCrs()
         return SpatialExtent(crs, extent)
 
-
-
     def __init__(self, crs, *args):
         assert isinstance(crs, QgsCoordinateReferenceSystem)
         super(SpatialExtent, self).__init__(*args)
@@ -95,8 +95,6 @@ class SpatialExtent(QgsRectangle):
     def crs(self):
         return self.mCrs
 
-
-
     def toCrs(self, crs):
         assert isinstance(crs, QgsCoordinateReferenceSystem)
         box = QgsRectangle(self)
@@ -153,78 +151,253 @@ class SpatialExtent(QgsRectangle):
 
         return '{} {} {}'.format(self.upperLeft(), self.lowerRight(), self.crs().authid())
 
+class TsvMimeDataUtils(QObject):
+    def __init__(self, mimeData):
+        assert isinstance(mimeData, QMimeData)
+        super(TsvMimeDataUtils, self).__init__()
+
+        self.mimeData = mimeData
+
+        self.xmlDoc = QDomDocument()
+
+        if self.mimeData.hasText():
+            self.xmlDoc.setContent(self.mimeData.text())
+        self.xmlRoot = self.xmlDoc.documentElement()
+        pass
+
+    def hasRasterStyle(self):
+        if self.xmlRoot.tagName() == 'qgis':
+            elem = self.xmlRoot.elementsByTagName('rasterrenderer')
+            return elem.count() != 0
+
+        return False
+
+
+    def rasterStyle(self, qgisDataType):
+
+        elem = self.xmlRoot.elementsByTagName('rasterrenderer').item(0).toElement()
+        type = str(elem.attribute('type'))
+        from qgis.core import QGis, QgsContrastEnhancement
+
+        def bandSettings(colorName):
+            band = int(elem.attribute(colorName + 'Band'))
+            ceNode = elem.elementsByTagName(colorName + 'ContrastEnhancement').item(0)
+            vMin = float(ceNode.firstChildElement('minValue').firstChild().nodeValue())
+            vMax = float(ceNode.firstChildElement('maxValue').firstChild().nodeValue())
+            ceName = ceNode.firstChildElement('algorithm').firstChild().nodeValue()
+            ceAlg = QgsContrastEnhancement.contrastEnhancementAlgorithmFromString(ceName)
+            ce = QgsContrastEnhancement(qgisDataType)
+            ce.setContrastEnhancementAlgorithm(ceAlg)
+            ce.setMinimumValue(vMin)
+            ce.setMaximumValue(vMax)
+            return band, ce
+
+        style = None
+        if type == 'multibandcolor':
+                A = int(elem.attribute('alphaBand'))
+                O = int(elem.attribute('opacity'))
+                R, ceR = bandSettings('red')
+                G, ceG = bandSettings('green')
+                B, ceB = bandSettings('blue')
+
+                style = QgsMultiBandColorRenderer(None, R, G, B)
+                style.setRedContrastEnhancement(ceR)
+                style.setGreenContrastEnhancement(ceG)
+                style.setBlueContrastEnhancement(ceB)
+
+        elif type == 'singlebandgrey':
+
+            pass
+
+        return style
+
+class QgisTsvBridge(QObject):
+    """
+    Class to control interactions between TSV and a running QGIS instance
+    """
+    _instance = None
+
+
+    @staticmethod
+    def instance():
+        return QgisTsvBridge._instance
+
+    def __init__(self, iface, TSV_UI):
+        super(QgisTsvBridge, self).__init__()
+        assert QgisTsvBridge._instance is None
+        assert isinstance(iface, QgisInterface)
+        self.iface = iface
+        self.ui = TSV_UI
+        self.cbVectorLayer = TSV_UI.cbQgsVectorLayer
+
+    def extent(self):
+        canvas = self.iface.mapCanvas()
+        assert isinstance(canvas, QgsMapCanvas)
+        crs = canvas.dest
+        self.iface.mapCanvas().extent()
+        s = ""
+
+    def center(self):
+        s = ""
+
+    def crs(self):
+        s = ""
+
+    def getVectorLayerRepresentation(self):
+        if self.ui.gbQgsVectorLayer.isChecked():
+            lyr = self.cbVectorLayer.currentLayer()
+            alpha = self.ui.sliderQgsVectorTransparency.value()
+            return lyr
+        else:
+            return None
+
+
+    def syncExtent(self, isChecked):
+        if isChecked:
+            self.dockRendering.cbSyncQgsMapCenter.setEnabled(False)
+            self.dockRendering.cbSyncQgsMapCenter.blockSignals(True)
+            self.dockRendering.cbSyncQgsMapCenter.setChecked(True)
+            self.dockRendering.cbSyncQgsMapCenter.blockSignals(False)
+        else:
+            self.dockRendering.cbSyncQgsMapCenter.setEnabled(True)
+        self.qgsSyncStateChanged()
+
+    def qgsSyncState(self):
+        return (self.cbSyncQgsMapCenter.isChecked(),
+                self.cbSyncQgsMapExtent.isChecked(),
+                self.cbSyncQgsCRS.isChecked())
+
+    def qgsSyncStateChanged(self, *args):
+        s = self.qgsSyncState()
+        self.sigQgsSyncChanged.emit(s[0], s[1], s[2])
+
+
 
 from timeseriesviewer.ui.widgets import *
 from timeseriesviewer.timeseries import TimeSeries, TimeSeriesDatum, SensorInstrument
 
+class SensorTableModel(QAbstractTableModel):
+    columnames = ['sensor', 'nb', 'n images']
+
+    def __init__(self, TS, parent=None, *args):
+        super(SensorTableModel, self).__init__()
+        assert isinstance(TS, TimeSeries)
+        self.TS = TS
+
 
 class TimeSeriesTableModel(QAbstractTableModel):
-    columnames = ['date','sensor','ns','nl','nb','image','mask']
+    columnames = ['date', 'sensor', 'ns', 'nl', 'nb', 'image', 'mask']
 
     def __init__(self, TS, parent=None, *args):
-        super(QAbstractTableModel, self).__init__()
+
+        super(TimeSeriesTableModel, self).__init__()
         assert isinstance(TS, TimeSeries)
         self.TS = TS
 
+        self.TS.sigTimeSeriesDatesRemoved.connect(self.removeTSDs)
+        self.TS.sigTimeSeriesDatesAdded.connect(self.addTSDs)
+
+        self.items = []
+        self.sortColumnIndex = 0
+        self.sortOrder = Qt.AscendingOrder
+        self.addTSDs([tsd for tsd in self.TS])
+
+    def removeTSDs(self, tsds):
+        #self.TS.removeDates(tsds)
+        for tsd in tsds:
+            if tsd in self.TS:
+                #remove from TimeSeries first.
+                self.TS.removeDates([tsd])
+            elif tsd in self.items:
+                idx = self.getIndexFromDate(tsd)
+                self.removeRows(idx.row(), 1)
+
+        #self.sort(self.sortColumnIndex, self.sortOrder)
+
+
+    def addTSDs(self, tsds):
+        self.items.extend(tsds)
+        self.sort(self.sortColumnIndex, self.sortOrder)
+
+
+
+    def sort(self, col, order):
+        if self.rowCount() == 0:
+            return
+
+        self.layoutAboutToBeChanged.emit()
+        colName = self.columnames[col]
+        r = order != Qt.AscendingOrder
+
+        if colName in ['date','ns','nl','sensor']:
+            self.items.sort(key = lambda d:d.__dict__[colName], reverse=r)
+
+        self.layoutChanged.emit()
+        s = ""
+
+
     def rowCount(self, parent = QModelIndex()):
-        return len(self.TS)
+        return len(self.items)
 
-    def columnCount(self, parent = QModelIndex()):
-        return len(self.columnames)
 
     def removeRows(self, row, count , parent=QModelIndex()):
         self.beginRemoveRows(parent, row, row+count-1)
-        toRemove = self._data[row:row+count]
-        for i in toRemove:
-            self._data.remove(i)
-
+        toRemove = self.items[row:row+count]
+        for tsd in toRemove:
+            self.items.remove(tsd)
         self.endRemoveRows()
 
+    def getIndexFromDate(self, tsd):
+        return self.createIndex(self.items.index(tsd),0)
+
     def getDateFromIndex(self, index):
         if index.isValid():
-            i = index.row()
-            if i >= 0 and i < len(self.TS):
-                return self.TS.getTSDs()[i]
+            return self.items[index.row()]
         return None
 
     def getTimeSeriesDatumFromIndex(self, index):
-
         if index.isValid():
             i = index.row()
-            if i >= 0 and i < len(self.TS):
-                return self.TS.data[i]
+            if i >= 0 and i < len(self.items):
+                return self.items[i]
 
         return None
 
-
+    def columnCount(self, parent = QModelIndex()):
+        return len(self.columnames)
 
     def data(self, index, role = Qt.DisplayRole):
         if role is None or not index.isValid():
             return None
 
-
         value = None
-        ic_name = self.columnames[index.column()]
+        columnName = self.columnames[index.column()]
+
         TSD = self.getTimeSeriesDatumFromIndex(index)
         keys = list(TSD.__dict__.keys())
+
+
         if role == Qt.DisplayRole or role == Qt.ToolTipRole:
-            if ic_name == 'name':
+            if columnName == 'name':
                 value = os.path.basename(TSD.pathImg)
-            elif ic_name == 'sensor':
+            elif columnName == 'sensor':
                 if role == Qt.ToolTipRole:
                     value = TSD.sensor.getDescription()
                 else:
                     value = str(TSD.sensor)
-            elif ic_name == 'date':
+            elif columnName == 'date':
                 value = '{}'.format(TSD.date)
-            elif ic_name == 'image':
+            elif columnName == 'image':
                 value = TSD.pathImg
-            elif ic_name == 'mask':
+            elif columnName == 'mask':
                 value = TSD.pathMsk
-            elif ic_name in keys:
-                value = TSD.__dict__[ic_name]
+            elif columnName in keys:
+                value = TSD.__dict__[columnName]
             else:
                 s = ""
+        elif role == Qt.CheckStateRole:
+            if columnName == 'date':
+                value = Qt.Checked if TSD.isVisible() else Qt.Unchecked
         elif role == Qt.BackgroundColorRole:
             value = None
         elif role == Qt.UserRole:
@@ -232,17 +405,33 @@ class TimeSeriesTableModel(QAbstractTableModel):
 
         return value
 
-    #def flags(self, index):
-    #    return Qt.ItemIsEnabled
+    def setData(self, index, value, role=None):
+        if role is None or not index.isValid():
+            return None
+
+        if role is Qt.UserRole:
+
+            s = ""
+
+        columnName = self.columnames[index.column()]
+
+        TSD = self.getTimeSeriesDatumFromIndex(index)
+        if columnName == 'date' and role == Qt.CheckStateRole:
+            TSD.setVisibility(value != Qt.Unchecked)
+            return True
+        else:
+            return False
+
+        return False
 
     def flags(self, index):
         if index.isValid():
-            item = self.getTimeSeriesDatumFromIndex(index)
-            cname = self.columnames[index.column()]
-            if cname.startswith('d'): #relative values can be edited
-                flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
-            else:
-                flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
+            TSD = self.getTimeSeriesDatumFromIndex(index)
+            columnName = self.columnames[index.column()]
+            flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
+            if columnName == 'date': #allow check state
+                flags = flags | Qt.ItemIsUserCheckable
+
             return flags
             #return item.qt_flags(index.column())
         return None
@@ -256,108 +445,278 @@ class TimeSeriesTableModel(QAbstractTableModel):
             return col
         return None
 
-class TimeSeriesItemModel(QAbstractItemModel):
 
-    def __init__(self, TS):
-        QAbstractItemModel.__init__(self)
-        #self.rootItem = TreeItem[]
-        assert type(TS) is TimeSeries
-        self.TS = TS
+class MapView(QObject):
 
-    def index(self, row, column, parent = QModelIndex()):
-        if not parent.isValid():
-            parentItem = self.rootItem
-        else:
-            parentItem = parent.internalPointer()
-        childItem = parentItem.child(row)
-        if childItem:
-            return self.createIndex(row, column, childItem)
-        else:
-            return QModelIndex()
+    sigRemoveMapView = pyqtSignal(object)
+    sigMapViewVisibility = pyqtSignal(bool)
+    sigTitleChanged = pyqtSignal(str)
+    sigSensorRendererChanged = pyqtSignal(SensorInstrument, QgsRasterRenderer)
+    sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
+
+    def __init__(self, mapViewCollection, recommended_bands=None, parent=None):
+        super(MapView, self).__init__()
+        assert isinstance(mapViewCollection, MapViewCollection)
+        self.MVC = mapViewCollection
+        self.ui = MapViewDefinitionUI(self, parent=parent)
+        self.ui.create()
+
+        self.setVisibility(True)
+
+        #forward actions with reference to this band view
+        self.spatialExtent = None
+        self.ui.actionRemoveMapView.triggered.connect(lambda: self.sigRemoveMapView.emit(self))
+        self.ui.actionApplyStyles.triggered.connect(self.applyStyles)
+        self.ui.sigShowMapView.connect(lambda: self.sigMapViewVisibility.emit(True))
+        self.ui.sigHideMapView.connect(lambda: self.sigMapViewVisibility.emit(False))
+        self.sensorViews = collections.OrderedDict()
+
+        self.mSpatialExtent = None
+
+    def applyStyles(self):
+        for sensorView in self.sensorViews.values():
+            sensorView.applyStyle()
+        s = ""
+
+
+    def setVisibility(self, isVisible):
+        self.ui.setVisibility(isVisible)
+
+    def setSpatialExtent(self, extent):
+        assert isinstance(extent, SpatialExtent)
+        self.mSpatialExtent = extent
+        self.sigSpatialExtentChanged.emit(extent)
+
+    def visibility(self):
+        return self.ui.visibility()
+
+    def setTitle(self, title):
+        self.mTitle = title
+        self.ui.setTitle('Map View' + title)
+        self.sigTitleChanged.emit(self.mTitle)
+
+    def title(self):
+        return self.mTitle
 
-    def setData(self, index, value, role = Qt.EditRole):
-        if role == Qt.EditRole:
-            row = index.row()
 
+    def removeSensor(self, sensor):
+        assert type(sensor) is SensorInstrument
+        if sensor in self.sensorViews.keys():
+            self.sensorViews[sensor].close()
+            self.sensorViews.pop(sensor)
+            self.ui.adjustSize()
+            return True
+        else:
             return False
-        return False
 
-    def data(self, index, role=Qt.DisplayRole):
-        data = None
-        if role == Qt.DisplayRole or role == Qt.EditRole:
-            data = 'sampletext'
+    def hasSensor(self, sensor):
+        assert type(sensor) is SensorInstrument
+        return sensor in self.sensorViews.keys()
+
+    def addSensor(self, sensor):
+        """
+        :param sensor:
+        :return:
+        """
+        assert type(sensor) is SensorInstrument
+        assert sensor not in self.sensorViews.keys()
+        w = MapViewSensorSettings(sensor)
+
+        #w.showSensorName(False)
+        self.sensorViews[sensor] = w
+        l = self.ui.sensorList
+        i = l.count()
+        l.addWidget(w.ui)
+        from timeseriesviewer.ui.widgets import maxWidgetSizes
+
+
+        s = ""
 
 
-        return data
+    def getSensorWidget(self, sensor):
+        assert type(sensor) is SensorInstrument
+        return self.sensorViews[sensor]
 
-    def flags(self, QModelIndex):
-        return Qt.ItemIsSelectable
 
-    def rowCount(self, index=QModelIndex()):
-        return len(self.TS)
 
-    #---------------------------------------------------------------------------
-    def columnCount(self, index=QModelIndex()):
-        return 1
 
+class TimeSeriesDatumView(QObject):
 
-class TimeSeriesDateViewManager(QObject):
+    sigExtentsChanged = pyqtSignal(SpatialExtent)
+    sigRenderProgress = pyqtSignal(int,int)
+    sigLoadingStarted = pyqtSignal(MapView, TimeSeriesDatum)
+    sigLoadingFinished = pyqtSignal(MapView, TimeSeriesDatum)
+    sigVisibilityChanged = pyqtSignal(bool)
 
-    def __init__(self, timeSeriesViewer):
-        assert isinstance(timeSeriesViewer, TimeSeriesViewer)
-        super(TimeSeriesDateViewManager, self).__init__()
+    def __init__(self, TSD, timeSeriesDateViewCollection, mapViewCollection, parent=None):
+        assert isinstance(TSD, TimeSeriesDatum)
+        assert isinstance(timeSeriesDateViewCollection, TimeSeriesDateViewCollection)
+        assert isinstance(mapViewCollection, MapViewCollection)
+
+        super(TimeSeriesDatumView, self).__init__()
+        self.ui = TimeSeriesDatumViewUI(parent)
+        self.ui.create()
+
+        self.L = self.ui.layout()
+        self.wOffset = self.L.count()-1
+        self.minHeight = self.ui.height()
+        self.minWidth = 50
+        self.renderProgress = dict()
 
-        self.TSV = timeSeriesViewer
-        self.TSDViews = list()
+        self.TSD = TSD
+        self.Sensor = self.TSD.sensor
+        self.TSD.sigVisibilityChanged.connect(self.setVisibility)
+        self.ui.labelTitle.setText(str(TSD.date))
+        self.MVC = mapViewCollection
+        self.TSDVC = timeSeriesDateViewCollection
+        self.mapCanvases = dict()
+        self.setSubsetSize(QSize(50, 50))
+
+    def setVisibility(self, b):
+        self.ui.setVisible(b)
+        self.sigVisibilityChanged.emit(b)
+
+    def activateMapTool(self, key):
+        for c in self.mapCanvases.values():
+            c.activateMapTool(key)
 
-        self.mapViewManager = self.TSV.mapViewManager
-        self.mapViewManager.sigMapViewAdded.connect(self.addMapView)
-        self.mapViewManager.sigMapViewRemoved.connect(self.removeMapView)
-        self.mapViewManager.sigMapViewVisibility.connect(self.setMapViewVisibility)
+    def setMapViewVisibility(self, bandView, isVisible):
+        self.mapCanvases[bandView].setVisible(isVisible)
+
+    def setSpatialExtent(self, spatialExtent):
+        assert isinstance(spatialExtent, SpatialExtent)
+
+        for c in self.mapCanvases.values():
+            c.setSpatialExtent(spatialExtent)
 
-        self.setSpatialExtent(self.TSV.TS.getMaxSpatialExtent())
-        self.setMaxTSDViews()
-        self.initTimeSeries(self.TSV.TS)
-        self.L = self.TSV.ui.scrollAreaSubsetContent.layout()
+
+    def setSubsetSize(self, size):
+        assert isinstance(size, QSize)
+        assert size.width() > 5 and size.height() > 5
+        self.subsetSize = size
+
+
+        self.ui.labelTitle.setFixedWidth(size.width())
+        self.ui.line.setFixedWidth(size.width())
+
+        #apply new subset size to existing canvases
+
+        for canvas in self.mapCanvases.values():
+            canvas.setFixedSize(size)
+        self.adjustBaseMinSize()
+
+
+    def adjustBaseMinSize(self):
+        self.ui.setFixedSize(self.ui.sizeHint())
+
+    def removeMapView(self, mapView):
+        canvas = self.mapCanvases.pop(mapView)
+        self.L.removeWidget(canvas)
+        canvas.close()
+        self.adjustBaseMinSize()
+
+    def redraw(self):
+        if self.ui.isVisible():
+            for c in self.mapCanvases.values():
+                if c.isVisible():
+                    c.refreshAllLayers()
+
+    def insertMapView(self, mapView):
+        assert isinstance(mapView, MapView)
+
+        i = self.MVC.index(mapView)
+
+        canvas = TsvMapCanvas(self, mapView, parent=self.ui)
+
+        canvas.setFixedSize(self.subsetSize)
+        canvas.extentsChanged.connect(lambda : self.sigExtentsChanged.emit(canvas.spatialExtent()))
+        canvas.renderStarting.connect(lambda : self.sigLoadingStarted.emit(mapView, self.TSD))
+        canvas.mapCanvasRefreshed.connect(lambda: self.sigLoadingFinished.emit(mapView, self.TSD))
+
+
+        self.mapCanvases[mapView] = canvas
+        self.L.insertWidget(self.wOffset + i, canvas)
+        canvas.refreshMap()
+        self.adjustBaseMinSize()
+        return canvas
+
+    def __lt__(self, other):
+
+        return self.TSD < other.TSD
+
+    def __cmp__(self, other):
+        return cmp(self.TSD, other.TSD)
+
+
+
+class SpatialTemporalVisualization(QObject):
+    """
+
+    """
+
+    def __init__(self, timeSeriesViewer):
+        assert isinstance(timeSeriesViewer, TimeSeriesViewer)
+        super(SpatialTemporalVisualization, self).__init__()
+
+
+        self.TS = timeSeriesViewer.TS
+        self.targetLayout = timeSeriesViewer.ui.scrollAreaSubsetContent.layout()
+        self.dockMapViews = timeSeriesViewer.ui.dockMapViews
+        self.MVC = MapViewCollection(self)
+        self.timeSeriesDateViewCollection = TimeSeriesDateViewCollection(self)
+        self.timeSeriesDateViewCollection.sigResizeRequired.connect(self.adjustScrollArea)
+        self.timeSeriesDateViewCollection.sigLoadingStarted.connect(timeSeriesViewer.ui.dockRendering.addStartedWork)
+        self.timeSeriesDateViewCollection.sigLoadingFinished.connect(timeSeriesViewer.ui.dockRendering.addFinishedWork)
+        self.TS.sigTimeSeriesDatesAdded.connect(self.timeSeriesDateViewCollection.addDates)
+        self.TS.sigTimeSeriesDatesRemoved.connect(self.timeSeriesDateViewCollection.removeDates)
+        #add dates, if already existing
+        self.timeSeriesDateViewCollection.addDates(self.TS[:])
+
+        self.setSpatialExtent(self.TS.getMaxSpatialExtent())
         self.setSubsetSize(QSize(100,50))
 
+    def createMapView(self):
+        self.MVC.createMapView()
 
     def activateMapTool(self, key):
         for tsdv in self.TSDViews:
             tsdv.activateMapTool(key)
 
-
     def setSubsetSize(self, size):
         assert isinstance(size, QSize)
         self.subsetSize = size
-        for tsdv in self.TSDViews:
-            tsdv.setSubsetSize(size)
+        self.timeSeriesDateViewCollection.setSubsetSize(size)
         self.adjustScrollArea()
 
     def redraw(self):
-        for tsdv in self.TSDViews:
-            tsdv.redraw()
+        for tsdView in self.timeSeriesDateViewCollection:
+            tsdView.redraw()
 
 
     def adjustScrollArea(self):
+        #adjust scroll area widget to fit all visible widgets
+        m = self.targetLayout.contentsMargins()
+        n = len(self.timeSeriesDateViewCollection)
+        w = h = 0
+
+        s = QSize()
+        r = None
+        tmp = [v for v in self.timeSeriesDateViewCollection if not v.ui.isVisible()]
+        for TSDView in [v for v in self.timeSeriesDateViewCollection if v.ui.isVisible()]:
+            s = s + TSDView.ui.sizeHint()
+            if r is None:
+                r = TSDView.ui.sizeHint()
+        if r:
+            if isinstance(self.targetLayout, QHBoxLayout):
+
+                s = QSize(s.width(), r.height())
+            else:
+                s = QSize(r.width(), s.height())
 
-        m = self.L.contentsMargins()
-        n = len(self.TSDViews)
-        if n > 0:
-            refTSDView = self.TSDViews[0]
-            size = refTSDView.ui.size()
-
-            w = n * size.width() + (n-1) * (m.left()+ m.right())
-            h = max([refTSDView.ui.minimumHeight() + m.top() + m.bottom(),
-                     self.TSV.ui.scrollAreaSubsets.height()-25])
-
-            self.L.parentWidget().setFixedSize(w,h)
+            s = s + QSize(m.left() + m.right(), m.top() + m.bottom())
+            self.targetLayout.parentWidget().setFixedSize(s)
 
 
-    def initTimeSeries(self, TS):
-        assert isinstance(TS, TimeSeries)
-        self.TS = TS
-        self.TS.sigTimeSeriesDatesAdded.connect(self.createTSDViews)
 
     def setMaxTSDViews(self, n=-1):
         self.nMaxTSDViews = n
@@ -366,10 +725,8 @@ class TimeSeriesDateViewManager(QObject):
     def setSpatialExtent(self, extent):
         self.extent = extent
         if extent:
-            assert isinstance(extent, SpatialExtent)
-            tsdviews = sorted(self.TSDViews, key=lambda t:t.TSD)
-            for tsdview in tsdviews:
-                tsdview.setSpatialExtent(extent)
+            self.timeSeriesDateViewCollection.setSpatialExtent(extent)
+
 
     def navToDOI(self, TSD):
         assert isinstance(TSD, TimeSeriesDatum)
@@ -386,219 +743,222 @@ class TimeSeriesDateViewManager(QObject):
             scrollBar.setValue(int(round(v)))
 
     def setMapViewVisibility(self, bandView, isVisible):
-        assert isinstance(bandView, MapViewDefinition)
+        assert isinstance(bandView, MapView)
         assert isinstance(isVisible, bool)
 
         for tsdv in self.TSDViews:
             tsdv.setMapViewVisibility(bandView, isVisible)
 
-
-    def addMapView(self, bandView):
-        assert isinstance(bandView, MapViewDefinition)
-
-        w = self.L.parentWidget()
-        w.setUpdatesEnabled(False)
-
-        for tsdv in self.TSDViews:
-            tsdv.ui.setUpdatesEnabled(False)
-
-        for tsdv in self.TSDViews:
-            tsdv.insertMapView(bandView)
-
-        for tsdv in self.TSDViews:
-            tsdv.ui.setUpdatesEnabled(True)
-
-        w.setUpdatesEnabled(True)
+    sigLoadingStarted = pyqtSignal(TimeSeriesDatumView, MapView)
+    sigLoadingFinished = pyqtSignal(TimeSeriesDatumView, MapView)
 
 
 
-    def removeMapView(self, bandView):
-        assert isinstance(bandView, MapViewDefinition)
-        for tsdv in self.TSDViews:
-            tsdv.removeMapView(bandView)
 
-    def createTSDViews(self, timeSeriesDates):
-        for TSD in timeSeriesDates:
-            assert isinstance(TSD, TimeSeriesDatum)
-            tsdView = TimeSeriesDatumView(TSD)
-            tsdView.setSubsetSize(self.subsetSize)
-            tsdView.sigExtentsChanged.connect(self.setSpatialExtent)
-            for i, bandView in enumerate(self.mapViewManager):
-                tsdView.insertMapView(bandView)
-            if self.extent:
-                tsdView.setSpatialExtent(self.extent)
-            self.addTSDView(tsdView)
 
 
-    def removeTSD(self, TSD):
-        assert isinstance(TSD, TimeSeriesDatum)
-        tsdvs = [tsdv for tsdv in self.TSDViews if tsdv.TSD == TSD]
-        assert len(tsdvs) == 1
-        self.removeTSDView(tsdvs[0])
+class TimeSeriesDateViewCollection(QObject):
 
-    def removeTSDView(self, TSDV):
-        assert isinstance(TSDV, TimeSeriesDatumView)
-        self.TSDViews.remove(TSDV)
+    sigResizeRequired = pyqtSignal()
+    sigLoadingStarted = pyqtSignal(MapView, TimeSeriesDatum)
+    sigLoadingFinished = pyqtSignal(MapView, TimeSeriesDatum)
 
-    def addTSDView(self, TSDV):
-        assert isinstance(TSDV, TimeSeriesDatumView)
+    def __init__(self, STViz):
+        assert isinstance(STViz, SpatialTemporalVisualization)
+        super(TimeSeriesDateViewCollection, self).__init__()
+        #self.tsv = tsv
+        #self.timeSeries = tsv.TS
 
-        if len(self.TSDViews) < 10:
-            pass
+        self.views = list()
+        self.STViz = STViz
 
-        bisect.insort(self.TSDViews, TSDV)
+        #potentially there are many more dates than views.
+        #therefore we implement the addinng/removing of mapviews here
+        #we reduce the number of layout refresh calls by
+        #suspending signals, adding the new map view canvases, and sending sigResizeRequired
 
-        TSDV.ui.setParent(self.L.parentWidget())
-        self.L.addWidget(TSDV.ui)
+        self.STViz.MVC.sigMapViewAdded.connect(self.addMapView)
+        self.STViz.MVC.sigMapViewRemoved.connect(self.removeMapView)
 
-        self.adjustScrollArea()
-        #self.TSV.ui.scrollAreaSubsetContent.update()
-        #self.TSV.ui.scrollAreaSubsets.update()
-        s = ""
+        self.setFocusView(None)
+        self.setSubsetSize(QSize(50,50))
 
 
+    def addMapView(self, mapView):
+        assert isinstance(mapView, MapView)
+        w = self.STViz.targetLayout.parentWidget()
+        w.setUpdatesEnabled(False)
+        for tsdv in self.views:
 
+            tsdv.ui.setUpdatesEnabled(False)
 
-class MapViewDefinition(QObject):
+        for tsdv in self.views:
+            tsdv.insertMapView(mapView)
 
+        for tsdv in self.views:
+            tsdv.ui.setUpdatesEnabled(True)
 
-    sigRemoveMapView = pyqtSignal(object)
-    sigHideMapView = pyqtSignal()
-    sigShowMapView = pyqtSignal()
-    sigTitleChanged = pyqtSignal(str)
+        #mapView.sigSensorRendererChanged.connect(lambda *args : self.setRasterRenderer(mapView, *args))
+        w.setUpdatesEnabled(True)
+        self.sigResizeRequired.emit()
 
-    def __init__(self, recommended_bands=None, parent=None, showSensorNames=True):
-        super(MapViewDefinition, self).__init__()
-        self.ui = MapViewDefinitionUI(self, parent=parent)
-        self.ui.create()
-        self.setVisibility(True)
+    def removeMapView(self, mapView):
+        assert isinstance(mapView, MapView)
+        for tsdv in self.views:
+            tsdv.removeMapView(mapView)
+        self.sigResizeRequired.emit()
 
-        #forward actions with reference to this band view
 
-        self.ui.actionRemoveMapView.triggered.connect(lambda: self.sigRemoveMapView.emit(self))
-        self.ui.sigHideMapView.connect(lambda : self.sigHideMapView.emit())
-        self.ui.sigShowMapView.connect(lambda: self.sigShowMapView.emit())
-        self.sensorViews = collections.OrderedDict()
-        self.mShowSensorNames = showSensorNames
+    def setFocusView(self, tsd):
+        self.focusView = tsd
 
+    def setSpatialExtent(self, extent):
+        for tsdview in self.orderedViews():
+            tsdview.setSpatialExtent(extent)
+
+    def orderedViews(self):
+        #returns the
+        if self.focusView is not None:
+            assert isinstance(self.focusView, TimeSeriesDatumView)
+            return sorted(self.views,key=lambda v: np.abs(v.TSD.date - self.focusView.TSD.date))
+        else:
+            return self.views
 
-    def setVisibility(self, isVisible):
-        self.ui.setVisibility(isVisible)
+    def setSubsetSize(self, size):
+        assert isinstance(size, QSize)
+        self.subsetSize = size
+        for tsdView in self.orderedViews():
+            tsdView.setSubsetSize(size)
 
 
-    def visibility(self):
-        return self.ui.visibility()
 
-    def setTitle(self, title):
-        self.mTitle = title
-        self.ui.labelName.setText(title)
-        self.sigTitleChanged.emit(self.mTitle)
+    def addDates(self, tsdList):
+        """
+        Create a new TSDView
+        :param tsdList:
+        :return:
+        """
+        for tsd in tsdList:
+            assert isinstance(tsd, TimeSeriesDatum)
+            tsdView = TimeSeriesDatumView(tsd, self, self.STViz.MVC)
+            tsdView.setSubsetSize(self.subsetSize)
 
-    def title(self):
-        return self.mTitle
+            tsdView.sigExtentsChanged.connect(self.setSpatialExtent)
+            tsdView.sigLoadingStarted.connect(self.sigLoadingStarted.emit)
+            tsdView.sigLoadingFinished.connect(self.sigLoadingFinished.emit)
+            tsdView.sigVisibilityChanged.connect(lambda: self.STViz.adjustScrollArea())
 
-    def showSensorNames(self, b):
-        assert isinstance(b, bool)
-        self.mShowSensorNames = b
 
-        for s,w in self.sensorViews.items():
-            w.showSensorName(b)
+            for i, mapView in enumerate(self.STViz.MVC):
+                tsdView.insertMapView(mapView)
 
+            bisect.insort(self.views, tsdView)
+            tsdView.ui.setParent(self.STViz.targetLayout.parentWidget())
+            self.STViz.targetLayout.addWidget(tsdView.ui)
+            tsdView.ui.show()
 
-    def removeSensor(self, sensor):
-        assert type(sensor) is SensorInstrument
-        if sensor in self.sensorViews.keys():
-            self.sensorViews[sensor].close()
-            self.sensorViews.pop(sensor)
-            return True
-        else:
-            return False
 
-    def hasSensor(self, sensor):
-        assert type(sensor) is SensorInstrument
-        return sensor in self.sensorViews.keys()
+        if len(tsdList) > 0:
+            self.sigResizeRequired.emit()
 
-    def addSensor(self, sensor):
-        """
-        :param sensor:
-        :return:
-        """
-        assert type(sensor) is SensorInstrument
-        assert sensor not in self.sensorViews.keys()
-        w = MapViewRenderSettings(sensor)
-        #w.showSensorName(False)
-        self.sensorViews[sensor] = w
-        l = self.ui.sensorList
-        i = l.count()
-        l.addWidget(w.ui)
+    def removeDates(self, tsdList):
+        toRemove = [v for v in self.views if v.TSD in tsdList]
+        removedDates = []
+        for tsdView in toRemove:
 
+            self.views.remove(tsdView)
 
-    def getSensorWidget(self, sensor):
-        assert type(sensor) is SensorInstrument
-        return self.sensorViews[sensor]
+            tsdView.ui.parent().layout().removeWidget(tsdView.ui)
+            tsdView.ui.hide()
+            tsdView.ui.close()
+            removedDates.append(tsdView.TSD)
+            del tsdView
 
+        if len(removedDates) > 0:
+            self.sigResizeRequired.emit()
 
+    def __len__(self):
+        return len(self.views)
 
+    def __iter__(self):
+        return iter(self.views)
 
+    def __getitem__(self, slice):
+        return self.views[slice]
 
-class MapViewManager(QObject):
+    def __delitem__(self, slice):
+        self.removeDates(self.views[slice])
 
-    sigSensorAdded = pyqtSignal(SensorInstrument)
-    sigSensorRemoved = pyqtSignal(SensorInstrument)
-    sigMapViewAdded = pyqtSignal(MapViewDefinition)
-    sigMapViewRemoved = pyqtSignal(MapViewDefinition)
-    sigMapViewVisibility = pyqtSignal(MapViewDefinition, bool)
+class MapViewCollection(QObject):
 
-    def __init__(self, timeSeriesViewer):
-        assert isinstance(timeSeriesViewer, TimeSeriesViewer)
-        super(MapViewManager, self).__init__()
+    sigMapViewAdded = pyqtSignal(MapView)
+    sigMapViewRemoved = pyqtSignal(MapView)
+    sigSetMapViewVisibility = pyqtSignal(MapView, bool)
 
-        self.TSV = timeSeriesViewer
-        self.ui = self.TSV.ui
+    def __init__(self, STViz):
+        assert isinstance(STViz, SpatialTemporalVisualization)
+        super(MapViewCollection, self).__init__()
+        self.STViz = STViz
+        self.STViz.dockMapViews.actionApplyStyles.triggered.connect(self.applyStyles)
+        self.STViz.TS.sigSensorAdded.connect(self.addSensor)
+        self.btnList = STViz.dockMapViews.BVButtonList
+        self.scrollArea = STViz.dockMapViews.scrollAreaMapViews
+        self.scrollAreaContent = STViz.dockMapViews.scrollAreaMapsViewDockContent
         self.mapViewsDefinitions = []
         self.mapViewButtons = dict()
+        self.adjustScrollArea()
+    def applyStyles(self):
+        for mapView in self.mapViewsDefinitions:
+            mapView.applyStyles()
 
+    def index(self, mapView):
+        assert isinstance(mapView, MapView)
+        return self.mapViewsDefinitions.index(mapView)
 
-    def removeSensor(self, sensor):
-        assert isinstance(sensor, SensorInstrument)
+    def adjustScrollArea(self):
+        #adjust scroll area widget to fit all visible widgets
+        l = self.scrollAreaContent.layout()
+        from timeseriesviewer.ui.widgets import maxWidgetSizes
+        newSize = maxWidgetSizes(l)
+        #print(newSize)
+        #newSize = self.scrollAreaContent.sizeHint()
+        self.scrollAreaContent.setFixedSize(newSize)
 
-        removed = False
-        for view in self.mapViewsDefinitions:
-            removed = removed and view.removeSensor(sensor)
+    def addSensor(self, sensor):
+        for mapView in self.mapViewsDefinitions:
+            mapView.addSensor(sensor)
+        self.adjustScrollArea()
 
-        if removed:
-            self.sigSensorRemoved(sensor)
+    def removeSensor(self, sensor):
+        for mapView in self.mapViewsDefinitions:
+            mapView.removeSensor(sensor)
 
 
     def createMapView(self):
-        btnList = self.TSV.ui.dockMapViews.BVButtonList
-        btn = QToolButton(btnList)
-        btnList.layout().insertWidget(btnList.layout().count() - 1, btn)
 
-        mapView = MapViewDefinition(parent=self.TSV.ui.dockMapViews.scrollAreaMapViews, showSensorNames=False)
+        btn = QToolButton(self.btnList)
+        self.btnList.layout().insertWidget(self.btnList.layout().count() - 1, btn)
+
+        mapView = MapView(self, parent=self.scrollArea)
         mapView.sigRemoveMapView.connect(self.removeMapView)
-        mapView.sigShowMapView.connect(lambda : self.sigMapViewVisibility.emit(mapView, mapView.visibility()))
-        mapView.sigHideMapView.connect(lambda: self.sigMapViewVisibility.emit(mapView, mapView.visibility()))
-        #mapView.sigTitleChanged.connect(btn.setText)
 
-        #bandView.setTitle('#{}'.format(len(self)))
+        for sensor in self.STViz.TS.Sensors:
+            mapView.addSensor(sensor)
 
         self.mapViewButtons[mapView] = btn
         self.mapViewsDefinitions.append(mapView)
-        for sensor in self.TSV.TS.Sensors:
-            mapView.addSensor(sensor)
+
 
         btn.clicked.connect(lambda : self.showMapViewDefinition(mapView))
         self.refreshMapViewTitles()
-        self.sigMapViewAdded.emit(mapView)
-
         if len(self) == 1:
             self.showMapViewDefinition(mapView)
+        self.sigMapViewAdded.emit(mapView)
+        self.adjustScrollArea()
 
     def removeMapView(self, mapView):
-        assert isinstance(mapView, MapViewDefinition)
+        assert isinstance(mapView, MapView)
         btn = self.mapViewButtons[mapView]
-        btnList = self.TSV.ui.dockMapViews.BVButtonList
 
         idx = self.mapViewsDefinitions.index(mapView)
 
@@ -607,8 +967,8 @@ class MapViewManager(QObject):
 
         mapView.ui.setVisible(False)
         btn.setVisible(False)
-        btnList.layout().removeWidget(btn)
-        l = self.ui.dockMapViews.scrollAreaMapsViewDockContent.layout()
+        self.btnList.layout().removeWidget(btn)
+        l = self.scrollAreaContent.layout()
 
         for d in self.recentMapViewDefinitions():
             d.ui.setVisible(False)
@@ -618,13 +978,13 @@ class MapViewManager(QObject):
         btn.close()
         self.refreshMapViewTitles()
         self.sigMapViewRemoved.emit(mapView)
-
         if len(self) > 0:
             #show previous mapViewDefinition
             idxNext = max([idx-1, 0])
             self.showMapViewDefinition(self.mapViewsDefinitions[idxNext])
 
     def refreshMapViewTitles(self):
+
         for i, mapView in enumerate(self.mapViewsDefinitions):
             number = i+1
             title = '#{}'.format(number)
@@ -633,12 +993,16 @@ class MapViewManager(QObject):
             btn.setText('{}'.format(number))
             btn.setToolTip('Show definition for map view {}'.format(number))
             btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
-            s = ""
+
+
+    def setSpatialExtent(self, extent):
+        for mv in self.mapViewsDefinitions:
+            mv.setSpatialExtent(extent)
 
     def showMapViewDefinition(self, mapViewDefinition):
         assert mapViewDefinition in self.mapViewsDefinitions
-        assert isinstance(mapViewDefinition, MapViewDefinition)
-        l = self.ui.dockMapViews.scrollAreaMapsViewDockContent.layout()
+        assert isinstance(mapViewDefinition, MapView)
+        l = self.scrollAreaContent.layout()
 
         for d in self.recentMapViewDefinitions():
             d.ui.setVisible(False)
@@ -648,12 +1012,12 @@ class MapViewManager(QObject):
         mapViewDefinition.ui.setVisible(True)
 
     def recentMapViewDefinitions(self):
-        parent = self.ui.dockMapViews.scrollAreaMapsViewDockContent
+        parent = self.scrollAreaContent
         return [ui.mapViewDefinition() for ui in parent.findChildren(MapViewDefinitionUI)]
 
 
     def setMapViewVisibility(self, bandView, isVisible):
-        assert isinstance(bandView, MapViewDefinition)
+        assert isinstance(bandView, MapView)
         assert isinstance(isVisible, bool)
 
 
@@ -673,151 +1037,6 @@ class MapViewManager(QObject):
         return mapView in self.mapViewsDefinitions
 
 
-class TimeSeriesDatumView(QObject):
-
-    sigExtentsChanged = pyqtSignal(SpatialExtent)
-
-    def __init__(self, TSD, parent=None):
-
-        super(TimeSeriesDatumView, self).__init__()
-        self.ui = TimeSeriesDatumViewUI(parent)
-        self.ui.create()
-
-        self.TSD = None
-
-        self.mapCanvases = dict()
-        self.mapOrder = []
-        self.setTimeSeriesDatum(TSD)
-        self.L = self.ui.layout()
-        self.wOffset = self.L.count()-1
-        self.setSubsetSize(QSize(150,100))
-
-
-    def activateMapTool(self, key):
-        for c in self.mapCanvases.values():
-            c.activateMapTool(key)
-
-    def setMapViewVisibility(self, bandView, isVisible):
-        self.mapCanvases[bandView].setVisible(isVisible)
-
-    def setSpatialExtent(self, spatialExtent):
-        assert isinstance(spatialExtent, SpatialExtent)
-
-        for c in self.mapCanvases.values():
-            c.setSpatialExtent(spatialExtent)
-
-
-    def setSubsetSize(self, size):
-        assert isinstance(size, QSize)
-        assert size.width() > 5 and size.height() > 5
-        self.subsetSize = size
-        m = self.L.contentsMargins()
-
-        self.ui.labelTitle.setFixedWidth(size.width())
-        self.ui.line.setFixedWidth(size.width())
-
-        #apply new subset size to existing canvases
-        for c in self.mapCanvases.values():
-            c.setFixedSize(size)
-
-        self.ui.setFixedWidth(size.width() + 2*(m.left() + m.right()))
-        n = len(self.mapCanvases)
-        #todo: improve size forecast
-        self.ui.setMinimumHeight((n+1) * size.height())
-
-
-    def setTimeSeriesDatum(self, TSD):
-        assert isinstance(TSD, TimeSeriesDatum)
-        self.TSD = TSD
-        self.ui.labelTitle.setText(str(TSD.date))
-
-        for c in self.mapCanvases.values():
-            c.setLayer(self.TSD.pathImg)
-
-    def removeMapView(self, bandView):
-        self.mapOrder.remove(bandView)
-        canvas = self.mapCanvases.pop(bandView)
-        self.L.removeWidget(canvas)
-        canvas.close()
-
-    def redraw(self):
-        for c in self.mapCanvases.values():
-            c.refreshAllLayers()
-
-    def insertMapView(self, bandView, i=-1):
-        assert isinstance(bandView, MapViewDefinition)
-        assert bandView not in self.mapOrder
-        if len(self.mapCanvases) != len(self.mapOrder):
-            s = ""
-
-        assert i >= -1 and i <= len(self.mapOrder)
-        if i == -1:
-            i = len(self.mapCanvases)
-
-        canvas = MapViewMapCanvas(self.ui)
-        canvas.setLayer(self.TSD.pathImg)
-        canvas.setFixedSize(self.subsetSize)
-        canvas.extentsChanged.connect(lambda : self.sigExtentsChanged.emit(canvas.spatialExtent()))
-
-
-        self.mapCanvases[bandView] = canvas
-        self.mapOrder.insert(i, bandView)
-        self.L.insertWidget(self.wOffset + i, canvas)
-
-    def __lt__(self, other):
-
-        return self.TSD < other.TSD
-
-
-class RenderJob(object):
-
-    def __init__(self, TSD, renderer, destinationId=None):
-        assert isinstance(TSD, TimeSeriesDatum)
-        assert isinstance(renderer, QgsRasterRenderer)
-
-        self.TSD = TSD
-        self.renderer = renderer
-        self.destinationId = destinationId
-
-    def __eq__(self, other):
-        if not isinstance(other, RenderJob):
-            return False
-        return self.TSD == other.TSD and \
-               self.renderer == other.renderer and \
-               self.destinationId == other.destinationId
-
-
-
-list2str = lambda ll : '\n'.join([str(l) for l in ll])
-
-
-class QgsInstanceInteraction(QObject):
-
-    def __init__(self, iface, TSV_UI):
-        super(QgsInstanceInteraction, self).__init__()
-
-        self.iface = iface
-        self.ui = TSV_UI
-        self.cbVectorLayer = TSV_UI.cbQgsVectorLayer
-
-    def extent(self):
-        s = ""
-
-    def center(self):
-        s = ""
-
-    def crs(self):
-        s = ""
-
-    def getVectorLayerRepresentation(self):
-        if self.ui.gbQgsVectorLayer.isChecked():
-            lyr = self.cbVectorLayer.currentLayer()
-            alpha = self.ui.sliderQgsVectorTransparency.value()
-            return lyr
-        else:
-            return None
-
-
 class TimeSeriesViewer:
 
     def __init__(self, iface):
@@ -831,30 +1050,34 @@ class TimeSeriesViewer:
         # Save reference to the QGIS interface
         from timeseriesviewer.ui.widgets import TimeSeriesViewerUI
 
-        self.ui = TimeSeriesViewerUI()
+        self.ui = TimeSeriesViewerUI(parent=iface)
         if iface:
             import timeseriesviewer
-            timeseriesviewer.QGIS_TSV_BRIDGE = QgsInstanceInteraction(iface, self.ui)
+            timeseriesviewer.QGIS_TSV_BRIDGE = QgisTsvBridge(iface, self.ui)
             self.ui.setQgsLinkWidgets()
 
         #init empty time series
         self.TS = TimeSeries()
         self.hasInitialCenterPoint = False
         self.TS.sigTimeSeriesDatesAdded.connect(self.datesAdded)
-        self.TS.sigProgress.connect(self.ua_TSprogress)
+
+
+
 
         #init TS model
-        TSM = TimeSeriesTableModel(self.TS)
+
         D = self.ui
         #self.ICP = D.scrollAreaSubsetContent.layout()
         #D.scrollAreaMapViews.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
         #self.BVP = self.ui.scrollAreaMapViews.layout()
+        D.dockNavigation.connectTimeSeries(self.TS)
+        D.dockTimeSeries.connectTimeSeries(self.TS)
+
+        self.spatialTemporalVis = SpatialTemporalVisualization(self)
+        self.spatialTemporalVis.sigLoadingStarted.connect(self.ui.dockRendering.addStartedWork)
+        self.spatialTemporalVis.sigLoadingFinished.connect(self.ui.dockRendering.addFinishedWork)
 
-        D.tableView_TimeSeries.setModel(TSM)
-        D.tableView_TimeSeries.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
 
-        self.mapViewManager = MapViewManager(self)
-        self.timeSeriesDateViewManager = TimeSeriesDateViewManager(self)
 
         self.ValidatorPxX = QIntValidator(0,99999)
         self.ValidatorPxY = QIntValidator(0,99999)
@@ -864,19 +1087,18 @@ class TimeSeriesViewer:
         #D.btn_showPxCoordinate.clicked.connect(lambda: self.showSubsetsStart())
         #connect actions with logic
 
-        D.actionSelectCenter.triggered.connect(lambda : self.timeSeriesDateViewManager.activateMapTool('selectCenter'))
-        D.actionSelectArea.triggered.connect(lambda : self.timeSeriesDateViewManager.activateMapTool('selectArea'))
+        D.actionSelectCenter.triggered.connect(lambda : self.spatialTemporalVis.activateMapTool('selectCenter'))
+        D.actionSelectArea.triggered.connect(lambda : self.spatialTemporalVis.activateMapTool('selectArea'))
         D.actionZoomMaxExtent.triggered.connect(lambda : self.zoomTo('maxExtent'))
         D.actionZoomPixelScale.triggered.connect(lambda: self.zoomTo('pixelScale'))
-        D.actionZoomIn.triggered.connect(lambda: self.timeSeriesDateViewManager.activateMapTool('zoomIn'))
-        D.actionZoomOut.triggered.connect(lambda: self.timeSeriesDateViewManager.activateMapTool('zoomOut'))
-        D.actionPan.triggered.connect(lambda: self.timeSeriesDateViewManager.activateMapTool('pan'))
-
-        D.actionAddMapView.triggered.connect(self.mapViewManager.createMapView)
-
-        D.actionAddTSD.triggered.connect(self.ua_addTSImages)
-        D.actionRemoveTSD.triggered.connect(self.removeTimeSeriesDates)
-        D.actionRedraw.triggered.connect(self.timeSeriesDateViewManager.redraw)
+        D.actionZoomIn.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('zoomIn'))
+        D.actionZoomOut.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('zoomOut'))
+        D.actionPan.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('pan'))
+        D.actionAddMapView.triggered.connect(self.spatialTemporalVis.createMapView)
+
+        D.actionAddTSD.triggered.connect(lambda : self.ua_addTSImages())
+        D.actionRemoveTSD.triggered.connect(lambda: self.TS.removeDates(self.ui.dockTimeSeries.selectedTimeSeriesDates()))
+        D.actionRedraw.triggered.connect(self.spatialTemporalVis.redraw)
         D.actionLoadTS.triggered.connect(self.loadTimeSeries)
         D.actionClearTS.triggered.connect(self.clearTimeSeries)
         D.actionSaveTS.triggered.connect(self.ua_saveTSFile)
@@ -884,7 +1106,6 @@ class TimeSeriesViewer:
 
 
         #connect buttons with actions
-        D.btnClearLabelList.clicked.connect(D.tbCollectedLabels.clear)
         D.actionAbout.triggered.connect(lambda: AboutDialogUI(self.ui).exec_())
         D.actionSettings.triggered.connect(lambda : PropertyDialogUI(self.ui).exec_())
 
@@ -894,96 +1115,59 @@ class TimeSeriesViewer:
         D.actionPreviousTSD.triggered.connect(lambda: self.setDOISliderValue('previous'))
 
 
-        D.sliderDOI.valueChanged.connect(self.setDOI)
-
-        D.actionSetSubsetSize.triggered.connect(lambda : self.timeSeriesDateViewManager.setSubsetSize(
-                                                self.ui.subsetSize()))
-        D.actionSetExtent.triggered.connect(lambda: self.timeSeriesDateViewManager.setSpatialExtent(self.ui.spatialExtent()))
+        D.dockRendering.actionSetSubsetSize.triggered.connect(lambda : self.spatialTemporalVis.setSubsetSize(
+                                                D.dockRendering.subsetSize()))
+        D.actionSetExtent.triggered.connect(lambda: self.spatialTemporalVis.setSpatialExtent(self.ui.spatialExtent()))
 
         self.canvasCrs = QgsCoordinateReferenceSystem()
 
 
-    def zoomTo(self, key):
-        if key == 'maxExtent':
-            ext = self.TS.getMaxSpatialExtent(self.ui.crs())
-            self.timeSeriesDateViewManager.setSpatialExtent(ext)
-        elif key == 'pixelScale':
-            s = ""
-
-
-    def setDOISliderValue(self, key):
-        ui = self.ui
-        v = ui.sliderDOI.value()
-        if key == 'first':
-            v = ui.sliderDOI.minimum()
-        elif key == 'last':
-            v = ui.sliderDOI.maximum()
-        elif key =='next':
-            v = min([v+1,ui.sliderDOI.maximum()])
-        elif key =='previous':
-            v = max([v - 1, ui.sliderDOI.minimum()])
-        ui.sliderDOI.setValue(v)
+    def loadImageFiles(self, files):
+        assert isinstance(files, list)
+        self.TS.addFiles(files)
 
-    def setDOI(self, i):
 
-        TSD = None
+    def loadTimeSeries(self, path=None, n_max=None):
+        if path is None or path is False:
+            path = QFileDialog.getOpenFileName(self.ui, 'Open Time Series file', '')
 
-        if len(self.TS) == 0:
-            text = '<empty timeseries>'
-        else:
-            assert i <= len(self.TS)
-            TSD = self.TS.data[i - 1]
-            text = str(TSD.date)
+        if os.path.exists(path):
+            M = self.ui.dockTimeSeries.tableView_TimeSeries.model()
+            M.beginResetModel()
+            self.clearTimeSeries()
+            self.TS.loadFromFile(path, n_max=n_max)
+            M.endResetModel()
 
-        self.ui.labelDOIValue.setText(text)
 
-        if TSD:
-            self.timeSeriesDateViewManager.navToDOI(TSD)
+    def zoomTo(self, key):
+        if key == 'maxExtent':
+            ext = self.TS.getMaxSpatialExtent(self.ui.dockNavigation.crs())
+            self.spatialTemporalVis.setSpatialExtent(ext)
+        elif key == 'pixelScale':
+            s = ""
 
 
     def icon(self):
         return TimeSeriesViewer.icon()
 
     def timeseriesChanged(self):
-        D = self.ui
-        D.sliderDOI.setMinimum(1)
-        l = len(self.TS.data)
-        D.sliderDOI.setMaximum(l)
-        #get meaningfull tick intervall
-        for tickInterval in [1,5,10,25,50,100,200]:
-            if (D.sliderDOI.size().width() / float(l) * tickInterval) > 5:
-                break
-        D.sliderDOI.setTickInterval(tickInterval)
 
         if not self.hasInitialCenterPoint:
             if len(self.TS.data) > 0:
-                extent = self.TS.getMaxSpatialExtent(self.canvasCrs)
-                self.timeSeriesDateViewManager.setSubsetSize(self.ui.subsetSize())
-                self.timeSeriesDateViewManager.setSpatialExtent(extent)
-                self.ui.setSpatialExtent(extent)
+                extent = self.TS.getMaxSpatialExtent()
+                self.spatialTemporalVis.setSubsetSize(self.ui.dockRendering.subsetSize())
+                self.spatialTemporalVis.setSpatialExtent(extent)
                 self.hasInitialCenterPoint = True
 
-            if len(self.mapViewManager) == 0:
+            if len(self.spatialTemporalVis.MVC) == 0:
                 # add two empty band-views by default
-                self.mapViewManager.createMapView()
-                self.mapViewManager.createMapView()
+                self.spatialTemporalVis.createMapView()
+                self.spatialTemporalVis.createMapView()
 
         if len(self.TS.data) == 0:
             self.hasInitialCenterPoint = False
 
 
-    def loadTimeSeries(self, path=None, n_max=None):
-        if path is None or path is False:
-            path = QFileDialog.getOpenFileName(self.ui, 'Open Time Series file', '')
-
-        if os.path.exists(path):
-
-
-            M = self.ui.tableView_TimeSeries.model()
-            M.beginResetModel()
-            self.clearTimeSeries()
-            self.TS.loadFromFile(path, n_max=n_max)
-            M.endResetModel()
 
     def ua_saveTSFile(self):
         path = QFileDialog.getSaveFileName(self.ui, caption='Save Time Series file')
@@ -1013,7 +1197,7 @@ class TimeSeriesViewer:
         #keep specified CRS but translate extent
         oldExtent = self.ui.spatialExtent()
         self.ui.setSpatialExtent(extent)
-        self.timeSeriesDateViewManager.setSpatialExtent(extent)
+        self.spatialTemporalVis.setSpatialExtent(extent)
 
     def qgs_handleMouseDown(self, pt, btn):
         pass
@@ -1033,7 +1217,7 @@ class TimeSeriesViewer:
 
     def datesAdded(self, dates):
         assert isinstance(dates, list)
-        self.ui.tableView_TimeSeries.resizeColumnsToContents()
+        self.ui.dockTimeSeries.tableView_TimeSeries.resizeColumnsToContents()
         self.timeseriesChanged()
 
 
@@ -1136,39 +1320,16 @@ class TimeSeriesViewer:
             files = QFileDialog.getOpenFileNames()
 
         if files:
-            M = self.ui.tableView_TimeSeries.model()
-            M.beginResetModel()
             self.TS.addFiles(files)
-            M.endResetModel()
-            self.refreshMapViews()
-
-        self.check_enabled()
-
-
-
 
     def clearTimeSeries(self):
         #remove views
 
-        M = self.ui.tableView_TimeSeries.model()
+        M = self.ui.dockTimeSeries.tableView_TimeSeries.model()
         M.beginResetModel()
         self.TS.clear()
         M.endResetModel()
 
-
-    def removeTimeSeriesDates(self, TSDs=None):
-        if TSDs is None:
-            TSDs = self.getSelectedTSDs()
-        assert isinstance(TSDs,list)
-
-        M = self.ui.tableView_TimeSeries.model()
-        M.beginResetModel()
-        self.TS.removeDates(TSDs)
-        M.endResetModel()
-
-
-
-
     def getSelectedTSDs(self):
         TV = self.ui.tableView_TimeSeries
         TVM = TV.model()
@@ -1198,8 +1359,6 @@ def run_tests():
             TSD = TimeSeriesDatum(pathImg)
             TSD.setMask(pathMsk)
 
-            print(TSD)
-
             c = [670949.883,-786288.771]
 
             w_x = w_y = 1000 #1km box
@@ -1318,4 +1477,9 @@ def run_tests():
 
 if __name__ == '__main__':
     run_tests()
+
+    newExtent = model.convertSpatialExten(exten, crs)
+
+    ext = SpatialExtent()
+
     print('Done')
\ No newline at end of file